diff --git a/LeanPool/AbstractLinearControl.lean b/LeanPool/AbstractLinearControl.lean new file mode 100644 index 0000000000..4357a3a7f7 --- /dev/null +++ b/LeanPool/AbstractLinearControl.lean @@ -0,0 +1,36 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +-- Background +public import LeanPool.AbstractLinearControl.Background.Semigroup +public import LeanPool.AbstractLinearControl.Background.Lp +public import LeanPool.AbstractLinearControl.Background.Phillips +public import LeanPool.AbstractLinearControl.Background.InvariantHahnBanach +-- Definitions 1.1 and 1.4, Lemma 2.1 +public import LeanPool.AbstractLinearControl.Definitions +-- Proposition 1.3 +public import LeanPool.AbstractLinearControl.ContinuityFiniteP +-- Theorem 1.5 +public import LeanPool.AbstractLinearControl.ZeroClass +-- Corollary 1.6 +public import LeanPool.AbstractLinearControl.ContinuityLinfty +-- Section 3: examples +public import LeanPool.AbstractLinearControl.Examples.FinitePNotZeroClass +public import LeanPool.AbstractLinearControl.Examples.ExoticMean +public import LeanPool.AbstractLinearControl.Examples.Periodization +public import LeanPool.AbstractLinearControl.Examples.NoRepresentation + +/-! +# Continuity and zero-class properties of abstract linear control systems + +Source: url:https://github.com/frederic-marbach/alcs/tree/bda56576f8b2730b73a55f273511c80fabbe56f4 +Authors: Frédéric Marbach, GPT-6 Pro, Claude Opus 5.5 +Status: verified +Main declarations: `AbstractLinearControl.ALCS.zero_class` +Tags: functional-analysis, control-theory, semigroups, lp-spaces, hahn-banach +MSC: 47D06, 93C25, 46E30 +-/ diff --git a/LeanPool/AbstractLinearControl/Background/InvariantHahnBanach.lean b/LeanPool/AbstractLinearControl/Background/InvariantHahnBanach.lean new file mode 100644 index 0000000000..85ef3377ac --- /dev/null +++ b/LeanPool/AbstractLinearControl/Background/InvariantHahnBanach.lean @@ -0,0 +1,376 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import Mathlib.Tactic.Abel +public import Mathlib.Tactic.Linarith +public import Mathlib.Tactic.Push +public import Mathlib.Tactic.Ring +public import Mathlib.Analysis.Normed.Module.HahnBanach + + +/-! +# Translation-invariant Hahn–Banach extensions by finite averaging + +Background for Lemma 3.2 (`lem:exotic-mean`). Let `R` be an action of the additive group +`ℝ` on a real normed space `E` by linear contractions (no continuity in the translation +parameter is assumed). Let `e ∈ E` be fixed by `R` and `V` an `R`-invariant subspace such +that `|c| ≤ ‖c • e + v‖` for all `c ∈ ℝ` and `v ∈ V`. Then +`exists_invariant_extension` provides `m ∈ E*` with `‖m‖ ≤ 1`, `m e = 1`, `m = 0` on `V` +and `m ∘ R a = m` for all `a`. + +Proof: finite Cesàro averages of translations make every coboundary `R a x - x` +arbitrarily small without moving `e` nor leaving `V` (`difference_annihilable`), so the +separation of `e` from `V` persists from `V` to `V ⊔ coboundaries` +(`separation_sup_coboundaries`); then apply the Hahn–Banach theorem to the coefficient +of `e` (`extend_from_separation`). +-/ + +namespace AbstractLinearControl + +@[expose] public section + +noncomputable section +open scoped BigOperators + +namespace ExoticMean.HahnBanach + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] + +/-- A contractive real-translation action, with no continuity assumption in `a`. -/ +structure Action (E : Type*) [NormedAddCommGroup E] [NormedSpace ℝ E] where + /-- Translation by the real parameter. -/ + T : ℝ → E →ₗ[ℝ] E + zero_apply : ∀ x, T 0 x = x + add_apply : ∀ a b x, T (a + b) x = T a (T b x) + bound : ∀ a x, ‖T a x‖ ≤ ‖x‖ + +namespace Action + +variable (R : Action E) + +lemma commute (a b : ℝ) (x : E) : R.T a (R.T b x) = R.T b (R.T a x) := by + rw [← R.add_apply, ← R.add_apply, add_comm a b] + +end Action + +/-- An averaging operator preserves `e` and `V`, is contractive, and belongs +algebraically to the bicommutant of the translation action. The last field +lets us compose averaging operators without introducing a finite-product API. +Every finite Cesàro average of translations has this property. -/ +structure Averager (R : Action E) (e : E) (V : Submodule ℝ E) where + /-- The contractive averaging operator. -/ + op : E →ₗ[ℝ] E + fixes : op e = e + preserves : ∀ x ∈ V, op x ∈ V + bound : ∀ x, ‖op x‖ ≤ ‖x‖ + bicommutes : ∀ L : E →ₗ[ℝ] E, + (∀ a x, L (R.T a x) = R.T a (L x)) → ∀ x, op (L x) = L (op x) + +namespace Averager + +variable {R : Action E} {e : E} {V : Submodule ℝ E} + +/-- The identity averaging operator. -/ +def identity (R : Action E) (e : E) (V : Submodule ℝ E) : Averager R e V where + op := LinearMap.id + fixes := rfl + preserves := fun _ hx => hx + bound := fun _ => le_rfl + bicommutes := by intros; rfl + +lemma commute_translation (Q : Averager R e V) (a : ℝ) (x : E) : + Q.op (R.T a x) = R.T a (Q.op x) := + Q.bicommutes (R.T a) (fun b y => R.commute a b y) x + +lemma commute (Q P : Averager R e V) (x : E) : Q.op (P.op x) = P.op (Q.op x) := + Q.bicommutes P.op (fun a y => P.commute_translation a y) x + +/-- Composition of two averaging operators. -/ +def comp (Q P : Averager R e V) : Averager R e V where + op := Q.op.comp P.op + fixes := by change Q.op (P.op e) = e; rw [P.fixes, Q.fixes] + preserves := fun x hx => Q.preserves _ (P.preserves x hx) + bound := fun x => (Q.bound _).trans (P.bound x) + bicommutes := by + intro L hL x + change Q.op (P.op (L x)) = L (Q.op (P.op x)) + rw [P.bicommutes L hL, Q.bicommutes L hL] + +/-- The ordinary finite Cesàro average. `N` must be strictly positive. -/ +def cesaro (R : Action E) (e : E) (V : Submodule ℝ E) + (he : ∀ a, R.T a e = e) + (hV : ∀ a x, x ∈ V → R.T a x ∈ V) + (a : ℝ) (N : ℕ) (hN : 0 < N) : Averager R e V where + op := (N : ℝ)⁻¹ • ∑ k ∈ Finset.range N, R.T ((k : ℝ) * a) + fixes := by + simp only [LinearMap.smul_apply, LinearMap.sum_apply] + change (N : ℝ)⁻¹ • (∑ k ∈ Finset.range N, R.T ((k : ℝ) * a) e) = e + simp_rw [he] + rw [Finset.sum_const, Finset.card_range, ← Nat.cast_smul_eq_nsmul ℝ, + smul_smul, inv_mul_cancel₀ (by exact_mod_cast hN.ne'), one_smul] + preserves := by + intro x hx + simp only [LinearMap.smul_apply, LinearMap.sum_apply] + change (N : ℝ)⁻¹ • (∑ k ∈ Finset.range N, R.T ((k : ℝ) * a) x) ∈ V + exact V.smul_mem _ (V.sum_mem (fun k _ => hV _ x hx)) + bound := by + intro x + have hNr : 0 < (N : ℝ) := by exact_mod_cast hN + have hi : 0 ≤ (N : ℝ)⁻¹ := inv_nonneg.mpr hNr.le + simp only [LinearMap.smul_apply, LinearMap.sum_apply] + change ‖(N : ℝ)⁻¹ • (∑ k ∈ Finset.range N, R.T ((k : ℝ) * a) x)‖ ≤ ‖x‖ + rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg hi] + calc + (N : ℝ)⁻¹ * ‖∑ k ∈ Finset.range N, R.T ((k : ℝ) * a) x‖ + ≤ (N : ℝ)⁻¹ * ∑ k ∈ Finset.range N, ‖R.T ((k : ℝ) * a) x‖ := + mul_le_mul_of_nonneg_left (norm_sum_le _ _) hi + _ ≤ (N : ℝ)⁻¹ * ∑ _k ∈ Finset.range N, ‖x‖ := + mul_le_mul_of_nonneg_left (Finset.sum_le_sum (fun k _ => R.bound _ x)) hi + _ = ‖x‖ := by simp [hNr.ne', nsmul_eq_mul] + bicommutes := by + intro L hL x + simp only [LinearMap.smul_apply, LinearMap.sum_apply] + change (N : ℝ)⁻¹ • (∑ k ∈ Finset.range N, R.T ((k : ℝ) * a) (L x)) = + L ((N : ℝ)⁻¹ • (∑ k ∈ Finset.range N, R.T ((k : ℝ) * a) x)) + rw [map_smul, map_sum] + congr 1 + apply Finset.sum_congr rfl + intro k _ + exact (hL ((k : ℝ) * a) x).symm + +lemma cesaro_difference (R : Action E) (e : E) (V : Submodule ℝ E) + (he : ∀ a, R.T a e = e) + (hV : ∀ a x, x ∈ V → R.T a x ∈ V) + (a : ℝ) (N : ℕ) (hN : 0 < N) (x : E) : + (cesaro R e V he hV a N hN).op (R.T a x - x) = + (N : ℝ)⁻¹ • (R.T ((N : ℝ) * a) x - x) := by + have telescoping : ∀ n : ℕ, + (∑ k ∈ Finset.range n, R.T ((k : ℝ) * a) (R.T a x - x)) = + R.T ((n : ℝ) * a) x - x := by + intro n + induction n with + | zero => simp [R.zero_apply] + | succ n ih => + rw [Finset.sum_range_succ, ih, map_sub, ← R.add_apply] + have harg : (n : ℝ) * a + a = ((n + 1 : ℕ) : ℝ) * a := by + push_cast + ring + rw [harg] + abel + change ((N : ℝ)⁻¹ • ∑ k ∈ Finset.range N, R.T ((k : ℝ) * a)) (R.T a x - x) = _ + simp only [LinearMap.smul_apply, LinearMap.sum_apply] + rw [telescoping] + +lemma cesaro_difference_bound (R : Action E) (e : E) (V : Submodule ℝ E) + (he : ∀ a, R.T a e = e) + (hV : ∀ a x, x ∈ V → R.T a x ∈ V) + (a : ℝ) (N : ℕ) (hN : 0 < N) (x : E) : + ‖(cesaro R e V he hV a N hN).op (R.T a x - x)‖ ≤ 2 * ‖x‖ / (N : ℝ) := by + have hNr : 0 < (N : ℝ) := by exact_mod_cast hN + rw [cesaro_difference, norm_smul, Real.norm_eq_abs, + abs_of_nonneg (inv_nonneg.mpr hNr.le)] + calc + (N : ℝ)⁻¹ * ‖R.T ((N : ℝ) * a) x - x‖ + ≤ (N : ℝ)⁻¹ * (‖R.T ((N : ℝ) * a) x‖ + ‖x‖) := + mul_le_mul_of_nonneg_left (norm_sub_le _ _) (inv_nonneg.mpr hNr.le) + _ ≤ (N : ℝ)⁻¹ * (‖x‖ + ‖x‖) := + mul_le_mul_of_nonneg_left (add_le_add (R.bound _ x) le_rfl) + (inv_nonneg.mpr hNr.le) + _ = 2 * ‖x‖ / (N : ℝ) := by ring + +end Averager + +/-- Vectors made arbitrarily small by finite contractive averaging. -/ +def annihilable (R : Action E) (e : E) (V : Submodule ℝ E) : Submodule ℝ E where + carrier := {x | ∀ ε : ℝ, 0 < ε → ∃ Q : Averager R e V, ‖Q.op x‖ < ε} + zero_mem' := by + intro ε hε + exact ⟨Averager.identity R e V, by simpa using hε⟩ + add_mem' := by + intro x y hx hy ε hε + obtain ⟨Q, hQ⟩ := hx (ε / 2) (by linarith) + obtain ⟨P, hP⟩ := hy (ε / 2) (by linarith) + refine ⟨Q.comp P, ?_⟩ + change ‖Q.op (P.op (x + y))‖ < ε + rw [map_add, map_add] + have hx' : ‖Q.op (P.op x)‖ < ε / 2 := by + rw [Q.commute P x] + exact (P.bound _).trans_lt hQ + have hy' : ‖Q.op (P.op y)‖ < ε / 2 := (Q.bound _).trans_lt hP + have ht := norm_add_le (Q.op (P.op x)) (Q.op (P.op y)) + linarith + smul_mem' := by + intro c x hx ε hε + by_cases hc : c = 0 + · subst c + exact ⟨Averager.identity R e V, by simpa using hε⟩ + · have hc' : 0 < ‖c‖ := norm_pos_iff.mpr hc + obtain ⟨Q, hQ⟩ := hx (ε / ‖c‖) (div_pos hε hc') + refine ⟨Q, ?_⟩ + rw [map_smul, norm_smul] + have h := (lt_div_iff₀ hc').mp hQ + simpa [mul_comm] using h + +/-- All finite real linear combinations of translation differences. -/ +def coboundaries (R : Action E) : Submodule ℝ E := + Submodule.span ℝ {d | ∃ a : ℝ, ∃ x : E, d = R.T a x - x} + +lemma difference_annihilable (R : Action E) (e : E) (V : Submodule ℝ E) + (he : ∀ a, R.T a e = e) + (hV : ∀ a x, x ∈ V → R.T a x ∈ V) (a : ℝ) (x : E) : + R.T a x - x ∈ annihilable R e V := by + intro ε hε + obtain ⟨N, hN⟩ := exists_nat_gt (2 * ‖x‖ / ε) + have hNr : 0 < (N : ℝ) := + lt_of_le_of_lt (div_nonneg (by positivity) hε.le) hN + have hNnat : 0 < N := by exact_mod_cast hNr + refine ⟨Averager.cesaro R e V he hV a N hNnat, ?_⟩ + apply (Averager.cesaro_difference_bound R e V he hV a N hNnat x).trans_lt + apply (div_lt_iff₀ hNr).mpr + have h := (div_lt_iff₀ hε).mp hN + simpa [mul_comm] using h + +lemma coboundaries_le_annihilable (R : Action E) (e : E) (V : Submodule ℝ E) + (he : ∀ a, R.T a e = e) + (hV : ∀ a x, x ∈ V → R.T a x ∈ V) : + coboundaries R ≤ annihilable R e V := by + apply Submodule.span_le.mpr + rintro d ⟨a, x, rfl⟩ + exact difference_annihilable R e V he hV a x + +/-- The key estimate: adjoining all translation differences preserves the +norm separation of the constants. -/ +theorem separation_sup_coboundaries (R : Action E) (e : E) (V : Submodule ℝ E) + (he : ∀ a, R.T a e = e) + (hV : ∀ a x, x ∈ V → R.T a x ∈ V) + (hsep : ∀ c : ℝ, ∀ v ∈ V, |c| ≤ ‖c • e + v‖) : + ∀ c : ℝ, ∀ w ∈ V ⊔ coboundaries R, |c| ≤ ‖c • e + w‖ := by + intro c w hw + obtain ⟨v, hv, d, hd, rfl⟩ := Submodule.mem_sup.mp hw + by_contra h + have hgap : 0 < |c| - ‖c • e + (v + d)‖ := sub_pos.mpr (lt_of_not_ge h) + have hd' := coboundaries_le_annihilable R e V he hV hd + obtain ⟨Q, hQ⟩ := hd' (|c| - ‖c • e + (v + d)‖) hgap + have hlow := hsep c (Q.op v) (Q.preserves v hv) + have htriangle : ‖c • e + Q.op v‖ ≤ + ‖Q.op (c • e + (v + d))‖ + ‖Q.op d‖ := by + calc + ‖c • e + Q.op v‖ = ‖Q.op (c • e + (v + d)) - Q.op d‖ := by + congr 1 + rw [map_add, map_add, map_smul, Q.fixes] + abel + _ ≤ _ := norm_sub_le _ _ + have hbound := Q.bound (c • e + (v + d)) + linarith + +/-- Hahn--Banach applied to the coefficient of `e`, without presupposing a +choice of direct-sum decomposition. The separation estimate itself proves +that the coefficient is well-defined. -/ +theorem extend_from_separation (e : E) (W : Submodule ℝ E) + (hsep : ∀ c : ℝ, ∀ w ∈ W, |c| ≤ ‖c • e + w‖) : + ∃ m : E →L[ℝ] ℝ, + ‖m‖ ≤ 1 ∧ m e = 1 ∧ ∀ w ∈ W, m w = 0 := by + classical + have scalar_zero : ∀ c : ℝ, c • e ∈ W → c = 0 := by + intro c hc + have h := hsep c (-(c • e)) (W.neg_mem hc) + simp only [add_neg_cancel, norm_zero] at h + exact abs_eq_zero.mp (le_antisymm h (abs_nonneg c)) + let S : Submodule ℝ E := + { carrier := {x | ∃ c : ℝ, x - c • e ∈ W} + zero_mem' := ⟨0, by simp⟩ + add_mem' := by + rintro x y ⟨c, hc⟩ ⟨d, hd⟩ + refine ⟨c + d, ?_⟩ + convert W.add_mem hc hd using 1 + rw [add_smul] + abel + smul_mem' := by + rintro a x ⟨c, hc⟩ + refine ⟨a * c, ?_⟩ + convert W.smul_mem a hc using 1 + rw [smul_sub, mul_smul] } + let coord : S → ℝ := fun x => Classical.choose x.property + have coord_spec (x : S) : (x : E) - coord x • e ∈ W := + Classical.choose_spec x.property + have coord_eq (x : S) (c : ℝ) (hc : (x : E) - c • e ∈ W) : coord x = c := by + have hmem : (coord x - c) • e ∈ W := by + convert W.sub_mem hc (coord_spec x) using 1 + rw [sub_smul] + abel + exact sub_eq_zero.mp (scalar_zero (coord x - c) hmem) + let f : S →ₗ[ℝ] ℝ := + { toFun := coord + map_add' := by + intro x y + change coord (x + y) = coord x + coord y + apply coord_eq + change (x : E) + (y : E) - (coord x + coord y) • e ∈ W + convert W.add_mem (coord_spec x) (coord_spec y) using 1 + rw [add_smul] + abel + map_smul' := by + intro a x + change coord (a • x) = a * coord x + apply coord_eq + change a • (x : E) - (a * coord x) • e ∈ W + convert W.smul_mem a (coord_spec x) using 1 + rw [smul_sub, mul_smul] } + have hf (x : S) : ‖f x‖ ≤ ‖x‖ := by + have h := hsep (coord x) ((x : E) - coord x • e) (coord_spec x) + have heq : coord x • e + ((x : E) - coord x • e) = (x : E) := by abel + rw [heq] at h + change ‖coord x‖ ≤ ‖(x : E)‖ + simpa only [Real.norm_eq_abs] using h + let fC : S →L[ℝ] ℝ := f.mkContinuous 1 (fun x => by simpa using hf x) + have hfC : ‖fC‖ ≤ 1 := by + apply ContinuousLinearMap.opNorm_le_bound _ (by norm_num) + intro x + change ‖f x‖ ≤ 1 * ‖x‖ + simpa using hf x + obtain ⟨m, hm, hnorm⟩ := exists_extension_norm_eq S fC + refine ⟨m, hnorm.le.trans hfC, ?_, ?_⟩ + · have heS : e ∈ S := ⟨1, by simp⟩ + calc + m e = fC ⟨e, heS⟩ := hm ⟨e, heS⟩ + _ = coord ⟨e, heS⟩ := rfl + _ = 1 := coord_eq _ 1 (by simp) + · intro w hw + have hwS : w ∈ S := ⟨0, by simpa using hw⟩ + calc + m w = fC ⟨w, hwS⟩ := hm ⟨w, hwS⟩ + _ = coord ⟨w, hwS⟩ := rfl + _ = 0 := coord_eq _ 0 (by simpa using hw) + +/-- Translation-invariant Hahn–Banach extension: the main result of this file. -/ +theorem exists_invariant_extension (R : Action E) (e : E) (V : Submodule ℝ E) + (he : ∀ a, R.T a e = e) + (hV : ∀ a x, x ∈ V → R.T a x ∈ V) + (hsep : ∀ c : ℝ, ∀ v ∈ V, |c| ≤ ‖c • e + v‖) : + ∃ m : E →L[ℝ] ℝ, + ‖m‖ ≤ 1 ∧ m e = 1 ∧ (∀ v ∈ V, m v = 0) ∧ + ∀ a x, m (R.T a x) = m x := by + obtain ⟨m, hnorm, he', hW⟩ := extend_from_separation e (V ⊔ coboundaries R) + (separation_sup_coboundaries R e V he hV hsep) + refine ⟨m, hnorm, he', ?_, ?_⟩ + · intro v hv + exact hW v (Submodule.mem_sup.mpr ⟨v, hv, 0, (coboundaries R).zero_mem, + by simp⟩) + · intro a x + have hd : R.T a x - x ∈ coboundaries R := + Submodule.subset_span ⟨a, x, rfl⟩ + have h := hW (R.T a x - x) + (Submodule.mem_sup.mpr ⟨0, V.zero_mem, R.T a x - x, hd, by simp⟩) + rw [map_sub] at h + exact sub_eq_zero.mp h + +end ExoticMean.HahnBanach + +end +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Background/Linfty.lean b/LeanPool/AbstractLinearControl/Background/Linfty.lean new file mode 100644 index 0000000000..c7539db57b --- /dev/null +++ b/LeanPool/AbstractLinearControl/Background/Linfty.lean @@ -0,0 +1,55 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import Mathlib.MeasureTheory.Function.LpSpace.Basic + +/-! +# Bounds for essentially bounded functions + +The norm bound and almost-everywhere evaluation bound apply to arbitrary measures +and normed additive groups. Both the half-line input API and periodic-mean examples +use this shared implementation. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open MeasureTheory Filter +open scoped ENNReal + +namespace ALCS + +variable {α U : Type*} [MeasurableSpace α] [NormedAddCommGroup U] {μ : Measure α} + +/-- The `L^∞` norm is bounded by any nonnegative a.e. bound. -/ +lemma lp_norm_le {u : Lp U ∞ μ} {C : ℝ} (hC : 0 ≤ C) + (hb : ∀ᵐ t ∂μ, ‖u t‖ ≤ C) : ‖u‖ ≤ C := by + have htop : eLpNorm (⇑u) ∞ μ = eLpNormEssSup (⇑u) μ := + eLpNorm_exponent_top (Lp.aestronglyMeasurable u) + rw [Lp.norm_def, htop] + calc + (eLpNormEssSup (⇑u) μ).toReal ≤ (ENNReal.ofReal C).toReal := + ENNReal.toReal_mono ENNReal.ofReal_ne_top (eLpNormEssSup_le_of_ae_bound hb) + _ = C := ENNReal.toReal_ofReal hC + +/-- The representative of an `L^∞` class obeys its norm bound a.e. -/ +lemma ae_norm_le (u : Lp U ∞ μ) : ∀ᵐ t ∂μ, ‖u t‖ ≤ ‖u‖ := by + have htop : eLpNorm (⇑u) ∞ μ = eLpNormEssSup (⇑u) μ := + eLpNorm_exponent_top (Lp.aestronglyMeasurable u) + have hfinite : eLpNormEssSup (⇑u) μ ≠ ∞ := by + rw [← htop] + exact Lp.eLpNorm_ne_top u + filter_upwards [enorm_ae_le_eLpNormEssSup (⇑u) μ] with t ht + have ht' := ENNReal.toReal_mono hfinite ht + simpa only [Lp.norm_def, htop, toReal_enorm] using ht' + +end ALCS + +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Background/Lp.lean b/LeanPool/AbstractLinearControl/Background/Lp.lean new file mode 100644 index 0000000000..9b3ee6e134 --- /dev/null +++ b/LeanPool/AbstractLinearControl/Background/Lp.lean @@ -0,0 +1,379 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Background.Linfty +public import Mathlib.MeasureTheory.Function.LpSpace.Complete +public import Mathlib.MeasureTheory.Function.LpSpace.ContinuousCompMeasurePreserving +public import Mathlib.MeasureTheory.Function.LpSpace.Indicator +public import Mathlib.MeasureTheory.Function.UniformIntegrable +public import Mathlib.MeasureTheory.Measure.Haar.Unique +public import Mathlib.MeasureTheory.Measure.Lebesgue.Basic +public import Mathlib.MeasureTheory.Measure.RegularityCompacts + + +/-! +# Inputs: the space `L^p(ℝ₊; U)`, concatenation, shifts and truncations + +This file contains the measure-theoretic plumbing on inputs used throughout the +development. Nothing here is specific to control systems. + +## Conventions + +* `L^p(ℝ₊; U)` is Mathlib's `Lp U p muPlus`, where `muPlus` is Lebesgue measure + restricted to `ℝ₊ = [0, ∞)`. Its elements are almost-everywhere classes; + `⇑u : ℝ → U` is an (arbitrary) representative, whose values at negative times + are irrelevant. +* The `τ`-concatenation `u ⋄_τ v` of the paper is `concat τ u v`, defined on raw + functions `ℝ → U`. Statements about inputs are phrased as "`w` is an element of + `L^p(ℝ₊; U)` whose representative is a.e. equal to `concat τ ⇑u ⇑v`". + +## Main declarations + +* `muPlus`, `concat`, `ALCS.concat_congr` : definitions, and independence of + the concatenation from the chosen representatives. +* `ALCS.shiftLeft a u` : the input `s ↦ u (a + s)`; `ALCS.exists_shift` gives + `u = u ⋄_a (shiftLeft a u)`, and `ALCS.tendsto_norm_shiftLeft_sub` is the + continuity of translations in `L^p` for `p < ∞`. +* `ALCS.exists_delay` : the delayed input `0 ⋄_a u`, with the same norm bound. +* `ALCS.truncate τ u` : the input `u ⋄_τ 0`; `ALCS.tendsto_norm_truncate` says + that `‖u‖_{L^p(0, τ)} → 0` as `τ → 0` for `p < ∞`. +* `ALCS.exists_concat` : for `p = ∞`, the concatenation of two inputs of norm + at most `C` is an input of norm at most `C`. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open MeasureTheory Filter Topology +open scoped ENNReal + +variable {U : Type*} + +/-- Lebesgue measure on `ℝ₊ = [0, ∞)`. -/ +noncomputable abbrev muPlus : Measure ℝ := volume.restrict (Set.Ici 0) + +/-- The `τ`-concatenation `u ⋄_τ v` of the paper: equal to `u s` for `s < τ` and to +`v (s - τ)` for `s ≥ τ` ("play `u` on `[0, τ)`, then play `v`"). -/ +noncomputable def concat (τ : ℝ) (u v : ℝ → U) : ℝ → U := + fun s => if s < τ then u s else v (s - τ) + +namespace ALCS + +/-! ## Translations of the half-line -/ + +/-- `s ↦ a + s` sends `ℝ₊` to `[a, ∞)`, preserving Lebesgue measure. -/ +theorem measurePreserving_shift (a : ℝ) : + MeasurePreserving (fun s => a + s) muPlus (volume.restrict (Set.Ici a)) := by + have h := (measurePreserving_add_left (volume : Measure ℝ) a).restrict_preimage + (measurableSet_Ici : MeasurableSet (Set.Ici a)) + rwa [Set.preimage_const_add_Ici, sub_self] at h + +/-- `s ↦ -a + s` sends `[a, ∞)` to `ℝ₊`, preserving Lebesgue measure. -/ +theorem measurePreserving_unshift (a : ℝ) : + MeasurePreserving (fun s => -a + s) (volume.restrict (Set.Ici a)) muPlus := by + have h := (measurePreserving_add_left (volume : Measure ℝ) (-a)).restrict_preimage + (measurableSet_Ici : MeasurableSet (Set.Ici (0 : ℝ))) + rwa [Set.preimage_const_add_Ici, zero_sub, neg_neg] at h + +/-! ## Concatenation -/ + +/-- The concatenation does not depend on the chosen representatives. For the second +argument, the null set has to be transported by a translation. -/ +lemma concat_congr {f f' g g' : ℝ → U} (a : ℝ) + (hf : f =ᵐ[muPlus] f') (hg : g =ᵐ[muPlus] g') : + concat a f g =ᵐ[muPlus] concat a f' g' := by + have hg₁ := (measurePreserving_unshift a).quasiMeasurePreserving.ae hg + have hg₂ := (ae_restrict_iff' + (measurableSet_Ici : MeasurableSet (Set.Ici a))).1 hg₁ + filter_upwards [hf, ae_restrict_of_ae hg₂] with t hft hgt + by_cases ht : t < a + · simp [concat, ht, hft] + · simpa only [concat, ite_eq_right ht, sub_eq_neg_add] using + hgt (Set.mem_Ici.2 (not_lt.1 ht)) + +variable [NormedAddCommGroup U] + +lemma concat_stronglyMeasurable {f g : ℝ → U} + (hf : StronglyMeasurable f) (hg : StronglyMeasurable g) (a : ℝ) : + StronglyMeasurable (concat a f g) := + StronglyMeasurable.ite measurableSet_Iio hf + (hg.comp_measurable (measurable_id.sub_const a)) + +/-! ## Extension by zero to the whole line -/ + +/-- Extension by zero to `ℝ` of a function on `ℝ₊`. -/ +noncomputable def zeroExt (f : ℝ → U) : ℝ → U := (Set.Ici (0 : ℝ)).indicator f + +lemma zeroExt_of_nonneg (f : ℝ → U) {s : ℝ} (hs : 0 ≤ s) : zeroExt f s = f s := + Set.indicator_of_mem (Set.mem_Ici.2 hs) f + +lemma zeroExt_of_neg (f : ℝ → U) {s : ℝ} (hs : s < 0) : zeroExt f s = 0 := + Set.indicator_of_notMem (fun h => (not_le.2 hs) (Set.mem_Ici.1 h)) f + +section General + +variable {p : ℝ≥0∞} + +lemma memLp_zeroExt (u : Lp U p muPlus) : MemLp (zeroExt ⇑u) p volume := + (memLp_indicator_iff_restrict measurableSet_Ici).2 (Lp.memLp u) + +lemma eLpNorm_zeroExt (u : Lp U p muPlus) : + eLpNorm (zeroExt ⇑u) p volume = eLpNorm (⇑u) p muPlus := + eLpNorm_indicator_eq_eLpNorm_restrict measurableSet_Ici + +/-- If `φ` preserves Lebesgue measure on `ℝ`, then `‖(zeroExt u) ∘ φ‖_{L^p(ℝ₊)} ≤ ‖u‖`. -/ +lemma eLpNorm_zeroExt_comp_le (u : Lp U p muPlus) {φ : ℝ → ℝ} + (hφ : MeasurePreserving φ volume volume) : + eLpNorm (zeroExt ⇑u ∘ φ) p muPlus ≤ eLpNorm (⇑u) p muPlus := + calc eLpNorm (zeroExt ⇑u ∘ φ) p muPlus + ≤ eLpNorm (zeroExt ⇑u ∘ φ) p volume := eLpNorm_mono_measure _ Measure.restrict_le_self + _ = eLpNorm (zeroExt ⇑u) p volume := + eLpNorm_comp_measurePreserving (memLp_zeroExt u).aestronglyMeasurable hφ + _ = eLpNorm (⇑u) p muPlus := eLpNorm_zeroExt u + +lemma memLp_zeroExt_comp (u : Lp U p muPlus) {φ : ℝ → ℝ} + (hφ : MeasurePreserving φ volume volume) : MemLp (zeroExt ⇑u ∘ φ) p muPlus := + ((memLp_zeroExt u).comp_measurePreserving hφ).mono_measure Measure.restrict_le_self + +/-- An element of `L^p` defined from a raw function has norm at most `‖u‖` as soon as +the `eLpNorm` of the raw function is at most that of `u`. -/ +lemma norm_toLp_le_of_eLpNorm_le {f : ℝ → U} (hf : MemLp f p muPlus) (u : Lp U p muPlus) + (h : eLpNorm f p muPlus ≤ eLpNorm (⇑u) p muPlus) : ‖hf.toLp f‖ ≤ ‖u‖ := by + rw [Lp.norm_toLp, Lp.norm_def] + exact ENNReal.toReal_mono (Lp.eLpNorm_ne_top u) h + +/-! ## Left shifts `u ↦ u (a + ·)` -/ + +/-- The left shift `s ↦ u (a + s)` of an input. (For `a < 0`, the input is first +extended by zero to negative times.) -/ +noncomputable def shiftLeft (a : ℝ) (u : Lp U p muPlus) : Lp U p muPlus := + (memLp_zeroExt_comp u (measurePreserving_add_left volume a)).toLp + (zeroExt ⇑u ∘ fun s => a + s) + +lemma shiftLeft_ae (a : ℝ) (u : Lp U p muPlus) : + ⇑(shiftLeft a u) =ᵐ[muPlus] (zeroExt ⇑u ∘ fun s => a + s) := + (memLp_zeroExt_comp u (measurePreserving_add_left volume a)).coeFn_toLp + +lemma norm_shiftLeft_le (a : ℝ) (u : Lp U p muPlus) : ‖shiftLeft a u‖ ≤ ‖u‖ := + norm_toLp_le_of_eLpNorm_le _ u + (eLpNorm_zeroExt_comp_le u (measurePreserving_add_left volume a)) + +/-- For `a ≥ 0`, `u = u ⋄_a (shiftLeft a u)`. -/ +lemma concat_shiftLeft (a : ℝ) (ha : 0 ≤ a) (u : Lp U p muPlus) : + ⇑u =ᵐ[muPlus] concat a ⇑u ⇑(shiftLeft a u) := by + -- pointwise, `u = u ⋄_a (zeroExt u ∘ (a + ·))` + have hraw : (⇑u : ℝ → U) = concat a ⇑u (zeroExt ⇑u ∘ fun s => a + s) := by + funext s + by_cases hs : s < a + · simp only [concat, ite_eq_left hs] + · have hs' : 0 ≤ s := le_trans ha (not_lt.1 hs) + have e : a + (s - a) = s := by ring + simp only [concat, ite_eq_right hs, Function.comp_apply, e, zeroExt_of_nonneg (⇑u) hs'] + exact (Filter.EventuallyEq.of_eq hraw).trans + (concat_congr a (Filter.EventuallyEq.refl _ _) (shiftLeft_ae a u)).symm + +/-- Shifted input (used with `τ := a` in the composition property): +for `a ≥ 0`, `u₁ := u (a + ·)` satisfies `‖u₁‖ ≤ ‖u‖` and `u = u ⋄_a u₁`. -/ +theorem exists_shift (a : ℝ) (ha : 0 ≤ a) (u : Lp U p muPlus) : + ∃ u₁ : Lp U p muPlus, ‖u₁‖ ≤ ‖u‖ ∧ ⇑u =ᵐ[muPlus] concat a ⇑u ⇑u₁ := + ⟨shiftLeft a u, norm_shiftLeft_le a u, concat_shiftLeft a ha u⟩ + +/-! ## Delays `u ↦ 0 ⋄_a u` -/ + +/-- Delayed input: the input `0 ⋄_a u` (zero on `[0, a)`, then `u`) +belongs to `L^p(ℝ₊; U)`, with norm at most `‖u‖`. -/ +theorem exists_delay (a : ℝ) (u : Lp U p muPlus) : + ∃ w : Lp U p muPlus, ‖w‖ ≤ ‖u‖ ∧ + ⇑w =ᵐ[muPlus] concat a ⇑(0 : Lp U p muPlus) ⇑u := by + have hφ : MeasurePreserving (fun s : ℝ => -a + s) volume volume := + measurePreserving_add_left volume (-a) + refine ⟨(memLp_zeroExt_comp u hφ).toLp _, + norm_toLp_le_of_eLpNorm_le _ u (eLpNorm_zeroExt_comp_le u hφ), ?_⟩ + -- pointwise, `zeroExt u (s - a) = (0 ⋄_a u) s` + have hraw : (zeroExt ⇑u ∘ fun s => -a + s) = concat a (fun _ => (0 : U)) ⇑u := by + funext s + by_cases hsa : s < a + · simp only [Function.comp_apply, zeroExt_of_neg (⇑u) (show -a + s < 0 by linarith), + concat, ite_eq_left hsa] + · simp only [Function.comp_apply, concat, ite_eq_right hsa, neg_add_eq_sub, + zeroExt_of_nonneg (⇑u) (show 0 ≤ s - a by linarith [not_lt.1 hsa])] + exact (memLp_zeroExt_comp u hφ).coeFn_toLp.trans + ((Filter.EventuallyEq.of_eq hraw).trans (concat_congr a (Lp.coeFn_zero U p muPlus).symm + (Filter.EventuallyEq.refl _ _))) + +/-! ## Truncations `u ↦ u ⋄_τ 0` -/ + +/-- The truncated input `u ⋄_τ 0`: equal to `u` on `[0, τ)` and to zero afterwards. -/ +noncomputable def truncate (τ : ℝ) (u : Lp U p muPlus) : Lp U p muPlus := + ((Lp.memLp u).indicator measurableSet_Iio).toLp ((Set.Iio τ).indicator ⇑u) + +lemma concat_truncate (τ : ℝ) (u : Lp U p muPlus) : + ⇑(truncate τ u) =ᵐ[muPlus] concat τ ⇑u ⇑(0 : Lp U p muPlus) := by + have hraw : (Set.Iio τ).indicator ⇑u = concat τ ⇑u (fun _ => (0 : U)) := by + funext s + by_cases hs : s < τ + · simp only [Set.indicator_of_mem (Set.mem_Iio.2 hs), concat, ite_eq_left hs] + · simp only [Set.indicator_of_notMem (fun h => hs (Set.mem_Iio.1 h)), concat, ite_eq_right hs] + exact ((Lp.memLp u).indicator measurableSet_Iio).coeFn_toLp.trans + ((Filter.EventuallyEq.of_eq hraw).trans + (concat_congr τ (Filter.EventuallyEq.refl _ _) (Lp.coeFn_zero U p muPlus).symm)) + +lemma muPlus_Iio (τ : ℝ) : muPlus (Set.Iio τ) = ENNReal.ofReal τ := by + rw [Measure.restrict_apply measurableSet_Iio, Set.inter_comm, Set.Ici_inter_Iio, + Real.volume_Ico, sub_zero] + +/-- For `p < ∞`, `‖u‖_{L^p(0, τ)} → 0` as `τ → 0`. -/ +theorem tendsto_norm_truncate [Fact (1 ≤ p)] (hp : p ≠ ∞) (u : Lp U p muPlus) : + Tendsto (fun τ => ‖truncate τ u‖) (𝓝 0) (𝓝 0) := by + -- first in `ℝ≥0∞`, using the absolute continuity of the `L^p` norm + have hmeas : Tendsto (fun τ : ℝ => ENNReal.ofReal τ) (𝓝 0) (𝓝 0) := + ENNReal.continuous_ofReal.tendsto' 0 0 ENNReal.ofReal_zero + have hlim : Tendsto (fun τ => eLpNorm ((Set.Iio τ).indicator ⇑u) p muPlus) (𝓝 0) (𝓝 0) := by + rw [ENNReal.tendsto_nhds_zero] + intro ε hε + obtain ⟨δ, hδ, hsmall⟩ := (Lp.memLp u).eLpNorm_indicator_le Fact.out hp hε + filter_upwards [hmeas.eventually (eventually_lt_nhds hδ)] with τ hτ + exact hsmall _ measurableSet_Iio (by rw [muPlus_Iio]; exact hτ.le) + -- then take real parts + have hreal := (ENNReal.tendsto_toReal ENNReal.zero_ne_top).comp hlim + simpa only [truncate, Lp.norm_toLp, Function.comp_def, ENNReal.toReal_zero] using hreal + +/-! ## Continuity of left shifts for `p < ∞` -/ + +/-- The translations `s ↦ a + s`, as continuous maps depending continuously on `a`. -/ +noncomputable def translation : C(ℝ, C(ℝ, ℝ)) := + ContinuousMap.curry ⟨fun q : ℝ × ℝ => q.1 + q.2, continuous_fst.add continuous_snd⟩ + +lemma translation_apply (a s : ℝ) : translation a s = a + s := by + simp [translation] + +lemma measurePreserving_translation (a : ℝ) : + MeasurePreserving (translation a) volume volume := by + have h : ⇑(translation a) = fun s => a + s := funext (translation_apply a) + rw [h] + exact measurePreserving_add_left volume a + +/-- The zero extension of `u`, as an element of `L^p(ℝ)`. -/ +noncomputable def zeroExtLp (u : Lp U p muPlus) : Lp U p (volume : Measure ℝ) := + (memLp_zeroExt u).toLp (zeroExt ⇑u) + +/-- The zero extension of `u`, translated by `a`, as an element of `L^p(ℝ)`. -/ +noncomputable def translateLp (u : Lp U p muPlus) (a : ℝ) : Lp U p (volume : Measure ℝ) := + Lp.compMeasurePreserving (translation a) (measurePreserving_translation a) (zeroExtLp u) + +lemma translateLp_ae (u : Lp U p muPlus) (a : ℝ) : + ⇑(translateLp u a) =ᵐ[volume] zeroExt ⇑u ∘ translation a := + (Lp.coeFn_compMeasurePreserving (zeroExtLp u) (measurePreserving_translation a)).trans + ((measurePreserving_translation a).quasiMeasurePreserving.ae_eq_comp + (memLp_zeroExt u).coeFn_toLp) + +/-- `‖u (a + ·) - u‖_{L^p(ℝ₊)} ≤ ‖Z (a + ·) - Z‖_{L^p(ℝ)}`, where `Z` is the zero +extension of `u`. -/ +lemma norm_shiftLeft_sub_le (a : ℝ) (u : Lp U p muPlus) : + ‖shiftLeft a u - u‖ ≤ ‖translateLp u a - translateLp u 0‖ := by + have hae : ⇑(shiftLeft a u - u) =ᵐ[muPlus] ⇑(translateLp u a - translateLp u 0) := by + have a1 := Lp.coeFn_sub (shiftLeft a u) u + have a2 := shiftLeft_ae a u + have a3 := ae_restrict_of_ae (s := Set.Ici (0 : ℝ)) + (Lp.coeFn_sub (translateLp u a) (translateLp u 0)) + have a4 := ae_restrict_of_ae (s := Set.Ici (0 : ℝ)) (translateLp_ae u a) + have a5 := ae_restrict_of_ae (s := Set.Ici (0 : ℝ)) (translateLp_ae u 0) + have a6 : ∀ᵐ s ∂muPlus, s ∈ Set.Ici (0 : ℝ) := ae_restrict_mem measurableSet_Ici + filter_upwards [a1, a2, a3, a4, a5, a6] with s e1 e2 e3 e4 e5 hs + rw [e1, Pi.sub_apply, e2, e3, Pi.sub_apply, e4, e5] + simp only [Function.comp_apply, translation_apply, zero_add, + zeroExt_of_nonneg (⇑u) (Set.mem_Ici.1 hs)] + rw [Lp.norm_def, Lp.norm_def, eLpNorm_congr_ae hae] + exact ENNReal.toReal_mono (Lp.eLpNorm_ne_top _) + (eLpNorm_mono_measure _ Measure.restrict_le_self) + +/-- Continuity of translations in `L^p(ℝ₊; U)` for `p < ∞`: `u (a + ·) → u` as `a → 0`. -/ +theorem tendsto_norm_shiftLeft_sub [Fact (1 ≤ p)] (hp : p ≠ ∞) (u : Lp U p muPlus) : + Tendsto (fun a => ‖shiftLeft a u - u‖) (𝓝 0) (𝓝 0) := by + -- continuity of translations in `L^p(ℝ)` (Mathlib) + have hlim : Tendsto (fun a => translateLp u a) (𝓝 0) (𝓝 (translateLp u 0)) := by + unfold translateLp + exact Filter.Tendsto.compMeasurePreservingLp tendsto_const_nhds + (translation.continuous.tendsto 0) measurePreserving_translation + (measurePreserving_translation 0) hp + exact squeeze_zero (fun a => norm_nonneg _) (fun a => norm_shiftLeft_sub_le a u) + (tendsto_iff_norm_sub_tendsto_zero.1 hlim) + +end General + +/-! ## Inputs in `L^∞(ℝ₊; U)` -/ + +section Infinity + +/-- A pointwise bound gives membership in `L^∞`, without a finite-measure assumption. -/ +lemma memLp_of_bound {f : ℝ → U} (hf : StronglyMeasurable f) + {C : ℝ} (hb : ∀ t, ‖f t‖ ≤ C) : MemLp f ∞ muPlus := + memLp_top_of_bound hf.aestronglyMeasurable C (Filter.Eventually.of_forall hb) + +/-- An everywhere bounded, strongly measurable representative. The representative is +only modified where it exceeds `C`. -/ +lemma exists_bounded_rep (u : Lp U ∞ muPlus) {C : ℝ} + (hC : 0 ≤ C) (hu : ‖u‖ ≤ C) : + ∃ f : ℝ → U, StronglyMeasurable f ∧ (∀ t, ‖f t‖ ≤ C) ∧ ⇑u =ᵐ[muPlus] f := by + let f : ℝ → U := fun t => if ‖u t‖ ≤ C then u t else 0 + have hf : StronglyMeasurable f := + StronglyMeasurable.ite + ((Lp.stronglyMeasurable u).norm.measurableSet_le stronglyMeasurable_const) + (Lp.stronglyMeasurable u) stronglyMeasurable_const + refine ⟨f, hf, ?_, ?_⟩ + · intro t + by_cases ht : ‖u t‖ ≤ C + · simp [f, ht] + · simpa [f, ht] using hC + · filter_upwards [ae_norm_le u] with t ht + simp [f, ht.trans hu] + +/-- For `p = ∞`, concatenation preserves a common norm bound: if `‖u‖, ‖v‖ ≤ C`, then +`u ⋄_a v` is an input of norm at most `C`. -/ +lemma exists_concat (a : ℝ) (u v : Lp U ∞ muPlus) {C : ℝ} + (hC : 0 ≤ C) (hu : ‖u‖ ≤ C) (hv : ‖v‖ ≤ C) : + ∃ w : Lp U ∞ muPlus, ‖w‖ ≤ C ∧ ⇑w =ᵐ[muPlus] concat a ⇑u ⇑v := by + obtain ⟨f, hf, hfb, huf⟩ := exists_bounded_rep u hC hu + obtain ⟨g, hg, hgb, hvg⟩ := exists_bounded_rep v hC hv + have hb : ∀ t, ‖concat a f g t‖ ≤ C := by + intro t + by_cases ht : t < a + · simpa [concat, ht] using hfb t + · simpa [concat, ht] using hgb (t - a) + have hm := memLp_of_bound (concat_stronglyMeasurable hf hg a) hb + refine ⟨hm.toLp _, ?_, ?_⟩ + · apply lp_norm_le hC + filter_upwards [hm.coeFn_toLp] with t ht + rw [ht] + exact hb t + · exact hm.coeFn_toLp.trans (concat_congr a huf hvg).symm + +/-- The `L^∞` class of a bounded raw function has the same bound. -/ +lemma norm_toLp_le {f : ℝ → U} (hf : MemLp f ∞ muPlus) + {C : ℝ} (hC : 0 ≤ C) (hb : ∀ t, ‖f t‖ ≤ C) : ‖hf.toLp f‖ ≤ C := by + apply lp_norm_le hC + filter_upwards [hf.coeFn_toLp] with t ht + rw [ht] + exact hb t + +end Infinity + +/-- `‖(a + b) - (c + d)‖ ≤ ‖a - c‖ + ‖b‖ + ‖d‖` -/ +lemma norm_three_terms_le {X : Type*} [NormedAddCommGroup X] (a b c d : X) : + ‖a + b - (c + d)‖ ≤ ‖a - c‖ + ‖b‖ + ‖d‖ := by + have key : a + b - (c + d) = (a - c + b) - d := by abel + rw [key] + have k1 := norm_sub_le (a - c + b) d + have k2 := norm_add_le (a - c) b + linarith + +end ALCS + +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Background/Phillips.lean b/LeanPool/AbstractLinearControl/Background/Phillips.lean new file mode 100644 index 0000000000..5915075b10 --- /dev/null +++ b/LeanPool/AbstractLinearControl/Background/Phillips.lean @@ -0,0 +1,767 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import Mathlib.Analysis.Normed.Module.HahnBanach +public import Mathlib.Analysis.RCLike.Basic +public import Mathlib.Topology.ContinuousMap.Bounded.Normed +public import Mathlib.Topology.Instances.Nat +public import Mathlib.Data.Nat.Pairing +public import Mathlib.Data.Set.Finite.Lemmas +public import Mathlib.Topology.Algebra.InfiniteSum.Real + +public import Mathlib.Tactic.Abel +public import Mathlib.Tactic.Choose +public import Mathlib.Tactic.Linarith +public import Mathlib.Tactic.Positivity +public import Mathlib.Tactic.Push + + +/-! +# Phillips' lemma (Lemmas 2.2 and 2.3) + +**Lemma 2.2** (`lem:Phillips`). Let `(μ_n)` be a sequence in `(ℓ^∞(ℕ))*` such that +`μ_n(a) → 0` for every `a ∈ ℓ^∞(ℕ)`. Then `Σ_k |μ_n(e_k)| → 0`; in particular +`μ_n(e_n) → 0`. + +**Lemma 2.3** (`lem:cor-Phillips`). Let `S ∈ 𝓛(ℓ^∞(ℕ), X)` and `t_n ≥ 0` with `t_n → 0`. +Then `‖(T_{t_n} - Id) S e_n‖ → 0`. + +## Main declarations + +* `Phillips.full` : **Lemma 2.2** (summability of each `Σ_k |μ_n(e_k)|`, convergence of the + sums to `0`, and `μ_n(e_n) → 0`); `Phillips.tsum_abs_tendsto_zero` is the real case + written with absolute values. +* `Phillips.uniform` : **Lemma 2.3**. Only strong right-continuity of `T` at `0` is used; + the semigroup law and completeness are not needed. + +`Linfty 𝕜` is the space of bounded sequences with values in `𝕜 = ℝ` or `ℂ`, represented as +bounded continuous functions on the discrete space `ℕ`; `e k` is the `k`-th canonical +vector. The paper quotes Lemma 2.2 from [Phillips 1940]; here it is proved. + +## Proof of Lemma 2.2 + +1. Diagonal statement, `diagonal_tendsto_zero`: `μ_n(e_n) → 0`. An infinite set of indices + is thinned so that a given functional is small on all its subsets (`small_on_subsets`); + a recursive selection then produces a set `A` for which `μ_n(1_A)` cannot tend to zero + (`diagonal_of_indicator_tendsto`). Only finite sums are used. +2. For a single functional, `Σ_{k ∈ s} |φ(e_k)| ≤ ‖φ‖` for every finite `s`, by testing `φ` + on `Σ_{k ∈ s} λ_k e_k` with phases `|λ_k| ≤ 1` (`sum_norm_eval_le`); hence the series + converge (`summable_norm_eval`). +3. Disjoint finite blocks `B_j` with coefficients of modulus `≤ 1` are encoded by one bounded + operator `S : ℓ^∞ → ℓ^∞` with `S e_j` supported in `B_j`, defined coordinatewise + (`exists_block_operator`). +4. Gliding hump (`finite_sum_eventually_small`): if finite sums were not eventually uniformly + small, Steps 2–3 would produce functionals `ν_j = μ_{r_j} ∘ S` contradicting Step 1. + This gives `Σ_k |μ_n(e_k)| → 0` (`tsum_norm_tendsto_zero`). + +Lemma 2.3 (`uniform`) applies the diagonal statement to `μ_n = x_n^* ∘ (T_{t_n} - Id) ∘ S`, +with norming functionals `x_n^*` given by Hahn–Banach (`norm_diagonal_tendsto_zero`). +-/ + +namespace AbstractLinearControl + +@[expose] public section + +noncomputable section + +open Filter +open scoped BigOperators Topology + + +namespace Phillips + +attribute [local instance] Classical.propDecidable + +/-- Bounded scalar sequences, with the supremum norm. -/ +abbrev Linfty (𝕜 : Type*) [RCLike 𝕜] := BoundedContinuousFunction ℕ 𝕜 + +variable {𝕜 : Type*} [RCLike 𝕜] + +/-- The characteristic sequence of a set of natural numbers. -/ +def chi (S : Set ℕ) : Linfty 𝕜 := + BoundedContinuousFunction.ofNormedAddCommGroupDiscrete + (fun k => if k ∈ S then (1 : 𝕜) else 0) 1 + (by + intro k + by_cases hk : k ∈ S <;> simp [hk]) + +@[simp] theorem chi_apply (S : Set ℕ) (k : ℕ) : + chi (𝕜 := 𝕜) S k = if k ∈ S then 1 else 0 := rfl + +/-- The `k`th canonical vector of `ℓ∞`. -/ +def e (k : ℕ) : Linfty 𝕜 := chi {k} + +@[simp] theorem e_apply (k j : ℕ) : + e (𝕜 := 𝕜) k j = if j = k then 1 else 0 := by + simp [e] +/-! ## Step 1: the diagonal statement `μ_n(e_n) → 0` -/ + +/-- An infinite set can be thinned so that a given functional is small on +all characteristic sequences supported in the remaining set. -/ +private theorem small_on_subsets + (φ : Linfty 𝕜 →L[𝕜] 𝕜) (S : Set ℕ) (hS : S.Infinite) + (δ : ℝ) (hδ : 0 < δ) : + ∃ T : Set ℕ, T ⊆ S ∧ T.Infinite ∧ + ∀ B : Set ℕ, B ⊆ T → ‖φ (chi B)‖ ≤ δ := by + classical + -- Partition an infinite subset of S into infinitely many infinite sets. + let emb : ℕ ↪ S := Set.Infinite.natEmbedding S hS + let g : ℕ × ℕ → ℕ := fun p => (emb (Nat.pair p.1 p.2)).val + have hg : Function.Injective g := by + intro p q hpq + have hpq' : Nat.pair p.1 p.2 = Nat.pair q.1 q.2 := + emb.injective (Subtype.ext hpq) + exact Nat.pairEquiv.injective hpq' + let A : ℕ → Set ℕ := fun i => Set.range (fun j => g (i, j)) + have hAinf (i : ℕ) : (A i).Infinite := by + apply Set.infinite_range_of_injective + intro j k hjk + exact congrArg Prod.snd (hg hjk) + have hAS (i : ℕ) : A i ⊆ S := by + rintro x ⟨j, rfl⟩ + exact (emb (Nat.pair i j)).property + by_contra h + have hbad : ∀ i : ℕ, ∃ B : Set ℕ, B ⊆ A i ∧ δ < ‖φ (chi B)‖ := by + intro i + by_contra hi + apply h + refine ⟨A i, hAS i, hAinf i, ?_⟩ + intro B hBA + by_contra hle + exact hi ⟨B, hBA, lt_of_not_ge hle⟩ + choose B hBA hBδ using hbad + have hdisj {i j x : ℕ} (hi : x ∈ B i) (hj : x ∈ B j) : i = j := by + obtain ⟨a, ha⟩ := hBA i hi + obtain ⟨b, hb⟩ := hBA j hj + exact congrArg Prod.fst (hg (ha.trans hb.symm)) + have hz (i : ℕ) : φ (chi (B i)) ≠ 0 := + norm_pos_iff.mp (hδ.trans (hBδ i)) + -- Normalize each witness so that its image under φ is exactly 1. + let v : ℕ → Linfty 𝕜 := fun i => (φ (chi (B i)))⁻¹ • chi (B i) + have hv (i : ℕ) : φ (v i) = 1 := by + simp [v, map_smul, smul_eq_mul, hz i] + have hcoef (i : ℕ) : ‖(φ (chi (B i)))⁻¹‖ ≤ δ⁻¹ := by + simpa only [norm_inv, one_div] using + (one_div_le_one_div_of_le hδ (le_of_lt (hBδ i))) + -- Disjoint supports give a norm bound independent of the number of terms. + have hsum (s : Finset ℕ) : ‖∑ i ∈ s, v i‖ ≤ δ⁻¹ := by + apply (BoundedContinuousFunction.norm_le (show 0 ≤ δ⁻¹ by positivity)).2 + intro x + rw [BoundedContinuousFunction.sum_apply] + by_cases hx : ∃ i ∈ s, x ∈ B i + · obtain ⟨i, hi, hxi⟩ := hx + have heq : (∑ j ∈ s, (v j) x) = (v i) x := by + apply Finset.sum_eq_single i + · intro j hj hji + have hxj : x ∉ B j := fun hxj => hji (hdisj hxj hxi) + simp [v, BoundedContinuousFunction.smul_apply, smul_eq_mul, hxj] + · intro hnot + exact (hnot hi).elim + rw [heq] + simpa [v, BoundedContinuousFunction.smul_apply, smul_eq_mul, hxi] using hcoef i + · have hzero : ∀ i ∈ s, (v i) x = 0 := by + intro i hi + have hxi : x ∉ B i := fun hxi => hx ⟨i, hi, hxi⟩ + simp [v, BoundedContinuousFunction.smul_apply, smul_eq_mul, hxi] + rw [Finset.sum_eq_zero hzero, norm_zero] + positivity + obtain ⟨N, hN⟩ := exists_nat_gt (‖φ‖ * δ⁻¹) + have hval : φ (∑ i ∈ Finset.range N, v i) = (N : 𝕜) := by + simp [map_sum, hv] + have hup : ‖φ (∑ i ∈ Finset.range N, v i)‖ ≤ ‖φ‖ * δ⁻¹ := + (φ.le_opNorm _).trans + (mul_le_mul_of_nonneg_left (hsum _) (norm_nonneg φ)) + rw [hval, RCLike.norm_natCast] at hup + exact (not_le_of_gt hN) hup +/-- It is enough to assume convergence on characteristic sequences. -/ +theorem diagonal_of_indicator_tendsto + (μ : ℕ → (Linfty 𝕜 →L[𝕜] 𝕜)) + (hμ : ∀ S : Set ℕ, Tendsto (fun n => μ n (chi S)) atTop (𝓝 0)) : + Tendsto (fun n => μ n (e n)) atTop (𝓝 0) := by + classical + apply Metric.tendsto_atTop.2 + intro ε hε + by_contra hnot + have hbad : ∀ N : ℕ, ∃ n : ℕ, N ≤ n ∧ ε ≤ ‖μ n (e n)‖ := by + push Not at hnot + simpa only [dist_zero_right] using hnot + let D : Set ℕ := {n | ε ≤ ‖μ n (e n)‖} + have hD : D.Infinite := by + intro hfin + obtain ⟨N, hN⟩ := Set.exists_upper_bound_image D (fun n : ℕ => n) hfin + obtain ⟨n, hn, hbn⟩ := hbad (N + 1) + have hle : n ≤ N := hN n hbn + omega + let δ : ℝ := ε / 4 + have hδ : 0 < δ := by dsimp [δ]; positivity + -- A reservoir is an infinite subset of the bad indices. + let X := {S : Set ℕ // S.Infinite ∧ S ⊆ D} + have hstep : ∀ (F : Set ℕ) (S : X), ∃ (n : ℕ) (T : X), + n ∈ S.val ∧ + ‖μ n (chi F)‖ < δ ∧ + T.val ⊆ S.val ∧ + (∀ m ∈ T.val, n < m) ∧ + (∀ B : Set ℕ, B ⊆ T.val → ‖μ n (chi B)‖ ≤ δ) := by + intro F S + obtain ⟨N, hN⟩ := (Metric.tendsto_atTop.1 (hμ F)) δ hδ + obtain ⟨n, hnS, hnN⟩ := + S.property.1.exists_notMem_finite (Set.finite_lt_nat N) + have hNn : N ≤ n := by + simpa only [Set.mem_ofPred_eq, not_lt] using hnN + have hnsmall : ‖μ n (chi F)‖ < δ := by + simpa only [dist_zero_right] using hN n hNn + have hSinfinite : (S.val \ {m : ℕ | m ≤ n}).Infinite := + S.property.1.sdiff (Set.finite_le_nat n) + obtain ⟨T, hTS, hTinf, hTsmall⟩ := + small_on_subsets (μ n) (S.val \ {m : ℕ | m ≤ n}) hSinfinite δ hδ + have hTsub : T ⊆ S.val := fun m hm => (hTS hm).1 + have hTD : T ⊆ D := fun m hm => S.property.2 (hTsub hm) + refine ⟨n, ⟨T, hTinf, hTD⟩, hnS, hnsmall, hTsub, ?_, hTsmall⟩ + intro m hm + exact lt_of_not_ge (hTS hm).2 + choose pick tail hpick hhead hsub hgt hsmall using hstep + -- State = (already selected indices, current infinite reservoir). + let state : ℕ → Set ℕ × X := + Nat.rec (∅, ⟨D, hD, fun _ h => h⟩) + (fun _ p => (insert (pick p.1 p.2) p.1, tail p.1 p.2)) + let n : ℕ → ℕ := fun i => pick (state i).1 (state i).2 + let F : ℕ → Set ℕ := fun i => (state i).1 + let R : ℕ → Set ℕ := fun i => ((state i).2).val + have hF0 : F 0 = ∅ := rfl + have hFs (i : ℕ) : F (i + 1) = insert (n i) (F i) := rfl + have hnmem (i : ℕ) : n i ∈ R i := hpick (state i).1 (state i).2 + have hRsub (i : ℕ) : R (i + 1) ⊆ R i := hsub (state i).1 (state i).2 + have hRgt (i : ℕ) : ∀ m ∈ R (i + 1), n i < m := + hgt (state i).1 (state i).2 + have hhead' (i : ℕ) : ‖μ (n i) (chi (F i))‖ < δ := + hhead (state i).1 (state i).2 + have hsmall' (i : ℕ) : + ∀ B : Set ℕ, B ⊆ R (i + 1) → ‖μ (n i) (chi B)‖ ≤ δ := + hsmall (state i).1 (state i).2 + have hnD (i : ℕ) : ε ≤ ‖μ (n i) (e (n i))‖ := + (state i).2.property.2 (hnmem i) + have hnstep (i : ℕ) : n i < n (i + 1) := hRgt i _ (hnmem (i + 1)) + have hnmono : StrictMono n := strictMono_nat_of_lt_succ hnstep + have hRanti : Antitone R := antitone_nat_of_succ_le hRsub + have hin : ∀ i : ℕ, i ≤ n i := by + intro i + induction i with + | zero => exact Nat.zero_le _ + | succ i ih => + have hi := hnstep i + omega + have hFmem : ∀ (i x : ℕ), x ∈ F i ↔ ∃ j < i, n j = x := by + intro i + induction i with + | zero => + intro x + simp [hF0] + | succ i ih => + intro x + rw [hFs, Set.mem_insert_iff, ih] + constructor + · rintro (hxi | ⟨j, hj, hjx⟩) + · exact ⟨i, Nat.lt_succ_self i, hxi.symm⟩ + · exact ⟨j, by omega, hjx⟩ + · rintro ⟨j, hj, hjx⟩ + by_cases hji : j = i + · left + simpa [hji] using hjx.symm + · right + exact ⟨j, by omega, hjx⟩ + let A : Set ℕ := Set.range n + let B : ℕ → Set ℕ := fun i => {x | ∃ j, i < j ∧ n j = x} + have hBsub (i : ℕ) : B i ⊆ R (i + 1) := by + rintro x ⟨j, hij, rfl⟩ + exact hRanti (Nat.succ_le_of_lt hij) (hnmem j) + have hsplit (i : ℕ) : + chi (𝕜 := 𝕜) A = chi (F i) + e (n i) + chi (B i) := by + apply BoundedContinuousFunction.ext + intro x + simp only [BoundedContinuousFunction.add_apply, chi_apply, e_apply] + by_cases hx : x ∈ A + · obtain ⟨j, rfl⟩ := hx + have hA : n j ∈ A := ⟨j, rfl⟩ + have hF : n j ∈ F i ↔ j < i := by + rw [hFmem] + constructor + · rintro ⟨k, hk, hkj⟩ + exact hnmono.injective hkj ▸ hk + · intro hji + exact ⟨j, hji, rfl⟩ + have hB : n j ∈ B i ↔ i < j := by + change (∃ k, i < k ∧ n k = n j) ↔ i < j + constructor + · rintro ⟨k, hk, hkj⟩ + exact hnmono.injective hkj ▸ hk + · intro hij + exact ⟨j, hij, rfl⟩ + have heq : n j = n i ↔ j = i := + ⟨fun h => hnmono.injective h, fun h => congrArg n h⟩ + rcases lt_trichotomy j i with hji | hji | hij + · simp [hA, hF, hB, heq, hji, ne_of_lt hji, not_lt_of_ge (le_of_lt hji)] + · subst j + simp [hA, hF, hB] + · simp [hA, hF, hB, heq, hij, ne_of_gt hij, not_lt_of_ge (le_of_lt hij)] + · have hxF : x ∉ F i := by + intro hxF + obtain ⟨j, hj, hjx⟩ := (hFmem i x).1 hxF + exact hx ⟨j, hjx⟩ + have hxB : x ∉ B i := by + rintro ⟨j, hj, hjx⟩ + exact hx ⟨j, hjx⟩ + have hxn : x ≠ n i := by + intro hxn + exact hx ⟨i, hxn.symm⟩ + simp [hx, hxF, hxB, hxn] + -- The characteristic sequence of all selected indices contradicts hμ. + obtain ⟨N, hN⟩ := (Metric.tendsto_atTop.1 (hμ A)) δ hδ + have hA_small : ‖μ (n N) (chi A)‖ < δ := by + simpa only [dist_zero_right] using hN (n N) (hin N) + have hF_small := hhead' N + have hB_small := hsmall' N (B N) (hBsub N) + have hidentity : μ (n N) (chi A) = + μ (n N) (chi (F N)) + μ (n N) (e (n N)) + μ (n N) (chi (B N)) := by + rw [hsplit N, map_add, map_add] + have hdiag : μ (n N) (e (n N)) = + μ (n N) (chi A) - μ (n N) (chi (F N)) - μ (n N) (chi (B N)) := by + rw [hidentity] + abel + have hnorm : ‖μ (n N) (e (n N))‖ ≤ + ‖μ (n N) (chi A)‖ + ‖μ (n N) (chi (F N))‖ + + ‖μ (n N) (chi (B N))‖ := by + rw [hdiag] + exact (norm_sub_le _ _).trans (add_le_add (norm_sub_le _ _) le_rfl) + have hlarge := hnD N + dsimp [δ] at hA_small hF_small hB_small + linarith only [hε, hA_small, hF_small, hB_small, hnorm, hlarge] +/-- Step 1 (diagonal statement): if `μ_n(a) → 0` for every `a ∈ ℓ^∞`, then +`μ_n(e_n) → 0`. This is the "in particular" part of Lemma 2.2, proved first; the full +lemma (`Phillips.full`) is deduced from it. -/ +theorem diagonal_tendsto_zero + (μ : ℕ → (Linfty 𝕜 →L[𝕜] 𝕜)) + (hμ : ∀ a : Linfty 𝕜, Tendsto (fun n => μ n a) atTop (𝓝 0)) : + Tendsto (fun n => μ n (e n)) atTop (𝓝 0) := + diagonal_of_indicator_tendsto μ (fun S => hμ (chi S)) + +end Phillips + +namespace Phillips + +open Filter +open scoped BigOperators Topology + +variable {𝕜 : Type*} [RCLike 𝕜] + +/-! ## Step 2: finite sums `Σ_{k ∈ s} |φ(e_k)| ≤ ‖φ‖` -/ + +/-- Multiplying `z` by this scalar gives the nonnegative real `‖z‖`. +The coefficient is zero when `z = 0`. -/ +private noncomputable def phase (z : 𝕜) : 𝕜 := (‖z‖ : 𝕜) / z + +private theorem phase_mul (z : 𝕜) : phase z * z = (‖z‖ : 𝕜) := by + by_cases hz : z = 0 + · simp [phase, hz] + · exact div_mul_cancel₀ _ hz +private theorem norm_phase_le (z : 𝕜) : ‖phase z‖ ≤ 1 := by + by_cases hz : z = 0 + · simp [phase, hz] + · have hn : ‖z‖ ≠ 0 := ne_of_gt (norm_pos_iff.mpr hz) + simpa only [phase, norm_div, + RCLike.norm_of_nonneg (norm_nonneg z), div_self hn] using + (le_refl (1 : ℝ)) +/-- A finite linear combination of the canonical vectors. -/ +private noncomputable def finiteVector (s : Finset ℕ) (c : ℕ → 𝕜) : Linfty 𝕜 := + ∑ k ∈ s, c k • e k + +private theorem finiteVector_apply (s : Finset ℕ) (c : ℕ → 𝕜) (k : ℕ) : + finiteVector s c k = if k ∈ s then c k else 0 := by + classical + simp only [finiteVector, BoundedContinuousFunction.sum_apply, + BoundedContinuousFunction.smul_apply, e_apply, smul_eq_mul] + by_cases hk : k ∈ s + · rw [ite_eq_left hk] + calc + (∑ j ∈ s, c j * (if k = j then 1 else 0)) = + c k * (if k = k then 1 else 0) := by + apply Finset.sum_eq_single k + · intro j hj hjk + simp [Ne.symm hjk] + · intro hnot + exact (hnot hk).elim + _ = c k := by simp + · rw [ite_eq_right hk] + apply Finset.sum_eq_zero + intro j hj + have hkj : k ≠ j := by + intro h + exact hk (h.symm ▸ hj) + simp [hkj] +private theorem norm_finiteVector_le (s : Finset ℕ) (c : ℕ → 𝕜) + (hc : ∀ k : ℕ, ‖c k‖ ≤ 1) : + ‖finiteVector s c‖ ≤ 1 := by + classical + apply (BoundedContinuousFunction.norm_le (by positivity : (0 : ℝ) ≤ 1)).2 + intro k + rw [finiteVector_apply] + by_cases hk : k ∈ s + · simpa only [ite_eq_left hk] using hc k + · simp [hk] +private theorem norm_eval_finiteVector + (φ : Linfty 𝕜 →L[𝕜] 𝕜) (s : Finset ℕ) : + ‖φ (finiteVector s (fun k => phase (φ (e k))))‖ = + ∑ k ∈ s, ‖φ (e k)‖ := by + have heval : φ (finiteVector s (fun k => phase (φ (e k)))) = + ((∑ k ∈ s, ‖φ (e k)‖ : ℝ) : 𝕜) := by + simp only [finiteVector, map_sum, map_smul, smul_eq_mul, phase_mul] + rw [heval] + exact RCLike.norm_of_nonneg (Finset.sum_nonneg (fun _ _ => norm_nonneg _)) +/-- Every finite sum of the absolute values of the atomic coefficients is +bounded by the norm of the functional. -/ +theorem sum_norm_eval_le (φ : Linfty 𝕜 →L[𝕜] 𝕜) (s : Finset ℕ) : + (∑ k ∈ s, ‖φ (e k)‖) ≤ ‖φ‖ := by + calc + (∑ k ∈ s, ‖φ (e k)‖) = + ‖φ (finiteVector s (fun k => phase (φ (e k))))‖ := + (norm_eval_finiteVector φ s).symm + _ ≤ ‖φ‖ * ‖finiteVector s (fun k => phase (φ (e k)))‖ := + φ.le_opNorm _ + _ ≤ ‖φ‖ * 1 := + mul_le_mul_of_nonneg_left + (norm_finiteVector_le s _ (fun k => norm_phase_le (φ (e k)))) + (norm_nonneg φ) + _ = ‖φ‖ := mul_one _ +/-- The atomic coefficients of any bounded functional on `ℓ∞` are in `ℓ¹`. +This requires no convergence hypothesis on a sequence of functionals. -/ +theorem summable_norm_eval (φ : Linfty 𝕜 →L[𝕜] 𝕜) : + Summable (fun k : ℕ => ‖φ (e k)‖) := + summable_of_sum_le (fun _ => norm_nonneg _) (sum_norm_eval_le φ) + +/-- The `ℓ¹` norm of the atomic coefficients is at most the operator norm. -/ +theorem tsum_norm_eval_le (φ : Linfty 𝕜 →L[𝕜] 𝕜) : + (∑' k : ℕ, ‖φ (e k)‖) ≤ ‖φ‖ := + Real.tsum_le_of_sum_le (fun _ => norm_nonneg _) (sum_norm_eval_le φ) + +/-! ## Step 3: disjoint finite blocks, encoded by one bounded operator `ℓ^∞ → ℓ^∞` -/ + +/-- Disjoint finite blocks with coefficients of norm at most one can be +encoded as the images of the canonical vectors under one bounded operator. +The operator is defined coordinatewise, not by a norm-convergent series. -/ +private theorem exists_block_operator + (s : ℕ → Finset ℕ) + (hs : ∀ i j k : ℕ, k ∈ s i → k ∈ s j → i = j) + (c : ℕ → ℕ → 𝕜) + (hc : ∀ i k : ℕ, ‖c i k‖ ≤ 1) : + ∃ S : Linfty 𝕜 →L[𝕜] Linfty 𝕜, + ∀ i : ℕ, S (e i) = finiteVector (s i) (c i) := by + classical + -- p k is the (unique, when it exists) block containing coordinate k. + let p : ℕ → ℕ := fun k => + if h : ∃ i : ℕ, k ∈ s i then Classical.choose h else 0 + let w : ℕ → 𝕜 := fun k => + if ∃ i : ℕ, k ∈ s i then c (p k) k else 0 + have hw (k : ℕ) : ‖w k‖ ≤ 1 := by + dsimp [w] + by_cases h : ∃ i : ℕ, k ∈ s i + · simpa only [ite_eq_left h] using hc (p k) k + · simp [h] + have hbound (a : Linfty 𝕜) (k : ℕ) : + ‖w k * a (p k)‖ ≤ ‖a‖ := by + calc + ‖w k * a (p k)‖ = ‖w k‖ * ‖a (p k)‖ := norm_mul _ _ + _ ≤ 1 * ‖a‖ := + mul_le_mul (hw k) (BoundedContinuousFunction.norm_coe_le_norm a (p k)) + (norm_nonneg _) (by positivity) + _ = ‖a‖ := one_mul _ + let L : Linfty 𝕜 →ₗ[𝕜] Linfty 𝕜 := + { toFun := fun a => + BoundedContinuousFunction.ofNormedAddCommGroupDiscrete + (fun k => w k * a (p k)) ‖a‖ (hbound a) + map_add' := by + intro a b + apply BoundedContinuousFunction.ext + intro k + change w k * (a (p k) + b (p k)) = + w k * a (p k) + w k * b (p k) + exact mul_add _ _ _ + map_smul' := by + intro t a + apply BoundedContinuousFunction.ext + intro k + change w k * (t * a (p k)) = t * (w k * a (p k)) + exact mul_left_comm _ _ _ } + have hL (a : Linfty 𝕜) : ‖L a‖ ≤ 1 * ‖a‖ := by + rw [one_mul] + apply (BoundedContinuousFunction.norm_le (norm_nonneg a)).2 + intro k + exact hbound a k + refine ⟨L.mkContinuous 1 hL, ?_⟩ + intro i + apply BoundedContinuousFunction.ext + intro k + change w k * (e i) (p k) = finiteVector (s i) (c i) k + rw [finiteVector_apply, e_apply] + by_cases hk : k ∈ s i + · have hex : ∃ j : ℕ, k ∈ s j := ⟨i, hk⟩ + have hp : p k = i := by + dsimp [p] + rw [dite_eq_left hex] + exact hs _ _ k (Classical.choose_spec hex) hk + simp [hk, w, hex, hp] + · by_cases hex : ∃ j : ℕ, k ∈ s j + · have hpk : k ∈ s (p k) := by + dsimp [p] + rw [dite_eq_left hex] + exact Classical.choose_spec hex + have hp : p k ≠ i := by + intro h + exact hk (h ▸ hpk) + simp [hk, hp] + · simp [w, hex, hk] +/-! ## Step 4: uniform smallness of all finite sums (gliding hump) -/ + +/-- Eventually, `Σ_{k ∈ s} |μ_n(e_k)| < ε` for *all* finite sets `s` at once. +Otherwise one selects late rows `r_j` and pairwise disjoint finite blocks `B_j` with +`Σ_{k ∈ B_j} |μ_{r_j}(e_k)| ≥ ε/2`; encoding the blocks (with phases) by one operator `S`, +the functionals `ν_j = μ_{r_j} ∘ S` contradict the diagonal statement of Step 1. -/ +theorem finite_sum_eventually_small + (μ : ℕ → (Linfty 𝕜 →L[𝕜] 𝕜)) + (hμ : ∀ a : Linfty 𝕜, Tendsto (fun n => μ n a) atTop (𝓝 0)) + (ε : ℝ) (hε : 0 < ε) : + ∃ N : ℕ, ∀ n : ℕ, N ≤ n → + ∀ s : Finset ℕ, (∑ k ∈ s, ‖μ n (e k)‖) < ε := by + classical + by_contra hnot + have hbad : ∀ N : ℕ, ∃ n : ℕ, N ≤ n ∧ + ∃ s : Finset ℕ, ε ≤ ∑ k ∈ s, ‖μ n (e k)‖ := by + push Not at hnot + exact hnot + let δ : ℝ := ε / 2 + have hδ : 0 < δ := by dsimp [δ]; positivity + -- A fixed finite set of coordinates has total mass tending to zero. + have hfinite (F : Finset ℕ) : + Tendsto (fun n => ∑ k ∈ F, ‖μ n (e k)‖) atTop (𝓝 (0 : ℝ)) := by + induction F using Finset.induction_on with + | empty => simp + | @insert k F hk ih => + have hkzero : Tendsto (fun n => ‖μ n (e k)‖) atTop (𝓝 (0 : ℝ)) := by + simpa only [norm_zero] using (hμ (e k)).norm + simpa only [Finset.sum_insert hk, add_zero] using hkzero.add ih + -- After excluding any finite set F, a sufficiently late bad functional + -- still has a finite block of mass at least δ outside F. + have hstep : ∀ (F : Finset ℕ) (N : ℕ), + ∃ (n : ℕ) (s : Finset ℕ), N ≤ n ∧ + (∀ k ∈ s, k ∉ F) ∧ δ ≤ ∑ k ∈ s, ‖μ n (e k)‖ := by + intro F N + obtain ⟨K, hK⟩ := (Metric.tendsto_atTop.1 (hfinite F)) δ hδ + obtain ⟨n, hn, t, ht⟩ := hbad (max N K) + have hnN : N ≤ n := (le_max_left N K).trans hn + have hnK : K ≤ n := (le_max_right N K).trans hn + have hFnonneg : 0 ≤ ∑ k ∈ F, ‖μ n (e k)‖ := + Finset.sum_nonneg (fun _ _ => norm_nonneg _) + have hFsmall : (∑ k ∈ F, ‖μ n (e k)‖) < δ := by + simpa only [dist_zero_right, Real.norm_eq_abs, abs_of_nonneg hFnonneg] + using hK n hnK + have hsubset : t ⊆ F ∪ (t \ F) := by + intro k hk + by_cases hkF : k ∈ F + · exact Finset.mem_union.mpr (Or.inl hkF) + · exact Finset.mem_union.mpr (Or.inr (Finset.mem_sdiff.mpr ⟨hk, hkF⟩)) + have hdisj : Disjoint F (t \ F) := by + apply Finset.disjoint_left.mpr + intro k hkF hkt + exact (Finset.mem_sdiff.mp hkt).2 hkF + have hmass : (∑ k ∈ t, ‖μ n (e k)‖) ≤ + (∑ k ∈ F, ‖μ n (e k)‖) + (∑ k ∈ t \ F, ‖μ n (e k)‖) := by + calc + (∑ k ∈ t, ‖μ n (e k)‖) ≤ + ∑ k ∈ F ∪ (t \ F), ‖μ n (e k)‖ := + Finset.sum_le_sum_of_subset_of_nonneg hsubset + (fun _ _ _ => norm_nonneg _) + _ = (∑ k ∈ F, ‖μ n (e k)‖) + (∑ k ∈ t \ F, ‖μ n (e k)‖) := + Finset.sum_union hdisj + refine ⟨n, t \ F, hnN, ?_, ?_⟩ + · intro k hk + exact (Finset.mem_sdiff.mp hk).2 + · dsimp [δ] at hFsmall ⊢ + linarith only [ht, hFsmall, hmass] + choose pick block hpick havoid hmass using hstep + -- F i is the union of the blocks selected before stage i. + let F : ℕ → Finset ℕ := Nat.rec ∅ (fun i F => F ∪ block F i) + let s : ℕ → Finset ℕ := fun i => block (F i) i + let r : ℕ → ℕ := fun i => pick (F i) i + have hFs (i : ℕ) : F (i + 1) = F i ∪ s i := rfl + have hFmono : Monotone F := by + apply monotone_nat_of_le_succ + intro i + rw [hFs] + exact Finset.subset_union_left + have hsF (i : ℕ) : s i ⊆ F (i + 1) := by + rw [hFs] + exact Finset.subset_union_right + have hsavoid (i k : ℕ) (hk : k ∈ s i) : k ∉ F i := + havoid (F i) i k hk + have hs : ∀ i j k : ℕ, k ∈ s i → k ∈ s j → i = j := by + intro i j k hi hj + rcases lt_trichotomy i j with hij | hij | hji + · exact False.elim + (hsavoid j k hj (hFmono (Nat.succ_le_of_lt hij) (hsF i hi))) + · exact hij + · exact False.elim + (hsavoid i k hi (hFmono (Nat.succ_le_of_lt hji) (hsF j hj))) + have hr (i : ℕ) : i ≤ r i := hpick (F i) i + have hr_top : Tendsto r atTop atTop := + tendsto_atTop_mono hr tendsto_id + have hlarge (i : ℕ) : δ ≤ ∑ k ∈ s i, ‖μ (r i) (e k)‖ := + hmass (F i) i + let c : ℕ → ℕ → 𝕜 := fun i k => phase (μ (r i) (e k)) + obtain ⟨S, hS⟩ := exists_block_operator s hs c (fun i k => norm_phase_le _) + let ν : ℕ → (Linfty 𝕜 →L[𝕜] 𝕜) := fun i => (μ (r i)).comp S + have hν : ∀ a : Linfty 𝕜, Tendsto (fun i => ν i a) atTop (𝓝 0) := by + intro a + change Tendsto (fun i => μ (r i) (S a)) atTop (𝓝 0) + exact (hμ (S a)).comp hr_top + have hνlarge (i : ℕ) : δ ≤ ‖ν i (e i)‖ := by + change δ ≤ ‖μ (r i) (S (e i))‖ + rw [hS i] + change δ ≤ ‖μ (r i) (finiteVector (s i) + (fun k => phase (μ (r i) (e k))))‖ + rw [norm_eval_finiteVector] + exact hlarge i + -- Contradiction with the diagonal statement (Step 1). + have hdiag := diagonal_tendsto_zero ν hν + obtain ⟨N, hN⟩ := (Metric.tendsto_atTop.1 hdiag) δ hδ + have hsmall : ‖ν N (e N)‖ < δ := by + simpa only [dist_zero_right] using hN N (le_refl N) + exact (not_lt_of_ge (hνlarge N)) hsmall +/-! ## Lemma 2.2 -/ + +/-- Main conclusion of Lemma 2.2: `Σ_k |μ_n(e_k)| → 0` (each series converges by +`summable_norm_eval`). -/ +theorem tsum_norm_tendsto_zero + (μ : ℕ → (Linfty 𝕜 →L[𝕜] 𝕜)) + (hμ : ∀ a : Linfty 𝕜, Tendsto (fun n => μ n a) atTop (𝓝 0)) : + Tendsto (fun n => ∑' k : ℕ, ‖μ n (e k)‖) atTop (𝓝 (0 : ℝ)) := by + apply Metric.tendsto_atTop.2 + intro ε hε + obtain ⟨N, hN⟩ := finite_sum_eventually_small μ hμ (ε / 2) (by positivity) + refine ⟨N, ?_⟩ + intro n hn + have hnonneg : 0 ≤ ∑' k : ℕ, ‖μ n (e k)‖ := + tsum_nonneg (fun _ => norm_nonneg _) + have hupper : (∑' k : ℕ, ‖μ n (e k)‖) ≤ ε / 2 := + Real.tsum_le_of_sum_le (fun _ => norm_nonneg _) + (fun s => le_of_lt (hN n hn s)) + rw [dist_zero_right, Real.norm_eq_abs, abs_of_nonneg hnonneg] + linarith only [hε, hupper] +/-- **Lemma 2.2** (`lem:Phillips`, Phillips' lemma), over `ℝ` or `ℂ`. Let `(μ_n)` be bounded +linear functionals on `ℓ^∞(ℕ)` with `μ_n(a) → 0` for every `a ∈ ℓ^∞(ℕ)`. Then, for every +`n`, the series `Σ_k |μ_n(e_k)|` converges, `Σ_k |μ_n(e_k)| → 0`, and in particular +`μ_n(e_n) → 0`. -/ +theorem full + (μ : ℕ → (Linfty 𝕜 →L[𝕜] 𝕜)) + (hμ : ∀ a : Linfty 𝕜, Tendsto (fun n => μ n a) atTop (𝓝 0)) : + (∀ n : ℕ, Summable (fun k : ℕ => ‖μ n (e k)‖)) ∧ + Tendsto (fun n => ∑' k : ℕ, ‖μ n (e k)‖) atTop (𝓝 (0 : ℝ)) ∧ + Tendsto (fun n => μ n (e n)) atTop (𝓝 0) := by + have hs (n : ℕ) := summable_norm_eval (μ n) + have ht := tsum_norm_tendsto_zero μ hμ + refine ⟨hs, ht, ?_⟩ + refine squeeze_zero_norm (a := fun n => ∑' k : ℕ, ‖μ n (e k)‖) ?_ ht + intro n + exact (hs n).le_tsum n (fun _ _ => norm_nonneg _) +/-- Lemma 2.2 for real scalars, written with absolute values as in the paper. -/ +theorem tsum_abs_tendsto_zero + (μ : ℕ → (Linfty ℝ →L[ℝ] ℝ)) + (hμ : ∀ a : Linfty ℝ, Tendsto (fun n => μ n a) atTop (𝓝 0)) : + Tendsto (fun n => ∑' k : ℕ, |μ n (e k)|) atTop (𝓝 (0 : ℝ)) := by + simpa only [Real.norm_eq_abs] using tsum_norm_tendsto_zero μ hμ +end Phillips + +namespace Phillips + +open Filter +open scoped Topology + +variable {𝕜 : Type*} [RCLike 𝕜] +variable {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] + +/-! ## Lemma 2.3 -/ + +/-- Vector-valued version of `diagonal_tendsto_zero`: if `A_n a → 0` for every `a ∈ ℓ^∞`, +then `‖A_n e_n‖ → 0`. (A norming functional is chosen for each `A_n e_n`.) -/ +theorem norm_diagonal_tendsto_zero + (A : ℕ → (Linfty 𝕜 →L[𝕜] X)) + (hA : ∀ a : Linfty 𝕜, + Tendsto (fun n => A n a) atTop (𝓝 0)) : + Tendsto (fun n => ‖A n (e n)‖) atTop (𝓝 0) := by + classical + -- Choose a norming functional for each diagonal vector. + choose φ hφnorm hφeval using + (fun n : ℕ => exists_dual_vector'' 𝕜 (A n (e n))) + let μ : ℕ → (Linfty 𝕜 →L[𝕜] 𝕜) := + fun n => (φ n).comp (A n) + -- The scalar functionals converge pointwise to zero. + have hμ : ∀ a : Linfty 𝕜, + Tendsto (fun n => μ n a) atTop (𝓝 0) := by + intro a + refine squeeze_zero_norm (a := fun n => ‖A n a‖) ?_ ?_ + · intro n + change ‖φ n (A n a)‖ ≤ ‖A n a‖ + calc + ‖φ n (A n a)‖ ≤ ‖φ n‖ * ‖A n a‖ := + (φ n).le_opNorm _ + _ ≤ 1 * ‖A n a‖ := + mul_le_mul_of_nonneg_right (hφnorm n) (norm_nonneg _) + _ = ‖A n a‖ := one_mul _ + · simpa only [norm_zero] using (hA a).norm + -- Taking norms recovers the norms of the diagonal vectors. + have hnorm (n : ℕ) : ‖μ n (e n)‖ = ‖A n (e n)‖ := by + change ‖φ n (A n (e n))‖ = ‖A n (e n)‖ + rw [hφeval n] + exact RCLike.norm_of_nonneg (norm_nonneg _) + simpa only [hnorm, norm_zero] using + (diagonal_tendsto_zero μ hμ).norm +/-- **Lemma 2.3** (`lem:cor-Phillips`). Let `S : ℓ^∞ → X` be a bounded operator and +`t n ≥ 0` with `t n → 0`. Then `‖(T (t n) - Id) (S (e n))‖ → 0`. + +Only strong right-continuity of `T` at zero is required; the semigroup law and +completeness of `X` are not used. -/ +theorem uniform + (S : Linfty 𝕜 →L[𝕜] X) + (T : ℝ → (X →L[𝕜] X)) + (hT : ∀ x : X, + Tendsto (fun s : ℝ => T s x) + (nhdsWithin 0 (Set.Ici 0)) (𝓝 x)) + (t : ℕ → ℝ) + (ht_nonneg : ∀ n : ℕ, 0 ≤ t n) + (ht : Tendsto t atTop (𝓝 0)) : + Tendsto + (fun n => + ‖(T (t n) - ContinuousLinearMap.id 𝕜 X) (S (e n))‖) + atTop (𝓝 0) := by + have htWithin : + Tendsto t atTop (nhdsWithin (0 : ℝ) (Set.Ici 0)) := + tendsto_nhdsWithin_iff.2 + ⟨ht, Filter.Eventually.of_forall (fun n => ht_nonneg n)⟩ + refine norm_diagonal_tendsto_zero + (fun n => (T (t n) - ContinuousLinearMap.id 𝕜 X).comp S) ?_ + intro a + have hTa : + Tendsto (fun n => T (t n) (S a)) atTop (𝓝 (S a)) := + (hT (S a)).comp htWithin + change Tendsto (fun n => T (t n) (S a) - S a) atTop (𝓝 0) + simpa only [sub_self] using + (hTa.sub + (tendsto_const_nhds : + Tendsto (fun _ : ℕ => S a) atTop (𝓝 (S a)))) +end Phillips + +end +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Background/Semigroup.lean b/LeanPool/AbstractLinearControl/Background/Semigroup.lean new file mode 100644 index 0000000000..8a34e9c2aa --- /dev/null +++ b/LeanPool/AbstractLinearControl/Background/Semigroup.lean @@ -0,0 +1,205 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import Mathlib.Analysis.Normed.Operator.BanachSteinhaus +public import Mathlib.Analysis.SpecialFunctions.Log.Basic +public import Mathlib.Analysis.SpecificLimits.Basic + + +/-! +# Strongly continuous semigroups (Proposition 1.2) + +* `C0Semigroup 𝕜 X` : strongly continuous semigroups `T` on `X` (first item of + Definition 1.1): `T 0 = Id`, `T (t + s) = T t ∘ T s` for `t, s ≥ 0`, and `T t y → y` + as `t → 0⁺` for every `y`. +* `C0Semigroup.exists_exp_bound` : `‖T t‖ ≤ M exp(ω t)` for `t ≥ 0` + ([Pazy 1983, Chapter 1, Theorem 2.2], used in the proofs of Theorem 1.5 and + Proposition 1.3); proved with the Banach–Steinhaus theorem. +* `C0Semigroup.continuousOn_orbit` : **Proposition 1.2** + (`prop:pazy-semigroup-solution-continuous`), `t ↦ T t x°` is continuous on `ℝ₊`. + +`T` is a function `ℝ → (X →L[𝕜] X)`; all axioms only involve nonnegative times, so the +values of `T t` for `t < 0` play no role. Completeness of `X` is assumed where needed. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open Filter Topology + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] +variable {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] + +/-- A strongly continuous semigroup on `X` (first item of Definition 1.1). -/ +structure C0Semigroup (𝕜 : Type*) (X : Type*) [NontriviallyNormedField 𝕜] + [NormedAddCommGroup X] [NormedSpace 𝕜 X] where + /-- the operators `T t` -/ + T : ℝ → X →L[𝕜] X + /-- `T 0 = Id` -/ + T_zero : T 0 = ContinuousLinearMap.id 𝕜 X + /-- `T (t + s) = T t ∘ T s` for `t, s ≥ 0` -/ + T_add : ∀ t s : ℝ, 0 ≤ t → 0 ≤ s → T (t + s) = (T t).comp (T s) + /-- `T t y → y` as `t → 0⁺`, for every `y` -/ + T_cont : ∀ y : X, Tendsto (fun t => T t y) (nhdsWithin 0 (Set.Ici 0)) (𝓝 y) + +namespace C0Semigroup + +variable (S : C0Semigroup 𝕜 X) + +/-! ## Exponential bound -/ + +/-- First step: `‖T t‖ ≤ M` on some interval `[0, τ]` (Banach–Steinhaus). -/ +theorem exists_bound_near_zero [CompleteSpace X] : + ∃ τ > 0, ∃ M ≥ 1, ∀ t, 0 ≤ t → t ≤ τ → ‖S.T t‖ ≤ M := by + by_contra h + -- otherwise, for every `n`, there is `t n ∈ [0, 1/(n+1)]` with `‖T (t n)‖ > n + 1` + have key : ∀ n : ℕ, ∃ t : ℝ, 0 ≤ t ∧ t ≤ 1 / ((n : ℝ) + 1) ∧ (n : ℝ) + 1 < ‖S.T t‖ := by + intro n + by_contra hn + push Not at hn + exact h ⟨1 / ((n : ℝ) + 1), by positivity, (n : ℝ) + 1, + le_add_of_nonneg_left (by positivity), hn⟩ + choose t ht0 htle htbig using key + -- `t n → 0⁺` + have ht_lim : Tendsto t atTop (nhdsWithin 0 (Set.Ici 0)) := by + rw [tendsto_nhdsWithin_iff] + constructor + · exact squeeze_zero ht0 htle tendsto_one_div_add_atTop_nhds_zero_nat + · exact Filter.Eventually.of_forall (fun n => Set.mem_Ici.2 (ht0 n)) + -- for each `x`, the sequence `T (t n) x` converges to `x`, hence is bounded + have hbdd : ∀ x : X, ∃ C, ∀ n, ‖S.T (t n) x‖ ≤ C := by + intro x + have hx : Tendsto (fun n => S.T (t n) x) atTop (𝓝 x) := (S.T_cont x).comp ht_lim + obtain ⟨C, hC⟩ := isBounded_iff_forall_norm_le.1 (Metric.isBounded_range_of_tendsto _ hx) + exact ⟨C, fun n => hC _ (Set.mem_range_self n)⟩ + -- Banach–Steinhaus: the norms `‖T (t n)‖` are bounded, contradiction + obtain ⟨C, hC⟩ := banach_steinhaus hbdd + obtain ⟨n, hn⟩ := exists_nat_gt C + have h1 : ‖S.T (t n)‖ ≤ C := hC n + have h2 := htbig n + linarith + +/-- Exponential bound: `‖T t‖ ≤ M * exp (ω * t)` for all `t ≥ 0`, with `ω ≥ 0`, `M ≥ 1`. -/ +theorem exists_exp_bound [CompleteSpace X] : + ∃ ω ≥ 0, ∃ M ≥ 1, ∀ t, 0 ≤ t → ‖S.T t‖ ≤ M * Real.exp (ω * t) := by + obtain ⟨τ, hτ, M, hM, hbound⟩ := S.exists_bound_near_zero + have hMpos : 0 < M := by linarith + have hlogM : 0 ≤ Real.log M := Real.log_nonneg hM + -- `‖T (k τ)‖ ≤ M ^ k`, by induction on `k` + have hpow : ∀ k : ℕ, ‖S.T (k * τ)‖ ≤ M ^ k := by + intro k + induction k with + | zero => + rw [Nat.cast_zero, zero_mul, S.T_zero, pow_zero] + exact ContinuousLinearMap.norm_id_le + | succ k ih => + have hk : ((k + 1 : ℕ) : ℝ) * τ = k * τ + τ := by push_cast; ring + rw [hk, S.T_add (k * τ) τ (mul_nonneg (by positivity) hτ.le) hτ.le, pow_succ] + calc ‖(S.T (k * τ)).comp (S.T τ)‖ + ≤ ‖S.T (k * τ)‖ * ‖S.T τ‖ := by apply ContinuousLinearMap.opNorm_comp_le + _ ≤ M ^ k * M := + mul_le_mul ih (hbound τ hτ.le le_rfl) (norm_nonneg _) (pow_nonneg hMpos.le k) + -- `ω := log M / τ` + refine ⟨Real.log M / τ, div_nonneg hlogM hτ.le, M, hM, fun t ht => ?_⟩ + -- write `t = k τ + t'` with `k = ⌊t/τ⌋` and `t' ∈ [0, τ)` + obtain ⟨k, hk_le, hk_lt⟩ : ∃ k : ℕ, (k : ℝ) ≤ t / τ ∧ t / τ < k + 1 := + ⟨⌊t / τ⌋₊, Nat.floor_le (div_nonneg ht hτ.le), Nat.lt_floor_add_one _⟩ + have h1 : (k : ℝ) * τ ≤ t := (le_div_iff₀ hτ).1 hk_le + have h2 : t < (k + 1) * τ := (div_lt_iff₀ hτ).1 hk_lt + -- `T t = T (k τ) ∘ T (t - k τ)` + have hdec : S.T t = (S.T (k * τ)).comp (S.T (t - k * τ)) := by + rw [← S.T_add (k * τ) (t - k * τ) (mul_nonneg (by positivity) hτ.le) (by linarith)] + rw [show (k : ℝ) * τ + (t - k * τ) = t by ring] + -- `‖T t‖ ≤ M ^ k * M` + have h3 : ‖S.T t‖ ≤ M ^ k * M := by + rw [hdec] + calc ‖(S.T (k * τ)).comp (S.T (t - k * τ))‖ + ≤ ‖S.T (k * τ)‖ * ‖S.T (t - k * τ)‖ := by apply ContinuousLinearMap.opNorm_comp_le + _ ≤ M ^ k * M := + mul_le_mul (hpow k) (hbound (t - k * τ) (by linarith) (by linarith)) + (norm_nonneg _) (pow_nonneg hMpos.le k) + -- `M ^ k = exp (k log M) ≤ exp (ω t)` since `k ≤ t / τ` + have h4 : M ^ k ≤ Real.exp (Real.log M / τ * t) := by + calc M ^ k = Real.exp (Real.log M) ^ k := by rw [Real.exp_log hMpos] + _ = Real.exp (k * Real.log M) := (Real.exp_nat_mul _ _).symm + _ ≤ Real.exp (Real.log M / τ * t) := by + apply Real.exp_le_exp.2 + calc (k : ℝ) * Real.log M ≤ t / τ * Real.log M := + mul_le_mul_of_nonneg_right hk_le hlogM + _ = Real.log M / τ * t := by ring + calc ‖S.T t‖ ≤ M ^ k * M := h3 + _ ≤ Real.exp (Real.log M / τ * t) * M := mul_le_mul_of_nonneg_right h4 hMpos.le + _ = M * Real.exp (Real.log M / τ * t) := mul_comm _ _ + +/-! ## Proposition 1.2: continuity of the orbits -/ + +/-- `T (a + h) y - T a y = T a (T h y - y)` -/ +theorem orbit_sub (y : X) (a h : ℝ) (ha : 0 ≤ a) (hh : 0 ≤ h) : + S.T (a + h) y - S.T a y = S.T a (S.T h y - y) := by + rw [S.T_add a h ha hh, ContinuousLinearMap.comp_apply, map_sub] + +/-- `‖T (a + h) y - T a y‖ ≤ ‖T a‖ ‖T h y - y‖` -/ +theorem norm_orbit_sub_le (y : X) (a h : ℝ) (ha : 0 ≤ a) (hh : 0 ≤ h) : + ‖S.T (a + h) y - S.T a y‖ ≤ ‖S.T a‖ * ‖S.T h y - y‖ := by + rw [S.orbit_sub y a h ha hh] + apply ContinuousLinearMap.le_opNorm + +/-- **Proposition 1.2** (`prop:pazy-semigroup-solution-continuous`). For every `y`, +`t ↦ T t y` is continuous on `ℝ₊ = [0, ∞)`. -/ +theorem continuousOn_orbit [CompleteSpace X] (y : X) : + ContinuousOn (fun t => S.T t y) (Set.Ici 0) := by + obtain ⟨ω, hω, M, hM, hexp⟩ := S.exists_exp_bound + rw [Metric.continuousOn_iff] + intro t₀ ht₀ ε hε + rw [Set.mem_Ici] at ht₀ + -- uniform bound `‖T a‖ ≤ K` for `a ∈ [0, t₀]`, with `K := M exp (ω t₀)` + obtain ⟨K, hKpos, hK⟩ : ∃ K > 0, ∀ a, 0 ≤ a → a ≤ t₀ → ‖S.T a‖ ≤ K := by + refine ⟨M * Real.exp (ω * t₀), mul_pos (by linarith) (Real.exp_pos _), ?_⟩ + intro a ha hat + calc ‖S.T a‖ ≤ M * Real.exp (ω * a) := hexp a ha + _ ≤ M * Real.exp (ω * t₀) := + mul_le_mul_of_nonneg_left + (Real.exp_le_exp.2 (mul_le_mul_of_nonneg_left hat hω)) (by linarith) + -- strong continuity at `0`, with tolerance `ε / K` + obtain ⟨δ, hδ, hcont⟩ := + Metric.tendsto_nhdsWithin_nhds.1 (S.T_cont y) (ε / K) (div_pos hε hKpos) + -- key estimate: `‖T (a + h) y - T a y‖ < ε` for `a ∈ [0, t₀]`, `h ∈ [0, δ)` + have key : ∀ a h : ℝ, 0 ≤ a → a ≤ t₀ → 0 ≤ h → h < δ → + ‖S.T (a + h) y - S.T a y‖ < ε := by + intro a h ha hat hh hhδ + have h1 : dist (S.T h y) y < ε / K := by + apply hcont (Set.mem_Ici.2 hh) + rw [Real.dist_eq, sub_zero, abs_of_nonneg hh] + exact hhδ + rw [dist_eq_norm] at h1 + have h2 : K * ‖S.T h y - y‖ < ε := by + rw [mul_comm] + exact (lt_div_iff₀ hKpos).1 h1 + have h3 : ‖S.T a‖ * ‖S.T h y - y‖ ≤ K * ‖S.T h y - y‖ := + mul_le_mul_of_nonneg_right (hK a ha hat) (norm_nonneg _) + have h4 := S.norm_orbit_sub_le y a h ha hh + linarith + refine ⟨δ, hδ, fun t ht hdist => ?_⟩ + rw [Set.mem_Ici] at ht + rw [Real.dist_eq] at hdist + obtain ⟨hd1, hd2⟩ := abs_lt.1 hdist + show dist (S.T t y) (S.T t₀ y) < ε + rw [dist_eq_norm] + rcases le_total t₀ t with htt | htt + · -- case `t₀ ≤ t`: apply `key` with `a = t₀`, `h = t - t₀` + have := key t₀ (t - t₀) ht₀ le_rfl (by linarith) (by linarith) + rwa [show t₀ + (t - t₀) = t by ring] at this + · -- case `t ≤ t₀`: apply `key` with `a = t`, `h = t₀ - t` + have := key t (t₀ - t) ht htt (by linarith) (by linarith) + rwa [show t + (t₀ - t) = t₀ by ring, norm_sub_rev] at this + +end C0Semigroup + +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/ContinuityFiniteP.lean b/LeanPool/AbstractLinearControl/ContinuityFiniteP.lean new file mode 100644 index 0000000000..0f4611c6e9 --- /dev/null +++ b/LeanPool/AbstractLinearControl/ContinuityFiniteP.lean @@ -0,0 +1,173 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Definitions + + +/-! +# Continuity of the input response for `p < ∞` (Proposition 1.3) + +**Proposition 1.3** (`prop:finite-p-solution-continuous`). Assume `p ∈ [1, ∞)`. +For all `u ∈ L^p(ℝ₊; U)`, `t ↦ Φ_t u` is continuous on `ℝ₊`. + +The paper refers to [Weiss 1989, Proposition 2.3] and does not write out a proof. +We formalize the classical argument, which uses `p < ∞` twice: + +1. `‖u‖_{L^p(0, t)} → 0` as `t → 0` (`ALCS.tendsto_norm_truncate`). With causality and + monotonicity of `κ`, this gives `Φ_t u → 0` as `t → 0⁺` (`ALCS.tendsto_Phi_zero`). +2. Right continuity at `τ ≥ 0` then follows from the composition property + `Φ_{τ+h} u = T_h Φ_τ u + Φ_h u(τ + ·)` (`ALCS.tendsto_Phi_right`). +3. Left continuity at `τ > 0` uses `u = u ⋄_h u(h + ·)`, which gives + `Φ_τ u - Φ_{τ-h} u = T_{τ-h} Φ_h u + Φ_{τ-h} (u(h + ·) - u)`, and the continuity of + translations in `L^p` (`ALCS.tendsto_norm_shiftLeft_sub`); see `ALCS.tendsto_Phi_left`. + +The main statement is `ALCS.continuousOn_Phi_of_ne_top`. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open MeasureTheory Filter Topology +open scoped ENNReal + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] +variable {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] +variable {U : Type*} [NormedAddCommGroup U] [NormedSpace 𝕜 U] + +namespace ALCS + +variable {p : ℝ≥0∞} [Fact (1 ≤ p)] (S : ALCS 𝕜 X U p) + +/-- Step 1: for `p < ∞`, `Φ t u → 0` as `t → 0⁺`. +For `t ∈ [0, 1]`, `‖Φ_t u‖ = ‖Φ_t (u ⋄_t 0)‖ ≤ ‖Φ_1‖ ‖u‖_{L^p(0, t)}`. -/ +theorem tendsto_Phi_zero (hp : p ≠ ∞) (u : Lp U p muPlus) : + Tendsto (fun t => S.Φ t u) (𝓝[≥] 0) (𝓝 0) := by + have hbound : ∀ᶠ t in 𝓝[≥] (0 : ℝ), ‖S.Φ t u‖ ≤ ‖S.Φ 1‖ * ‖truncate t u‖ := by + have h1 : ∀ᶠ t in 𝓝[≥] (0 : ℝ), t ≤ 1 := + (eventually_le_nhds (by norm_num : (0 : ℝ) < 1)).filter_mono nhdsWithin_le_nhds + filter_upwards [self_mem_nhdsWithin, h1] with t ht0 ht1 + -- causality: `Φ t u = Φ t (u ⋄_t 0)` + rw [← S.causality t ht0 u 0 (truncate t u) (concat_truncate t u)] + calc + ‖S.Φ t (truncate t u)‖ ≤ ‖S.Φ t‖ * ‖truncate t u‖ := (S.Φ t).le_opNorm _ + _ ≤ ‖S.Φ 1‖ * ‖truncate t u‖ := + mul_le_mul_of_nonneg_right (S.norm_Phi_mono ht0 ht1) (norm_nonneg _) + have hlim : Tendsto (fun t => ‖S.Φ 1‖ * ‖truncate t u‖) (𝓝[≥] 0) (𝓝 0) := by + simpa using ((tendsto_norm_truncate hp u).mono_left nhdsWithin_le_nhds).const_mul ‖S.Φ 1‖ + exact tendsto_zero_iff_norm_tendsto_zero.2 + (squeeze_zero' (Eventually.of_forall fun _ => norm_nonneg _) hbound hlim) + +/-- Step 2 (right continuity): for `p < ∞` and `τ ≥ 0`, `Φ (τ + h) u → Φ τ u` as `h → 0⁺`, +since `Φ (τ + h) u = T h (Φ τ u) + Φ h u(τ + ·)`. -/ +theorem tendsto_Phi_right (hp : p ≠ ∞) (u : Lp U p muPlus) (τ : ℝ) (hτ : 0 ≤ τ) : + Tendsto (fun h => S.Φ (τ + h) u) (𝓝[≥] 0) (𝓝 (S.Φ τ u)) := by + obtain ⟨u₁, -, hcat⟩ := exists_shift τ hτ u + have heq : ∀ᶠ h in 𝓝[≥] (0 : ℝ), S.T h (S.Φ τ u) + S.Φ h u₁ = S.Φ (τ + h) u := by + filter_upwards [self_mem_nhdsWithin] with h hh + exact (S.composition τ h hτ hh u u₁ u hcat).symm + have hlim : Tendsto (fun h => S.T h (S.Φ τ u) + S.Φ h u₁) (𝓝[≥] 0) (𝓝 (S.Φ τ u + 0)) := + (S.T_cont (S.Φ τ u)).add (S.tendsto_Phi_zero hp u₁) + rw [add_zero] at hlim + exact hlim.congr' heq + +/-- Step 3 (left continuity): for `p < ∞` and `τ > 0`, `Φ (τ - h) u → Φ τ u` as `h → 0⁺`. +With `u_h := u (h + ·)`, one has `u = u ⋄_h u_h`, hence +`Φ τ u - Φ (τ - h) u = T (τ - h) (Φ h u) + Φ (τ - h) (u_h - u)`, so that +`‖Φ τ u - Φ (τ - h) u‖ ≤ K ‖Φ h u‖ + ‖Φ τ‖ ‖u_h - u‖`, where `K` bounds `‖T s‖` on `[0, τ]`. -/ +theorem tendsto_Phi_left [CompleteSpace X] (hp : p ≠ ∞) (u : Lp U p muPlus) + (τ : ℝ) (hτ : 0 < τ) : + Tendsto (fun h => S.Φ (τ - h) u) (𝓝[≥] 0) (𝓝 (S.Φ τ u)) := by + -- a bound `K` for `‖T s‖` on `[0, τ]` + obtain ⟨K, hK⟩ : ∃ K, ∀ s, 0 ≤ s → s ≤ τ → ‖S.T s‖ ≤ K := by + obtain ⟨ω, hω, M, hM, hexp⟩ := S.toC0Semigroup.exists_exp_bound + refine ⟨M * Real.exp (ω * τ), fun s hs hsτ => (hexp s hs).trans ?_⟩ + exact mul_le_mul_of_nonneg_left + (Real.exp_le_exp.2 (mul_le_mul_of_nonneg_left hsτ hω)) (by linarith) + -- the key estimate + have hest : ∀ h, 0 ≤ h → h ≤ τ → + ‖S.Φ (τ - h) u - S.Φ τ u‖ ≤ K * ‖S.Φ h u‖ + ‖S.Φ τ‖ * ‖shiftLeft h u - u‖ := by + intro h hh hhτ + have hcomp := S.composition h (τ - h) hh (by linarith) u (shiftLeft h u) u + (concat_shiftLeft h hh u) + rw [show h + (τ - h) = τ by ring] at hcomp + have hid : S.Φ (τ - h) u - S.Φ τ u = + -(S.T (τ - h) (S.Φ h u) + S.Φ (τ - h) (shiftLeft h u - u)) := by + rw [hcomp, map_sub] + abel + rw [hid, norm_neg] + calc + _ ≤ ‖S.T (τ - h) (S.Φ h u)‖ + ‖S.Φ (τ - h) (shiftLeft h u - u)‖ := norm_add_le _ _ + _ ≤ K * ‖S.Φ h u‖ + ‖S.Φ τ‖ * ‖shiftLeft h u - u‖ := by + apply add_le_add + · exact ((S.T (τ - h)).le_opNorm _).trans + (mul_le_mul_of_nonneg_right (hK _ (by linarith) (by linarith)) (norm_nonneg _)) + · exact ((S.Φ (τ - h)).le_opNorm _).trans + (mul_le_mul_of_nonneg_right (S.norm_Phi_mono (by linarith) (by linarith)) + (norm_nonneg _)) + -- both terms of the bound tend to zero + have h1 : Tendsto (fun h => ‖S.Φ h u‖) (𝓝[≥] 0) (𝓝 0) := by + simpa using (S.tendsto_Phi_zero hp u).norm + have h2 : Tendsto (fun h => ‖shiftLeft h u - u‖) (𝓝[≥] 0) (𝓝 0) := + (tendsto_norm_shiftLeft_sub hp u).mono_left nhdsWithin_le_nhds + have hlim : Tendsto (fun h => K * ‖S.Φ h u‖ + ‖S.Φ τ‖ * ‖shiftLeft h u - u‖) + (𝓝[≥] 0) (𝓝 0) := by + simpa using (h1.const_mul K).add (h2.const_mul ‖S.Φ τ‖) + have hev : ∀ᶠ h in 𝓝[≥] (0 : ℝ), + ‖S.Φ (τ - h) u - S.Φ τ u‖ ≤ K * ‖S.Φ h u‖ + ‖S.Φ τ‖ * ‖shiftLeft h u - u‖ := by + filter_upwards [self_mem_nhdsWithin, + (eventually_le_nhds hτ).filter_mono nhdsWithin_le_nhds] with h hh hhτ + exact hest h hh hhτ + exact tendsto_iff_norm_sub_tendsto_zero.2 + (squeeze_zero' (Eventually.of_forall fun _ => norm_nonneg _) hev hlim) + +/-- **Proposition 1.3** (`prop:finite-p-solution-continuous`). +For `p ∈ [1, ∞)` and every input `u ∈ L^p(ℝ₊; U)`, the map `t ↦ Φ t u` is continuous +on `ℝ₊ = [0, ∞)`. -/ +theorem continuousOn_Phi_of_ne_top [CompleteSpace X] (hp : p ≠ ∞) (u : Lp U p muPlus) : + ContinuousOn (fun t => S.Φ t u) (Set.Ici 0) := by + rw [Metric.continuousOn_iff] + intro τ hτ ε hε + rw [Set.mem_Ici] at hτ + -- right continuity + obtain ⟨δ₁, hδ₁, hright⟩ := + Metric.tendsto_nhdsWithin_nhds.1 (S.tendsto_Phi_right hp u τ hτ) ε hε + -- left continuity (vacuous at `τ = 0`) + obtain ⟨δ₂, hδ₂, hleft⟩ : ∃ δ₂ > 0, ∀ h : ℝ, 0 ≤ h → h < δ₂ → h ≤ τ → + dist (S.Φ (τ - h) u) (S.Φ τ u) < ε := by + rcases hτ.eq_or_lt with h0 | hpos + · refine ⟨1, one_pos, fun h hh _ hhτ => ?_⟩ + rw [show τ - h = τ by linarith, dist_self] + exact hε + · obtain ⟨δ₂, hδ₂, hl⟩ := + Metric.tendsto_nhdsWithin_nhds.1 (S.tendsto_Phi_left hp u τ hpos) ε hε + refine ⟨δ₂, hδ₂, fun h hh hhδ _ => hl (Set.mem_Ici.2 hh) ?_⟩ + rwa [Real.dist_eq, sub_zero, abs_of_nonneg hh] + refine ⟨min δ₁ δ₂, lt_min hδ₁ hδ₂, fun t ht hdist => ?_⟩ + rw [Set.mem_Ici] at ht + rw [Real.dist_eq] at hdist + show dist (S.Φ t u) (S.Φ τ u) < ε + rcases le_total τ t with htτ | htτ + · -- `t = τ + h` with `h = t - τ ≥ 0` + have hh : 0 ≤ t - τ := sub_nonneg.2 htτ + have hlt : t - τ < δ₁ := + lt_of_lt_of_le (by rwa [abs_of_nonneg hh] at hdist) (min_le_left _ _) + have h := hright (Set.mem_Ici.2 hh) (by rwa [Real.dist_eq, sub_zero, abs_of_nonneg hh]) + rwa [show τ + (t - τ) = t by ring] at h + · -- `t = τ - h` with `h = τ - t ∈ [0, τ]` + have hh : 0 ≤ τ - t := sub_nonneg.2 htτ + have hlt : τ - t < δ₂ := by + have : |t - τ| = τ - t := by rw [abs_sub_comm, abs_of_nonneg hh] + exact lt_of_lt_of_le (by rwa [this] at hdist) (min_le_right _ _) + have h := hleft (τ - t) hh hlt (by linarith) + rwa [show τ - (τ - t) = t by ring] at h + +end ALCS + +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/ContinuityLinfty.lean b/LeanPool/AbstractLinearControl/ContinuityLinfty.lean new file mode 100644 index 0000000000..e1ef345ce9 --- /dev/null +++ b/LeanPool/AbstractLinearControl/ContinuityLinfty.lean @@ -0,0 +1,130 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.ZeroClass + + +/-! +# Continuity of the input response for `p = ∞` (Corollary 1.6) + +**Corollary 1.6** (`cor:p-infty-solution-continuous`). Let `X`, `U` be Banach spaces and +`(𝕋, Φ)` an abstract linear control system with `p = ∞`. For all `u ∈ L^∞(ℝ₊; U)`, +`t ↦ Φ_t u` is continuous on `ℝ₊`. + +This answers positively Problem 2.4 of [Weiss 1989]. The proof (§ 2.4 of the paper) only +uses Theorem 1.5 (`ALCS.zero_class`), the composition property and the continuity of +semigroup orbits (Proposition 1.2, `C0Semigroup.continuousOn_orbit`): + +* at `t₀ = 0`, `‖Φ_t u‖ ≤ κ(t) ‖u‖ → 0`; +* at `t₀ > 0`, with `t₁ = t₀ - δ` and `u₁ = u (t₁ + ·)`, the composition property gives + `Φ_{t₁ + r} u = T_r (Φ_{t₁} u) + Φ_r u₁`, and `‖Φ_r u₁‖ ≤ κ(2δ) ‖u‖` for `r ≤ 2δ`. + +The main statement is `ALCS.continuousOn_Phi`. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open MeasureTheory Filter Topology +open scoped ENNReal + +noncomputable section + +variable {𝕜 : Type*} [RCLike 𝕜] +variable {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] +variable {U : Type*} [NormedAddCommGroup U] [NormedSpace 𝕜 U] + +namespace ALCS + +/-- Consequence of Theorem 1.5: for `ε > 0` there is `η > 0` such that +`‖Φ r v‖ < ε` for all `r ∈ [0, η)` and all inputs `v` with `‖v‖ ≤ ‖u‖`. -/ +theorem small_Phi [CompleteSpace X] (S : ALCS 𝕜 X U ∞) + (u : Lp U ∞ muPlus) (ε : ℝ) (hε : 0 < ε) : + ∃ η > 0, ∀ r, 0 ≤ r → r < η → ∀ v : Lp U ∞ muPlus, ‖v‖ ≤ ‖u‖ → ‖S.Φ r v‖ < ε := by + -- `κ(r) = ‖Φ r‖ < ε / (‖u‖ + 1)` for `r ∈ [0, η)` + have hz : Tendsto (fun t => ‖S.Φ t‖) (𝓝[≥] 0) (𝓝 0) := S.zero_class + obtain ⟨η, hη, hκ⟩ := Metric.tendsto_nhdsWithin_nhds.1 hz (ε / (‖u‖ + 1)) (by positivity) + refine ⟨η, hη, fun r hr hrη v hv => ?_⟩ + have h1 := hκ (Set.mem_Ici.2 hr) + (by rw [Real.dist_eq, sub_zero, abs_of_nonneg hr]; exact hrη) + have h2 : ‖S.Φ r‖ < ε / (‖u‖ + 1) := by simpa using h1 + have h3 : ‖S.Φ r‖ * (‖u‖ + 1) < ε := (lt_div_iff₀ (by positivity)).1 h2 + -- `‖Φ r v‖ ≤ κ(r) ‖v‖` + calc ‖S.Φ r v‖ ≤ ‖S.Φ r‖ * ‖v‖ := ContinuousLinearMap.le_opNorm _ _ + _ ≤ ‖S.Φ r‖ * (‖u‖ + 1) := mul_le_mul_of_nonneg_left (by linarith) (norm_nonneg _) + _ < ε := h3 + +/-- **Corollary 1.6** (`cor:p-infty-solution-continuous`). Let `X`, `U` be real or complex +Banach spaces and `S = (𝕋, Φ)` an abstract linear control system with `p = ∞`. For every +input `u ∈ L^∞(ℝ₊; U)`, the map `t ↦ Φ t u` is continuous on `ℝ₊ = [0, ∞)`. -/ +theorem continuousOn_Phi [CompleteSpace X] (S : ALCS 𝕜 X U ∞) + (u : Lp U ∞ muPlus) : + ContinuousOn (fun t => S.Φ t u) (Set.Ici 0) := by + rw [Metric.continuousOn_iff] + intro t₀ ht₀ ε hε + rw [Set.mem_Ici] at ht₀ + rcases ht₀.eq_or_lt with h0 | hpos + · -- continuity at `t₀ = 0`: `‖Φ t u‖ ≤ κ(t) ‖u‖ → 0` + subst h0 + obtain ⟨η, hη, hsmall⟩ := S.small_Phi u ε hε + refine ⟨η, hη, fun t ht hdist => ?_⟩ + rw [Set.mem_Ici] at ht + rw [Real.dist_eq, sub_zero, abs_of_nonneg ht] at hdist + show dist (S.Φ t u) (S.Φ 0 u) < ε + rw [S.Phi_zero, zero_apply, dist_zero_right] + exact hsmall t ht hdist u le_rfl + · -- continuity at `t₀ > 0` + -- `‖Φ r v‖ < ε / 4` for `r ∈ [0, η)` and `‖v‖ ≤ ‖u‖` + obtain ⟨η, hη, hsmall⟩ := S.small_Phi u (ε / 4) (by positivity) + -- `0 < δ < t₀` and `2 δ < η` + obtain ⟨δ, hδpos, hδt, hδη⟩ : ∃ δ : ℝ, 0 < δ ∧ δ ≤ t₀ / 2 ∧ δ ≤ η / 3 := + ⟨min (t₀ / 2) (η / 3), lt_min (by linarith) (by linarith), min_le_left _ _, + min_le_right _ _⟩ + -- `t₁ := t₀ - δ`, `u₁ := u (t₁ + ·)` and `y := Φ t₁ u` + have ht₁ : 0 ≤ t₀ - δ := by linarith + obtain ⟨u₁, hu₁, hcat⟩ := exists_shift (t₀ - δ) ht₁ u + obtain ⟨y, hy⟩ : ∃ y : X, y = S.Φ (t₀ - δ) u := ⟨_, rfl⟩ + -- composition: `Φ (t₁ + r) u = T r y + Φ r u₁` + have hcomp : ∀ r, 0 ≤ r → S.Φ (t₀ - δ + r) u = S.T r y + S.Φ r u₁ := by + intro r hr + rw [hy] + exact S.composition (t₀ - δ) r ht₁ hr u u₁ u hcat + -- in particular `Φ t₀ u = T δ y + Φ δ u₁` + have e₀ : S.Φ t₀ u = S.T δ y + S.Φ δ u₁ := by + have h := hcomp δ hδpos.le + rwa [sub_add_cancel] at h + -- continuity of `s ↦ T s y` at `s = δ` + obtain ⟨δ', hδ', horbit⟩ := Metric.continuousOn_iff.1 + (S.toC0Semigroup.continuousOn_orbit y) δ (Set.mem_Ici.2 hδpos.le) (ε / 2) (by positivity) + refine ⟨min δ δ', lt_min hδpos hδ', fun t _ hdist => ?_⟩ + -- write `t = t₁ + r`, with `|r - δ| = |t - t₀|` + obtain ⟨r, rfl⟩ : ∃ r, t = t₀ - δ + r := ⟨t - (t₀ - δ), by ring⟩ + rw [Real.dist_eq, show t₀ - δ + r - t₀ = r - δ by ring] at hdist + have hd1 : |r - δ| < δ := lt_of_lt_of_le hdist (min_le_left _ _) + have hd2 : |r - δ| < δ' := lt_of_lt_of_le hdist (min_le_right _ _) + obtain ⟨hr1, hr2⟩ := abs_lt.1 hd1 + have hr : 0 ≤ r := by linarith + -- the three terms + have h1 : ‖S.T r y - S.T δ y‖ < ε / 2 := by + have h := horbit r (Set.mem_Ici.2 hr) (by rw [Real.dist_eq]; exact hd2) + rwa [dist_eq_norm] at h + have h2 : ‖S.Φ r u₁‖ < ε / 4 := hsmall r hr (by linarith) u₁ hu₁ + have h3 : ‖S.Φ δ u₁‖ < ε / 4 := hsmall δ hδpos.le (by linarith) u₁ hu₁ + -- conclusion + change dist (S.Φ (t₀ - δ + r) u) (S.Φ t₀ u) < ε + rw [dist_eq_norm, hcomp r hr, e₀] + have h4 := norm_three_terms_le (S.T r y) (S.Φ r u₁) (S.T δ y) (S.Φ δ u₁) + linarith + +end ALCS + +end + +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Definitions.lean b/LeanPool/AbstractLinearControl/Definitions.lean new file mode 100644 index 0000000000..aa4e8064cb --- /dev/null +++ b/LeanPool/AbstractLinearControl/Definitions.lean @@ -0,0 +1,128 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Background.Semigroup +public import LeanPool.AbstractLinearControl.Background.Lp + + +/-! +# Abstract linear control systems (Section 1 and § 2.1 of the paper) + +* `ALCS 𝕜 X U p` : **Definition 1.1**, an abstract linear control system `(𝕋, Φ)`. +* `ALCS.IsZeroClass` : **Definition 1.4**, zero-class systems. +* `ALCS.Phi_zero` : `Φ_0 = 0` (§ 1.2). +* `ALCS.norm_Phi_mono` : equation `eq:Phi-monotone`, `κ(t) ≤ κ(t + τ)`, + where `κ(t) = ‖Φ t‖`. +* `ALCS.causality`, `ALCS.delay`, `ALCS.free` : **Lemma 2.1** (`lem:Phi-properties`), + equations `eq:causality`, `eq:delay`, `eq:free`. + +## Formalization choices + +* Scalars: any nontrivially normed field `𝕜` here; the main theorem uses `ℝ` or `ℂ` + (`RCLike 𝕜`). Completeness of `X` and `U` is assumed only where it is used. +* `L^p(ℝ₊; U)` is `Lp U p muPlus` (see `ALCS/Background/Lp.lean`). +* Like the semigroup `T`, the input maps form a function `Φ : ℝ → (L^p →L X)`; + only nonnegative times play a role in the axioms and in the results. +* Instead of constructing `u ⋄_τ v` as an element of `L^p`, the composition property + is required for every `w ∈ L^p` whose representative is a.e. equal to + `concat τ ⇑u ⇑v`. Since `u ⋄_τ v` does belong to `L^p` and a.e. classes are unique, + this is exactly the identity of the paper. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open MeasureTheory Filter Topology +open scoped ENNReal + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] +variable {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] +variable {U : Type*} [NormedAddCommGroup U] [NormedSpace 𝕜 U] + +/-- **Definition 1.1** (abstract linear control system). +An abstract linear control system with state space `X`, input space `U` and exponent +`p ∈ [1, ∞]` is a strongly continuous semigroup `T` on `X` (the parent structure +`C0Semigroup`) together with bounded linear input maps `Φ t : L^p(ℝ₊; U) → X` +satisfying the composition property `eq:composition`. -/ +structure ALCS (𝕜 : Type*) (X : Type*) (U : Type*) [NontriviallyNormedField 𝕜] + [NormedAddCommGroup X] [NormedSpace 𝕜 X] + [NormedAddCommGroup U] [NormedSpace 𝕜 U] + (p : ℝ≥0∞) [Fact (1 ≤ p)] extends C0Semigroup 𝕜 X where + /-- the input maps `Φ t : L^p(ℝ₊; U) → X` -/ + Φ : ℝ → Lp U p muPlus →L[𝕜] X + /-- composition property `eq:composition`: `Φ (τ + t) (u ⋄_τ v) = T t (Φ τ u) + Φ t v`, + where `w` is any input representing `u ⋄_τ v` -/ + composition : ∀ τ t : ℝ, 0 ≤ τ → 0 ≤ t → ∀ u v w : Lp U p muPlus, + (⇑w =ᵐ[muPlus] concat τ ⇑u ⇑v) → Φ (τ + t) w = T t (Φ τ u) + Φ t v + +namespace ALCS + +variable {p : ℝ≥0∞} [Fact (1 ≤ p)] (S : ALCS 𝕜 X U p) + +/-- **Definition 1.4** (zero-class system): `κ(t) = ‖Φ t‖ → 0` as `t → 0⁺` +(equation `eq:kappa-0`). -/ +def IsZeroClass : Prop := + Tendsto (fun t => ‖S.Φ t‖) (𝓝[≥] 0) (𝓝 0) + +/-! ## Elementary consequences of the composition property (§ 1.2 and Lemma 2.1) -/ + +/-- `Φ 0 = 0` (§ 1.2): composition with `τ = t = 0` and `u = v`, since `u ⋄_0 u = u`. -/ +theorem Phi_zero : S.Φ 0 = 0 := by + refine ContinuousLinearMap.ext (fun u => ?_) + -- `u ⋄_0 u = u` everywhere + have hw : ⇑u =ᵐ[muPlus] concat 0 ⇑u ⇑u := + Filter.Eventually.of_forall (fun s => by simp [concat]) + -- `Φ 0 u = T 0 (Φ 0 u) + Φ 0 u = Φ 0 u + Φ 0 u` + have h := S.composition 0 0 le_rfl le_rfl u u u hw + simpa [S.T_zero] using h + +/-- **Lemma 2.1** (`lem:Phi-properties`), causality `eq:causality`: +`Φ τ (u ⋄_τ v) = Φ τ u`, i.e. `Φ τ u` only depends on the restriction of `u` to `[0, τ)`. +(Composition with `t = 0`.) -/ +theorem causality (τ : ℝ) (hτ : 0 ≤ τ) (u v w : Lp U p muPlus) + (hw : ⇑w =ᵐ[muPlus] concat τ ⇑u ⇑v) : + S.Φ τ w = S.Φ τ u := by + have h := S.composition τ 0 hτ le_rfl u v w hw + simpa [S.T_zero, S.Phi_zero] using h + +/-- **Lemma 2.1** (`lem:Phi-properties`), delay `eq:delay`: +`Φ (s + t) (0 ⋄_s v) = Φ t v`, i.e. an initial period of zero input has no effect. +(Composition with `u = 0`.) -/ +theorem delay (s t : ℝ) (hs : 0 ≤ s) (ht : 0 ≤ t) (v w : Lp U p muPlus) + (hw : ⇑w =ᵐ[muPlus] concat s ⇑(0 : Lp U p muPlus) ⇑v) : + S.Φ (s + t) w = S.Φ t v := by + have h := S.composition s t hs ht 0 v w hw + simpa using h + +/-- **Lemma 2.1** (`lem:Phi-properties`), free evolution `eq:free`: +`Φ (τ + t) (u ⋄_τ 0) = T t (Φ τ u)`, i.e. once the input is switched off, the state evolves +freely. (Composition with `v = 0`.) -/ +theorem free (τ t : ℝ) (hτ : 0 ≤ τ) (ht : 0 ≤ t) (u w : Lp U p muPlus) + (hw : ⇑w =ᵐ[muPlus] concat τ ⇑u ⇑(0 : Lp U p muPlus)) : + S.Φ (τ + t) w = S.T t (S.Φ τ u) := by + have h := S.composition τ t hτ ht u 0 w hw + simpa using h + +/-- Monotonicity of `κ(t) = ‖Φ t‖`, equation `eq:Phi-monotone`: +`‖Φ s‖ ≤ ‖Φ t‖` for `0 ≤ s ≤ t`. Indeed `Φ s u = Φ t (0 ⋄_{t-s} u)` by `delay`. -/ +theorem norm_Phi_mono {s t : ℝ} (hs : 0 ≤ s) (hst : s ≤ t) : ‖S.Φ s‖ ≤ ‖S.Φ t‖ := by + apply ContinuousLinearMap.opNorm_le_bound _ (norm_nonneg _) + intro u + obtain ⟨w, hw, hcat⟩ := exists_delay (t - s) u + have heq := S.delay (t - s) s (sub_nonneg.2 hst) hs u w hcat + rw [sub_add_cancel] at heq + calc + ‖S.Φ s u‖ = ‖S.Φ t w‖ := congrArg norm heq.symm + _ ≤ ‖S.Φ t‖ * ‖w‖ := (S.Φ t).le_opNorm w + _ ≤ ‖S.Φ t‖ * ‖u‖ := mul_le_mul_of_nonneg_left hw (norm_nonneg _) + +end ALCS + +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Examples/ExoticMean.lean b/LeanPool/AbstractLinearControl/Examples/ExoticMean.lean new file mode 100644 index 0000000000..380bfe90cc --- /dev/null +++ b/LeanPool/AbstractLinearControl/Examples/ExoticMean.lean @@ -0,0 +1,443 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Background.InvariantHahnBanach +public import LeanPool.AbstractLinearControl.Background.Linfty +public import Mathlib.MeasureTheory.Integral.IntervalIntegral.Periodic +public import Mathlib.Topology.Separation.CompletelyRegular + + +/-! +# An exotic invariant mean on periodic `L^∞` functions (Lemma 3.2) + +**Lemma 3.2** (`lem:exotic-mean`). Let `L^∞_per` be the space of `1`-periodic elements of +`L^∞(ℝ; ℝ)`. There exists a linear map `m : L^∞_per → ℝ` such that +* (a) `m(f) ≥ 0` whenever `f ≥ 0` almost everywhere, and `m(1) = 1`; +* (b) `m(f(· - a)) = m(f)` for all `f ∈ L^∞_per` and `a ∈ ℝ`; +* (c) `m(f) ≠ ∫_0^1 f(s) ds` for some `f ∈ L^∞_per`. + +The paper quotes this classical fact from the literature; here it is proved. The final +statement is `ExoticMean.exotic_mean`. + +## Proof + +Let `V ⊆ L^∞_per` be the subspace of functions vanishing a.e. on some open dense set. +The constants are at distance `|c|` from `V` (`constant_separation`). A Hahn–Banach +argument combined with finite Cesàro averages of translations +(`ALCS/Background/InvariantHahnBanach.lean`) gives a translation-invariant functional `m` +of norm `≤ 1` with `m(1) = 1` and `m = 0` on `V` (`exists_strong_mean`); positivity +follows from `‖m‖ ≤ 1` and `m(1) = 1`. For (c), take the indicator of a periodic open +dense set of small measure (`exists_small_periodic_open`): its mean is `1` while its +integral over a period is `< 1/2`. + +## Formalization choices + +* `L^∞_per` (`LinftyPer`) is the subspace of `L^∞(ℝ)` fixed by the translation by `1`; + translations act on a.e. classes (`shift`, `translate`). +* Positivity (`Positive`) is an a.e. property of the class, not of a representative. +* `exists_strong_mean` proves more than needed (vanishing on `V`); this extra property is + used in Proposition 3.3 and does not appear in the statement of `exotic_mean`. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +noncomputable section +open Set Filter MeasureTheory +open scoped ENNReal NNReal Topology + +namespace ExoticMean + +local instance : Fact (1 ≤ (∞ : ℝ≥0∞)) := ⟨le_top⟩ + +/-! ## Generic `L^∞` helpers (also used in Proposition 3.3) -/ + +lemma linfty_norm_le {α : Type*} [MeasurableSpace α] {μ : Measure α} + (f : Lp ℝ ∞ μ) {C : ℝ} (hC : 0 ≤ C) + (hf : ∀ᵐ x ∂μ, ‖f x‖ ≤ C) : ‖f‖ ≤ C := + ALCS.lp_norm_le hC hf + +lemma linfty_ae_norm_le {α : Type*} [MeasurableSpace α] {μ : Measure α} + (f : Lp ℝ ∞ μ) : ∀ᵐ x ∂μ, ‖f x‖ ≤ ‖f‖ := + ALCS.ae_norm_le f + +/-- A constant is in L∞ even if the underlying measure has infinite mass. -/ +def linftyConst {α : Type*} [MeasurableSpace α] (μ : Measure α) (c : ℝ) : + Lp ℝ ∞ μ := + (memLp_top_of_bound stronglyMeasurable_const.aestronglyMeasurable ‖c‖ + (Eventually.of_forall (fun _ => le_rfl))).toLp (fun _ => c) + +lemma linftyConst_ae {α : Type*} [MeasurableSpace α] (μ : Measure α) (c : ℝ) : + ⇑(linftyConst μ c) =ᵐ[μ] fun _ => c := + MemLp.coeFn_toLp _ + +/-- A measurable indicator, as an actual L∞ equivalence class. -/ +def linftyIndicator {α : Type*} [MeasurableSpace α] (μ : Measure α) + (s : Set α) (hs : MeasurableSet s) : Lp ℝ ∞ μ := + (memLp_top_of_bound + (stronglyMeasurable_const.indicator hs).aestronglyMeasurable 1 + (Eventually.of_forall (fun x => by + by_cases hx : x ∈ s <;> simp [Set.indicator, hx]))).toLp + (s.indicator (fun _ => (1 : ℝ))) + +lemma linftyIndicator_ae {α : Type*} [MeasurableSpace α] (μ : Measure α) + (s : Set α) (hs : MeasurableSet s) : + ⇑(linftyIndicator μ s hs) =ᵐ[μ] s.indicator (fun _ => (1 : ℝ)) := + MemLp.coeFn_toLp _ + +/-! ## Translations and periodic functions -/ + +/-- `L^∞(ℝ)`. -/ +abbrev Ambient := Lp ℝ ∞ (volume : Measure ℝ) + +/-- `shift a f` is the a.e. class of `r ↦ f (r-a)`. -/ +def shift (a : ℝ) : Ambient →ₗ[ℝ] Ambient := + Lp.compMeasurePreservingₗ ℝ (fun r : ℝ => -a + r) + (measurePreserving_add_left (volume : Measure ℝ) (-a)) + +lemma shift_ae (a : ℝ) (f : Ambient) : + ⇑(shift a f) =ᵐ[volume] fun r => f (-a + r) := + Lp.coeFn_compMeasurePreserving f + (measurePreserving_add_left (volume : Measure ℝ) (-a)) + +lemma shift_zero (f : Ambient) : shift 0 f = f := by + apply Lp.ext + filter_upwards [shift_ae 0 f] with r hr + simpa using hr + +lemma shift_add (a b : ℝ) (f : Ambient) : + shift (a + b) f = shift a (shift b f) := by + apply Lp.ext + have hab := (measurePreserving_add_left (volume : Measure ℝ) (-a)).quasiMeasurePreserving.ae + (shift_ae b f) + filter_upwards [shift_ae (a + b) f, shift_ae a (shift b f), hab] with r h1 h2 h3 + rw [h1, h2, h3] + congr 1 + ring + +lemma shift_commute (a b : ℝ) (f : Ambient) : + shift a (shift b f) = shift b (shift a f) := by + rw [← shift_add, ← shift_add, add_comm a b] + +lemma norm_shift (a : ℝ) (f : Ambient) : ‖shift a f‖ = ‖f‖ := + Lp.norm_compMeasurePreserving f + (measurePreserving_add_left (volume : Measure ℝ) (-a)) + +/-- `L^∞_per`: the subspace of `L^∞(ℝ)` fixed by the translation by `1`, i.e. the a.e. +`1`-periodic functions. (This avoids choosing periodic representatives.) -/ +def periodicSubspace : Submodule ℝ Ambient where + carrier := {f | shift 1 f = f} + zero_mem' := by simp + add_mem' := by + intro f g hf hg + change shift 1 (f + g) = f + g + rw [map_add, hf, hg] + smul_mem' := by + intro c f hf + change shift 1 (c • f) = c • f + rw [map_smul, hf] + +/-- Almost-everywhere periodic bounded functions, with their inherited norm. -/ +abbrev LinftyPer := periodicSubspace + +/-- The real-translation action on the periodic subspace. -/ +def translate (a : ℝ) : LinftyPer →ₗ[ℝ] LinftyPer where + toFun f := ⟨shift a f.val, by + change shift 1 (shift a f.val) = shift a f.val + rw [shift_commute, f.property]⟩ + map_add' := by intros; apply Subtype.ext; apply map_add + map_smul' := by intros; apply Subtype.ext; apply map_smul + +lemma translate_ae (a : ℝ) (f : LinftyPer) : + ⇑((translate a f).val) =ᵐ[volume] fun r => f.val (r - a) := by + simpa [translate, sub_eq_add_neg, add_comm] using shift_ae a f.val + +lemma translate_zero (f : LinftyPer) : translate 0 f = f := + Subtype.ext (shift_zero f.val) + +lemma translate_add (a b : ℝ) (f : LinftyPer) : + translate (a + b) f = translate a (translate b f) := + Subtype.ext (shift_add a b f.val) + +lemma norm_translate (a : ℝ) (f : LinftyPer) : ‖translate a f‖ = ‖f‖ := + norm_shift a f.val + +lemma shift_const (a c : ℝ) : shift a (linftyConst volume c) = linftyConst volume c := by + apply Lp.ext + have hc := (measurePreserving_add_left (volume : Measure ℝ) (-a)).quasiMeasurePreserving.ae + (linftyConst_ae volume c) + filter_upwards [shift_ae a (linftyConst volume c), linftyConst_ae volume c, hc] + with r hr h1 h2 + exact hr.trans (h2.trans h1.symm) + +/-- The periodic class of the constant one function. -/ +def one : LinftyPer := ⟨linftyConst volume 1, shift_const 1 1⟩ + +lemma one_ae : ⇑one.val =ᵐ[volume] fun _ => (1 : ℝ) := linftyConst_ae volume 1 + +lemma translate_one (a : ℝ) : translate a one = one := + Subtype.ext (shift_const a 1) + +/-- The ordinary Lebesgue integral over `[0,1]`. +`Ioc` is the usual set-integral implementation of the interval integral; +changing either endpoint does not change an integral for Lebesgue measure. -/ +def integral01 (f : LinftyPer) : ℝ := ∫ r in Ioc (0 : ℝ) 1, f.val r + +/-- Positivity is explicitly an a.e. property, not pointwise positivity of +Mathlib's arbitrarily chosen `Lp` representative. -/ +def Positive (m : LinftyPer →ₗ[ℝ] ℝ) : Prop := + ∀ f, (∀ᵐ r ∂volume, 0 ≤ f.val r) → 0 ≤ m f + +/-! ## The open-dense vanishing subspace -/ + +private lemma dense_inter_open {s t : Set ℝ} + (hs : IsOpen s) (hds : Dense s) (hdt : Dense t) : Dense (s ∩ t) := by + rw [dense_iff_inter_open] + intro U hU hUne + obtain ⟨x, hx⟩ := hdt.inter_open_nonempty (U ∩ s) (hU.inter hs) + (hds.inter_open_nonempty U hU hUne) + exact ⟨x, hx.1.1, hx.1.2, hx.2⟩ + +/-- The subspace `V` of periodic functions vanishing a.e. on some open dense set. -/ +def vanishingOnDenseOpen : Submodule ℝ LinftyPer where + carrier := {f | ∃ O : Set ℝ, IsOpen O ∧ Dense O ∧ + ∀ᵐ r ∂volume, r ∈ O → f.val r = 0} + zero_mem' := by + refine ⟨univ, isOpen_univ, dense_univ, ?_⟩ + filter_upwards [Lp.coeFn_zero ℝ ∞ (volume : Measure ℝ)] with r hr + intro _ + exact hr + add_mem' := by + rintro f g ⟨O, hOo, hOd, hf⟩ ⟨P, hPo, hPd, hg⟩ + refine ⟨O ∩ P, hOo.inter hPo, dense_inter_open hOo hOd hPd, ?_⟩ + filter_upwards [hf, hg, Lp.coeFn_add f.val g.val] with r hfr hgr hsum + intro hr + change (f.val + g.val) r = 0 + simpa [hfr hr.1, hgr hr.2] using hsum + smul_mem' := by + rintro c f ⟨O, hOo, hOd, hf⟩ + refine ⟨O, hOo, hOd, ?_⟩ + filter_upwards [hf, Lp.coeFn_smul c f.val] with r hfr hsmul + intro hr + change (c • f.val) r = 0 + simpa [hfr hr] using hsmul + +lemma translate_mem_vanishing (a : ℝ) (f : LinftyPer) + (hf : f ∈ vanishingOnDenseOpen) : translate a f ∈ vanishingOnDenseOpen := by + obtain ⟨O, hOo, hOd, hf⟩ := hf + let P : Set ℝ := (fun r : ℝ => -a + r) ⁻¹' O + have hPo : IsOpen P := hOo.preimage (continuous_const.add continuous_id) + have hPd : Dense P := by + rw [dense_iff_inter_open] + intro U hU hUne + have himage : IsOpen ((fun r : ℝ => -a + r) '' U) := + isOpenMap_add_left (-a) U hU + obtain ⟨y, hy⟩ := hOd.inter_open_nonempty _ himage (hUne.image _) + obtain ⟨r, hrU, rfl⟩ := hy.1 + exact ⟨r, hrU, hy.2⟩ + refine ⟨P, hPo, hPd, ?_⟩ + have hshift := (measurePreserving_add_left (volume : Measure ℝ) (-a)).quasiMeasurePreserving.ae hf + filter_upwards [shift_ae a f.val, hshift] with r hr hfr + intro hrP + exact hr.trans (hfr hrP) + +lemma constant_separation (c : ℝ) (v : LinftyPer) + (hv : v ∈ vanishingOnDenseOpen) : |c| ≤ ‖c • one + v‖ := by + obtain ⟨O, hOo, hOd, hv⟩ := hv + have hgood : ∀ᵐ r ∂volume, r ∈ O → |c| ≤ ‖c • one + v‖ := by + filter_upwards [hv, one_ae, Lp.coeFn_smul c one.val, + Lp.coeFn_add (c • one.val) v.val, + linfty_ae_norm_le ((c • one + v).val)] with r hvr h1 hc hsum hbound + intro hrO + have heq : (c • one + v).val r = c := by + change (c • one.val + v.val) r = c + simp only [Pi.add_apply] at hsum + simp only [Pi.smul_apply] at hc + rw [hsum, hc, h1, hvr hrO] + simp + change |c| ≤ ‖(c • one + v).val‖ + simpa only [heq, Real.norm_eq_abs] using hbound + obtain ⟨r, hr⟩ := (Measure.dense_of_ae hgood).inter_open_nonempty O hOo hOd.nonempty + exact hr.2 hr.1 + +/-- Positivity follows from normalization and the norm bound, with the +unscaled argument `‖f‖ 1 - f`; this also handles `f = 0`. -/ +lemma positive_of_norm_le_one (m : LinftyPer →L[ℝ] ℝ) + (hm : ‖m‖ ≤ 1) (h1 : m one = 1) : Positive m.toLinearMap := by + intro f hf + have hnorm : ‖‖f‖ • one - f‖ ≤ ‖f‖ := by + apply linfty_norm_le (‖f‖ • one - f).val (norm_nonneg f) + filter_upwards [hf, linfty_ae_norm_le f.val, one_ae, + Lp.coeFn_smul ‖f‖ one.val, + Lp.coeFn_sub (‖f‖ • one.val) f.val] with r hfr hbr h1r hsmul hsub + change ‖(‖f‖ • one.val - f.val) r‖ ≤ ‖f‖ + simp only [Pi.sub_apply] at hsub + simp only [Pi.smul_apply] at hsmul + rw [hsub, hsmul, h1r] + simp only [smul_eq_mul, mul_one, Real.norm_eq_abs] + change |f.val r| ≤ ‖f‖ at hbr + exact abs_le.mpr ⟨by linarith [(abs_le.mp hbr).2], by linarith⟩ + have hmap : m (‖f‖ • one - f) = ‖f‖ - m f := by + rw [map_sub, map_smul, h1] + simp + have hbound : ‖m (‖f‖ • one - f)‖ ≤ ‖f‖ := + (m.le_opNorm _).trans ((mul_le_mul_of_nonneg_right hm (norm_nonneg _)).trans + (by simpa using hnorm)) + rw [hmap, Real.norm_eq_abs] at hbound + have h := (abs_le.mp hbound).2 + change 0 ≤ m f + linarith + +/-- The invariant mean, with the extra property that it vanishes on functions vanishing +a.e. on an open dense set (used in Proposition 3.3). -/ +theorem exists_strong_mean : + ∃ m : LinftyPer →L[ℝ] ℝ, + ‖m‖ ≤ 1 ∧ Positive m.toLinearMap ∧ m one = 1 ∧ + (∀ a f, m (translate a f) = m f) ∧ + ∀ v ∈ vanishingOnDenseOpen, m v = 0 := by + let R : HahnBanach.Action LinftyPer := + { T := translate + zero_apply := translate_zero + add_apply := translate_add + bound := fun a f => (norm_translate a f).le } + obtain ⟨m, hm, h1, hV, hT⟩ := + HahnBanach.exists_invariant_extension R one vanishingOnDenseOpen + translate_one translate_mem_vanishing constant_separation + exact ⟨m, hm, positive_of_norm_le_one m hm h1, h1, hT, hV⟩ + +/-! ## Small periodic open dense sets -/ + +/-- A Borel set with the exact period needed for the indicator class. -/ +structure PeriodicSet where + /-- The measurable periodic subset of the real line. -/ + carrier : Set ℝ + measurable : MeasurableSet carrier + period : ∀ r : ℝ, -1 + r ∈ carrier ↔ r ∈ carrier + +namespace PeriodicSet + +/-- The periodic indicator as an almost-everywhere bounded-function class. -/ +def indicator (O : PeriodicSet) : LinftyPer := + ⟨linftyIndicator volume O.carrier O.measurable, by + apply Lp.ext + have hs := (measurePreserving_add_left (volume : Measure ℝ) (-1)).quasiMeasurePreserving.ae + (linftyIndicator_ae volume O.carrier O.measurable) + filter_upwards [shift_ae 1 (linftyIndicator volume O.carrier O.measurable), + linftyIndicator_ae volume O.carrier O.measurable, hs] with r h1 h2 h3 + rw [h1, h2, h3] + by_cases hr : r ∈ O.carrier + · simp [Set.indicator, hr, (O.period r).mpr hr] + · have hr' : -1 + r ∉ O.carrier := fun h => hr ((O.period r).mp h) + simp [Set.indicator, hr, hr']⟩ + +lemma indicator_ae (O : PeriodicSet) : + ⇑O.indicator.val =ᵐ[volume] O.carrier.indicator (fun _ => (1 : ℝ)) := + linftyIndicator_ae volume O.carrier O.measurable + +lemma mean_indicator (m : LinftyPer →L[ℝ] ℝ) (h1 : m one = 1) + (hV : ∀ v ∈ vanishingOnDenseOpen, m v = 0) + (O : PeriodicSet) (hOo : IsOpen O.carrier) (hOd : Dense O.carrier) : + m O.indicator = 1 := by + have hv : one - O.indicator ∈ vanishingOnDenseOpen := by + refine ⟨O.carrier, hOo, hOd, ?_⟩ + filter_upwards [one_ae, O.indicator_ae, + Lp.coeFn_sub one.val O.indicator.val] with r h1r hOr hsub + intro hr + change (one.val - O.indicator.val) r = 0 + simp only [Pi.sub_apply] at hsub + rw [hsub, h1r, hOr] + simp [hr] + have h := hV (one - O.indicator) hv + rw [map_sub, h1] at h + linarith + +lemma integral_indicator (O : PeriodicSet) : + integral01 O.indicator = (volume (O.carrier ∩ Ioc (0 : ℝ) 1)).toReal := by + unfold integral01 + rw [integral_congr_ae (ae_restrict_of_ae O.indicator_ae)] + rw [MeasureTheory.integral_indicator O.measurable] + simp [Measure.real, Measure.restrict_apply, O.measurable] + +end PeriodicSet + +/-- A general topological observation: the inverse image of a dense set +under an open map is dense. Surjectivity is not needed for this assertion. -/ +private lemma dense_preimage_of_open {α β : Type*} + [TopologicalSpace α] [TopologicalSpace β] + {q : α → β} (hq : IsOpenMap q) {s : Set β} (hs : Dense s) : + Dense (q ⁻¹' s) := by + rw [dense_iff_inter_open] + intro U hU hUne + obtain ⟨y, hy⟩ := hs.inter_open_nonempty (q '' U) (hq U hU) (hUne.image q) + obtain ⟨x, hx, rfl⟩ := hy.1 + exact ⟨x, hx, hy.2⟩ + +/-- Outer regularity around a countable dense null set gives a small open +dense set on the circle; pulling it back makes it genuinely periodic. -/ +theorem exists_small_periodic_open (ε : ℝ) (hε : 0 < ε) : + ∃ O : PeriodicSet, IsOpen O.carrier ∧ Dense O.carrier ∧ + (volume (O.carrier ∩ Ioc (0 : ℝ) 1)).toReal < ε := by + let _ : Fact (0 < (1 : ℝ)) := ⟨by norm_num⟩ + let _ : NullSingletonClass (volume : Measure (AddCircle (1 : ℝ))) := + ⟨fun x => by rw [← Metric.closedBall_zero, AddCircle.volume_closedBall]; simp⟩ + obtain ⟨D, hDc, hDd⟩ := TopologicalSpace.exists_countable_dense (AddCircle (1 : ℝ)) + have hD0 : (volume : Measure (AddCircle (1 : ℝ))) D = 0 := hDc.measure_zero _ + obtain ⟨U, hDU, hUo, hUμ⟩ := + D.exists_isOpen_lt_of_lt (μ := (volume : Measure (AddCircle (1 : ℝ)))) + (ENNReal.ofReal ε) (by rw [hD0]; exact ENNReal.ofReal_pos.mpr hε) + have hUd : Dense U := Dense.mono hDU hDd + let q : ℝ → AddCircle (1 : ℝ) := fun r => (r : AddCircle (1 : ℝ)) + have hq : Continuous q := AddCircle.continuous_mk' 1 + have hqo : IsOpenMap q := QuotientAddGroup.isOpenMap_coe + let O : PeriodicSet := + { carrier := q ⁻¹' U + measurable := (hUo.preimage hq).measurableSet + period := by + intro r + have heq : q (-1 + r) = q r := by + change ((-1 + r : ℝ) : AddCircle (1 : ℝ)) = (r : AddCircle (1 : ℝ)) + rw [AddCircle.coe_add, AddCircle.coe_neg, AddCircle.coe_period] + simp + change q (-1 + r) ∈ U ↔ q r ∈ U + rw [heq] } + refine ⟨O, hUo.preimage hq, dense_preimage_of_open hqo hUd, ?_⟩ + have hμ : volume (O.carrier ∩ Ioc (0 : ℝ) 1) = + (volume : Measure (AddCircle (1 : ℝ))) U := by + simpa [O, q] using (AddCircle.add_projection_respects_measure 1 0 + hUo.measurableSet).symm + rw [hμ] + have hfin : (volume : Measure (AddCircle (1 : ℝ))) U ≠ ∞ := + ne_top_of_lt (hUμ.trans ENNReal.ofReal_lt_top) + have h := (ENNReal.toReal_lt_toReal hfin ENNReal.ofReal_ne_top).mpr hUμ + simpa [ENNReal.toReal_ofReal hε.le] using h + +/-! ## Lemma 3.2 -/ + +/-- **Lemma 3.2** (`lem:exotic-mean`). There is a linear map `m : L^∞_per → ℝ` which is +(a) positive and normalized, (b) invariant under every real translation, and +(c) different from the Lebesgue integral over a period. -/ +theorem exotic_mean : + ∃ m : LinftyPer →ₗ[ℝ] ℝ, + (Positive m ∧ m one = 1) ∧ + (∀ (f : LinftyPer) (a : ℝ), m (translate a f) = m f) ∧ + ∃ f : LinftyPer, m f ≠ integral01 f := by + obtain ⟨m, hm, hpos, h1, hT, hV⟩ := exists_strong_mean + obtain ⟨O, hOo, hOd, hOμ⟩ := exists_small_periodic_open (1 / 2) (by norm_num) + refine ⟨m.toLinearMap, ⟨hpos, h1⟩, fun f a => hT a f, O.indicator, ?_⟩ + have hmean := O.mean_indicator m h1 hV hOo hOd + have hint := O.integral_indicator + change m O.indicator ≠ integral01 O.indicator + rw [hmean, hint] + linarith + +end ExoticMean + +end +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Examples/FinitePNotZeroClass.lean b/LeanPool/AbstractLinearControl/Examples/FinitePNotZeroClass.lean new file mode 100644 index 0000000000..7f3737a48b --- /dev/null +++ b/LeanPool/AbstractLinearControl/Examples/FinitePNotZeroClass.lean @@ -0,0 +1,501 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Definitions + + +/-! +# For `p < ∞`, not every system is zero-class (Proposition 3.1) + +**Proposition 3.1** (`prop:example-finite-p-not-zero-class`). Let `p ∈ [1, ∞)`. There +exist Banach spaces `X` and `U` and an abstract linear control system `(𝕋, Φ)` such that +`κ(t) = 1` for all `t > 0`. + +As in the paper, `X = L^p(ℝ₊)`, `U = ℝ`, and +* `T t` is the right shift: `(T t f)(s) = f (s - t)` for `s ≥ t` and `0` for `s < t`; +* `Φ t` reverses the input on `[0, t]`: `(Φ t u)(s) = u (t - s)` for `0 < s ≤ t` and `0` + otherwise. (The paper uses `0 ≤ s < t`; this changes a null set only, and makes the + concatenation identity hold pointwise.) + +## Main declarations + +* `ShiftExample.shiftSystem` : the system, an `ALCS ℝ (Lp ℝ p muPlus) ℝ p`. +* `ShiftExample.norm_Phi_eq_one` : `‖Φ t‖ = 1` for all `t > 0`. +* `exists_system_norm_Phi_eq_one` : Proposition 3.1, as an existence statement. +* `ShiftExample.not_zero_class` : the system is not of the zero-class (Definition 1.4). + +## Implementation + +All operators are built in one way (`op`): extend `f` by zero to `ℝ` (`zext`), compose +with a measure-preserving map `φ : ℝ → ℝ`, multiply by the indicator of a set `A`, and +restrict to `ℝ₊`. Then `T t = op (· - t) univ` and `Φ t = op (t - ·) (Ioc 0 t)`. +Strong continuity of the shift reduces to the continuity of translations in `L^p(ℝ)`, +which is `Filter.Tendsto.compMeasurePreservingLp` in Mathlib; it fails for `p = ∞`. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open MeasureTheory Filter Topology +open scoped ENNReal + +noncomputable section + +namespace ShiftExample + +/-! ## Raw functions -/ + +section Raw + +/-- Extension by zero of `f` from `[0, ∞)` to `ℝ`. -/ +def zext (f : ℝ → ℝ) : ℝ → ℝ := ALCS.zeroExt f + +/-- The raw operator: `s ↦ 1_A(s) · (zext f)(φ s)`. -/ +def rawOp (φ : ℝ → ℝ) (A : Set ℝ) (f : ℝ → ℝ) : ℝ → ℝ := A.indicator (zext f ∘ φ) + +lemma zext_of_nonneg (f : ℝ → ℝ) (y : ℝ) (h : 0 ≤ y) : zext f y = f y := + ALCS.zeroExt_of_nonneg f h + +lemma zext_of_neg (f : ℝ → ℝ) (y : ℝ) (h : y < 0) : zext f y = 0 := + ALCS.zeroExt_of_neg f h + +variable {φ : ℝ → ℝ} {A : Set ℝ} + +lemma rawOp_add (f g : ℝ → ℝ) (x : ℝ) : + rawOp φ A (f + g) x = rawOp φ A f x + rawOp φ A g x := by + by_cases hx : x ∈ A + · by_cases hy : φ x ∈ Set.Ici (0 : ℝ) + · simp only [rawOp, zext, ALCS.zeroExt, Function.comp_apply, Set.indicator_of_mem hx, + Set.indicator_of_mem hy, Pi.add_apply] + · simp only [rawOp, zext, ALCS.zeroExt, Function.comp_apply, Set.indicator_of_mem hx, + Set.indicator_of_notMem hy, add_zero] + · simp only [rawOp, Set.indicator_of_notMem hx, add_zero] + +lemma rawOp_smul (c : ℝ) (f : ℝ → ℝ) (x : ℝ) : + rawOp φ A (c • f) x = c • rawOp φ A f x := by + by_cases hx : x ∈ A + · by_cases hy : φ x ∈ Set.Ici (0 : ℝ) + · simp only [rawOp, zext, ALCS.zeroExt, Function.comp_apply, Set.indicator_of_mem hx, + Set.indicator_of_mem hy, Pi.smul_apply] + · simp only [rawOp, zext, ALCS.zeroExt, Function.comp_apply, Set.indicator_of_mem hx, + Set.indicator_of_notMem hy, smul_zero] + · simp only [rawOp, Set.indicator_of_notMem hx, smul_zero] + +/-- `rawOp` only depends on the a.e. class of `f` on `ℝ₊`. -/ +lemma rawOp_congr (hφ : MeasurePreserving φ volume volume) (A : Set ℝ) {f g : ℝ → ℝ} + (h : f =ᵐ[muPlus] g) : rawOp φ A f =ᵐ[muPlus] rawOp φ A g := by + have h1 : ∀ᵐ x ∂volume, x ∈ Set.Ici (0 : ℝ) → f x = g x := + (ae_restrict_iff' measurableSet_Ici).1 h + -- the zero extensions agree a.e. on `ℝ` + have h2 : zext f =ᵐ[volume] zext g := by + filter_upwards [h1] with x hx + by_cases hx0 : x ∈ Set.Ici (0 : ℝ) + · simp only [zext, ALCS.zeroExt, Set.indicator_of_mem hx0, hx hx0] + · simp only [zext, ALCS.zeroExt, Set.indicator_of_notMem hx0] + -- composing with a measure-preserving map keeps a.e. equality + have h3 : zext f ∘ φ =ᵐ[volume] zext g ∘ φ := hφ.quasiMeasurePreserving.ae_eq_comp h2 + have h4 : rawOp φ A f =ᵐ[volume] rawOp φ A g := by + filter_upwards [h3] with x hx + by_cases hxA : x ∈ A + · simp only [rawOp, Set.indicator_of_mem hxA] + exact hx + · simp only [rawOp, Set.indicator_of_notMem hxA] + exact ae_restrict_of_ae h4 + +/-! ### Evaluation of the raw shift and of the raw input map -/ + +/-- Raw shift: `rawOp (· - t) univ f x = zext f (x - t)`. -/ +lemma rawT_apply (f : ℝ → ℝ) (t x : ℝ) : + rawOp (fun y => y - t) Set.univ f x = zext f (x - t) := by + simp only [rawOp, Set.indicator_univ, Function.comp_apply] + +/-- Raw input map, for `0 < y ≤ a`: the value is `f (a - y)`. -/ +lemma rawPhi_of_mem (f : ℝ → ℝ) (a y : ℝ) (h : 0 < y ∧ y ≤ a) : + rawOp (fun z => a - z) (Set.Ioc 0 a) f y = f (a - y) := by + have h1 : y ∈ Set.Ioc 0 a := h + simp only [rawOp, Set.indicator_of_mem h1, Function.comp_apply] + exact zext_of_nonneg f (a - y) (by linarith [h.2]) + +/-- Raw input map, outside `(0, a]`: the value is `0`. -/ +lemma rawPhi_of_not (f : ℝ → ℝ) (a y : ℝ) (h : ¬ (0 < y ∧ y ≤ a)) : + rawOp (fun z => a - z) (Set.Ioc 0 a) f y = 0 := by + have h1 : y ∉ Set.Ioc 0 a := h + simp only [rawOp, Set.indicator_of_notMem h1] + +/-- The raw input map vanishes on `(-∞, 0]`, also after extension by zero. -/ +lemma zext_rawPhi_of_nonpos (f : ℝ → ℝ) (a y : ℝ) (hy : y ≤ 0) : + zext (rawOp (fun z => a - z) (Set.Ioc 0 a) f) y = 0 := by + by_cases h0 : 0 ≤ y + · rw [zext_of_nonneg _ y h0] + exact rawPhi_of_not f a y (fun h => by linarith [h.1]) + · exact zext_of_neg _ y (not_le.1 h0) + +lemma concat_of_lt (u v : ℝ → ℝ) (τ y : ℝ) (h : y < τ) : concat τ u v y = u y := by + simp only [concat, ite_eq_left h] + +lemma concat_of_ge (u v : ℝ → ℝ) (τ y : ℝ) (h : τ ≤ y) : concat τ u v y = v (y - τ) := by + simp only [concat, ite_eq_right (not_lt.2 h)] + +/-- The concatenation identity, pointwise, for raw functions: +`Φ (τ + t) (u ⋄_τ v) = T t (Φ τ u) + Φ t v`. -/ +lemma concat_pointwise (u v : ℝ → ℝ) {τ t : ℝ} (hτ : 0 ≤ τ) (ht : 0 ≤ t) (x : ℝ) : + rawOp (fun y => τ + t - y) (Set.Ioc 0 (τ + t)) (concat τ u v) x = + rawOp (fun y => y - t) Set.univ (rawOp (fun y => τ - y) (Set.Ioc 0 τ) u) x + + rawOp (fun y => t - y) (Set.Ioc 0 t) v x := by + rw [rawT_apply] + by_cases hx0 : 0 < x + · by_cases hxt : x ≤ t + · -- case `0 < x ≤ t`: only `v` contributes + have h1 : x ≤ τ + t := by linarith + have h2 : x - t ≤ 0 := by linarith + have h3 : τ ≤ τ + t - x := by linarith + rw [rawPhi_of_mem _ (τ + t) x ⟨hx0, h1⟩, rawPhi_of_mem v t x ⟨hx0, hxt⟩, + zext_rawPhi_of_nonpos u τ (x - t) h2, zero_add, concat_of_ge u v τ (τ + t - x) h3, + show τ + t - x - τ = t - x by ring] + · by_cases hxτt : x ≤ τ + t + · -- case `t < x ≤ τ + t`: only `u` contributes + have h1 : 0 ≤ x - t := by linarith + have h2 : 0 < x - t := by linarith + have h3 : x - t ≤ τ := by linarith + have h4 : τ + t - x < τ := by linarith + rw [rawPhi_of_mem _ (τ + t) x ⟨hx0, hxτt⟩, rawPhi_of_not v t x (fun h => hxt h.2), + zext_of_nonneg _ (x - t) h1, rawPhi_of_mem u τ (x - t) ⟨h2, h3⟩, add_zero, + concat_of_lt u v τ (τ + t - x) h4, show τ - (x - t) = τ + t - x by ring] + · -- case `x > τ + t`: everything vanishes + have h1 : 0 ≤ x - t := by linarith + have h2 : ¬ (x - t ≤ τ) := by intro h; exact hxτt (by linarith) + rw [rawPhi_of_not _ (τ + t) x (fun h => hxτt h.2), rawPhi_of_not v t x (fun h => hxt h.2), + zext_of_nonneg _ (x - t) h1, rawPhi_of_not u τ (x - t) (fun h => h2 h.2), add_zero] + · -- case `x ≤ 0`: everything vanishes + have h1 : x - t ≤ 0 := by linarith + rw [rawPhi_of_not _ (τ + t) x (fun h => hx0 h.1), rawPhi_of_not v t x (fun h => hx0 h.1), + zext_rawPhi_of_nonpos u τ (x - t) h1, add_zero] + +end Raw + +/-! ## Bounded operators on `L^p(ℝ₊)` -/ + +section Operators + +variable {p : ℝ≥0∞} [Fact (1 ≤ p)] +variable {φ : ℝ → ℝ} {A : Set ℝ} + +omit [Fact (1 ≤ p)] in +lemma memLp_zext (f : Lp ℝ p muPlus) : MemLp (zext ⇑f) p volume := + ALCS.memLp_zeroExt f + +omit [Fact (1 ≤ p)] in +lemma eLpNorm_zext (f : Lp ℝ p muPlus) : eLpNorm (zext ⇑f) p volume = eLpNorm (⇑f) p muPlus := + ALCS.eLpNorm_zeroExt f + +omit [Fact (1 ≤ p)] in +lemma memLp_rawOp (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) : MemLp (rawOp φ A ⇑f) p muPlus := + (((memLp_zext f).comp_measurePreserving hφ).indicator hA).mono_measure + Measure.restrict_le_self + +omit [Fact (1 ≤ p)] in +lemma eLpNorm_rawOp_le (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) : eLpNorm (rawOp φ A ⇑f) p muPlus ≤ eLpNorm (⇑f) p muPlus := by + calc eLpNorm (rawOp φ A ⇑f) p muPlus + ≤ eLpNorm (rawOp φ A ⇑f) p volume := eLpNorm_mono_measure _ Measure.restrict_le_self + _ ≤ eLpNorm (zext ⇑f ∘ φ) p volume := + eLpNorm_indicator_le (zext ⇑f ∘ φ) hA + _ = eLpNorm (zext ⇑f) p volume := + eLpNorm_comp_measurePreserving (memLp_zext f).aestronglyMeasurable hφ + _ = eLpNorm (⇑f) p muPlus := eLpNorm_zext f + +/-- `f ↦ rawOp φ A f`, as a map on `L^p(ℝ₊)`. -/ +def opFun (φ : ℝ → ℝ) (hφ : MeasurePreserving φ volume volume) (A : Set ℝ) + (hA : MeasurableSet A) (f : Lp ℝ p muPlus) : Lp ℝ p muPlus := + (memLp_rawOp hφ hA f).toLp (rawOp φ A ⇑f) + +omit [Fact (1 ≤ p)] in +lemma opFun_ae (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) : ⇑(opFun φ hφ A hA f) =ᵐ[muPlus] rawOp φ A ⇑f := + (memLp_rawOp hφ hA f).coeFn_toLp + +omit [Fact (1 ≤ p)] in +lemma opFun_congr (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) {g : ℝ → ℝ} (h : ⇑f =ᵐ[muPlus] g) : + ⇑(opFun φ hφ A hA f) =ᵐ[muPlus] rawOp φ A g := + (opFun_ae hφ hA f).trans (rawOp_congr hφ A h) + +omit [Fact (1 ≤ p)] in +lemma opFun_add (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f g : Lp ℝ p muPlus) : opFun φ hφ A hA (f + g) = opFun φ hφ A hA f + opFun φ hφ A hA g := by + apply Lp.ext + filter_upwards [opFun_congr hφ hA (f + g) (Lp.coeFn_add f g), opFun_ae hφ hA f, + opFun_ae hφ hA g, Lp.coeFn_add (opFun φ hφ A hA f) (opFun φ hφ A hA g)] with x e1 e2 e3 e4 + rw [e1, e4, Pi.add_apply, e2, e3] + exact rawOp_add ⇑f ⇑g x + +omit [Fact (1 ≤ p)] in +lemma opFun_smul (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (c : ℝ) (f : Lp ℝ p muPlus) : opFun φ hφ A hA (c • f) = c • opFun φ hφ A hA f := by + apply Lp.ext + filter_upwards [opFun_congr hφ hA (c • f) (Lp.coeFn_smul c f), opFun_ae hφ hA f, + Lp.coeFn_smul c (opFun φ hφ A hA f)] with x e1 e2 e3 + rw [e1, e3, Pi.smul_apply, e2] + exact rawOp_smul c ⇑f x + +omit [Fact (1 ≤ p)] in +lemma norm_opFun_le (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) : ‖opFun φ hφ A hA f‖ ≤ ‖f‖ := + ALCS.norm_toLp_le_of_eLpNorm_le (memLp_rawOp hφ hA f) f (eLpNorm_rawOp_le hφ hA f) + +/-- `f ↦ rawOp φ A f`, as a bounded linear operator on `L^p(ℝ₊)`, of norm at most `1`. -/ +def op (φ : ℝ → ℝ) (hφ : MeasurePreserving φ volume volume) (A : Set ℝ) + (hA : MeasurableSet A) : Lp ℝ p muPlus →L[ℝ] Lp ℝ p muPlus := + LinearMap.mkContinuous + { toFun := opFun φ hφ A hA + map_add' := opFun_add hφ hA + map_smul' := fun c f => by simpa using opFun_smul hφ hA c f } + 1 (fun f => by simpa using norm_opFun_le hφ hA f) + +lemma op_apply (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) : op φ hφ A hA f = opFun φ hφ A hA f := rfl + +lemma op_ae (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) : ⇑(op φ hφ A hA f) =ᵐ[muPlus] rawOp φ A ⇑f := by + rw [op_apply] + exact opFun_ae hφ hA f + +lemma op_congr (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) + (f : Lp ℝ p muPlus) {g : ℝ → ℝ} (h : ⇑f =ᵐ[muPlus] g) : + ⇑(op φ hφ A hA f) =ᵐ[muPlus] rawOp φ A g := by + rw [op_apply] + exact opFun_congr hφ hA f h + +lemma norm_op_le (hφ : MeasurePreserving φ volume volume) (hA : MeasurableSet A) : + ‖(op φ hφ A hA : Lp ℝ p muPlus →L[ℝ] Lp ℝ p muPlus)‖ ≤ 1 := by + apply ContinuousLinearMap.opNorm_le_bound _ zero_le_one + intro f + rw [op_apply, one_mul] + exact norm_opFun_le hφ hA f + +/-! ## The right-shift semigroup -/ + +variable (p) in +/-- The right shift `T t`: `(T t f)(s) = f (s - t)` for `s ≥ t`, `0` for `s < t`. -/ +def shiftT (t : ℝ) : Lp ℝ p muPlus →L[ℝ] Lp ℝ p muPlus := + op (fun x => x - t) (measurePreserving_sub_right volume t) Set.univ MeasurableSet.univ + +lemma shiftT_ae (t : ℝ) (f : Lp ℝ p muPlus) : + ⇑(shiftT p t f) =ᵐ[muPlus] rawOp (fun x => x - t) Set.univ ⇑f := + op_ae (measurePreserving_sub_right volume t) MeasurableSet.univ f + +lemma shiftT_congr (t : ℝ) (f : Lp ℝ p muPlus) {g : ℝ → ℝ} (h : ⇑f =ᵐ[muPlus] g) : + ⇑(shiftT p t f) =ᵐ[muPlus] rawOp (fun x => x - t) Set.univ g := + op_congr (measurePreserving_sub_right volume t) MeasurableSet.univ f h + +theorem shiftT_zero : shiftT p 0 = ContinuousLinearMap.id ℝ (Lp ℝ p muPlus) := by + apply ContinuousLinearMap.ext + intro f + rw [ContinuousLinearMap.id_apply] + apply Lp.ext + filter_upwards [shiftT_ae 0 f, ae_restrict_mem measurableSet_Ici] with x e1 hx + rw [e1, rawT_apply, sub_zero, zext_of_nonneg (⇑f) x hx] + +theorem shiftT_add {t s : ℝ} (_ht : 0 ≤ t) (hs : 0 ≤ s) : + shiftT p (t + s) = (shiftT p t).comp (shiftT p s) := by + apply ContinuousLinearMap.ext + intro f + rw [ContinuousLinearMap.comp_apply] + apply Lp.ext + filter_upwards [shiftT_ae (t + s) f, shiftT_congr t (shiftT p s f) (shiftT_ae s f)] + with x e1 e2 + rw [e1, e2, rawT_apply, rawT_apply] + by_cases hx : 0 ≤ x - t + · rw [zext_of_nonneg _ (x - t) hx, rawT_apply, show x - t - s = x - (t + s) by ring] + · rw [zext_of_neg _ (x - t) (not_le.1 hx), zext_of_neg (⇑f) (x - (t + s)) (by linarith)] + +/-! ### Strong continuity, from the generic half-line translation theorem -/ + +/-- The right shift is the half-line left shift with a negative translation parameter. -/ +lemma shiftT_eq_shiftLeft (t : ℝ) (f : Lp ℝ p muPlus) : + shiftT p t f = ALCS.shiftLeft (-t) f := by + apply Lp.ext + filter_upwards [shiftT_ae t f, ALCS.shiftLeft_ae (-t) f] with x hright hleft + rw [hright, rawT_apply, hleft] + simp only [zext, Function.comp_apply, sub_eq_neg_add] + +/-- Strong continuity of the right shift (uses `p ≠ ∞`). -/ +theorem shiftT_tendsto (hp : p ≠ ∞) (y : Lp ℝ p muPlus) : + Tendsto (fun t => shiftT p t y) (nhdsWithin 0 (Set.Ici 0)) (𝓝 y) := by + have hneg : Tendsto (fun t : ℝ => -t) (nhdsWithin 0 (Set.Ici 0)) (𝓝 0) := by + simpa only [neg_zero] using + (continuous_neg.tendsto (0 : ℝ)).mono_left nhdsWithin_le_nhds + apply tendsto_iff_norm_sub_tendsto_zero.2 + simpa only [shiftT_eq_shiftLeft, Function.comp_def] using + (ALCS.tendsto_norm_shiftLeft_sub hp y).comp hneg + +/-- The right-shift semigroup on `L^p(ℝ₊)`, for `p < ∞`. -/ +def rightShift (hp : p ≠ ∞) : C0Semigroup ℝ (Lp ℝ p muPlus) where + T := shiftT p + T_zero := shiftT_zero + T_add := fun _ _ ht hs => shiftT_add ht hs + T_cont := shiftT_tendsto hp + +/-! ## The input maps -/ + +variable (p) in +/-- The input map `Φ t`: `(Φ t u)(s) = u (t - s)` for `0 < s ≤ t`, `0` otherwise. -/ +def inputPhi (t : ℝ) : Lp ℝ p muPlus →L[ℝ] Lp ℝ p muPlus := + op (fun x => t - x) (Measure.measurePreserving_sub_left volume t) (Set.Ioc 0 t) + measurableSet_Ioc + +lemma inputPhi_ae (t : ℝ) (f : Lp ℝ p muPlus) : + ⇑(inputPhi p t f) =ᵐ[muPlus] rawOp (fun x => t - x) (Set.Ioc 0 t) ⇑f := + op_ae (Measure.measurePreserving_sub_left volume t) measurableSet_Ioc f + +lemma inputPhi_congr (t : ℝ) (f : Lp ℝ p muPlus) {g : ℝ → ℝ} (h : ⇑f =ᵐ[muPlus] g) : + ⇑(inputPhi p t f) =ᵐ[muPlus] rawOp (fun x => t - x) (Set.Ioc 0 t) g := + op_congr (Measure.measurePreserving_sub_left volume t) measurableSet_Ioc f h + +/-- Composition property: `Φ (τ + t) (u ⋄_τ v) = T t (Φ τ u) + Φ t v`. -/ +theorem inputPhi_composition {τ t : ℝ} (hτ : 0 ≤ τ) (ht : 0 ≤ t) (u v w : Lp ℝ p muPlus) + (hw : ⇑w =ᵐ[muPlus] concat τ ⇑u ⇑v) : + inputPhi p (τ + t) w = shiftT p t (inputPhi p τ u) + inputPhi p t v := by + apply Lp.ext + have e1 := inputPhi_congr (τ + t) w hw + have e2 := shiftT_congr t (inputPhi p τ u) (inputPhi_ae τ u) + have e3 := inputPhi_ae t v + have e4 := Lp.coeFn_add (shiftT p t (inputPhi p τ u)) (inputPhi p t v) + filter_upwards [e1, e2, e3, e4] with x h1 h2 h3 h4 + rw [h1, h4, Pi.add_apply, h2, h3] + exact concat_pointwise ⇑u ⇑v hτ ht x + +/-- The abstract linear control system of Proposition 3.1 (right shift on `L^p(ℝ₊)`). -/ +def shiftSystem (hp : p ≠ ∞) : ALCS ℝ (Lp ℝ p muPlus) ℝ p where + toC0Semigroup := rightShift hp + Φ := inputPhi p + composition := fun _ _ hτ ht u v w hw => inputPhi_composition hτ ht u v w hw + +/-! ## `κ(t) = 1` for all `t > 0` -/ + +lemma p_ne_zero : p ≠ 0 := by + have hp1 : (1 : ℝ≥0∞) ≤ p := Fact.out + exact (lt_of_lt_of_le zero_lt_one hp1).ne' + +lemma muPlus_Ico (t : ℝ) : muPlus (Set.Ico 0 t) = ENNReal.ofReal t := by + have hsub : Set.Ico (0 : ℝ) t ⊆ Set.Ici 0 := by + intro x hx + exact Set.mem_Ici.2 hx.1 + rw [Measure.restrict_apply measurableSet_Ico, Set.inter_eq_left.2 hsub, Real.volume_Ico, + sub_zero] + +lemma muPlus_Ioc (t : ℝ) : muPlus (Set.Ioc 0 t) = ENNReal.ofReal t := by + have hsub : Set.Ioc (0 : ℝ) t ⊆ Set.Ici 0 := by + intro x hx + exact Set.mem_Ici.2 hx.1.le + rw [Measure.restrict_apply measurableSet_Ioc, Set.inter_eq_left.2 hsub, Real.volume_Ioc, + sub_zero] + +lemma muPlus_Ico_ne_top (t : ℝ) : muPlus (Set.Ico 0 t) ≠ ∞ := by + rw [muPlus_Ico] + exact ENNReal.ofReal_ne_top + +lemma muPlus_Ioc_ne_top (t : ℝ) : muPlus (Set.Ioc 0 t) ≠ ∞ := by + rw [muPlus_Ioc] + exact ENNReal.ofReal_ne_top + +variable (p) in +/-- The test input `1_{[0,t)}`. -/ +def testInput (t : ℝ) : Lp ℝ p muPlus := + indicatorConstLp p (measurableSet_Ico : MeasurableSet (Set.Ico (0 : ℝ) t)) + (muPlus_Ico_ne_top t) (1 : ℝ) + +variable (p) in +/-- The corresponding output `1_{(0,t]}`. -/ +def testOutput (t : ℝ) : Lp ℝ p muPlus := + indicatorConstLp p (measurableSet_Ioc : MeasurableSet (Set.Ioc (0 : ℝ) t)) + (muPlus_Ioc_ne_top t) (1 : ℝ) + +lemma inputPhi_testInput (t : ℝ) : inputPhi p t (testInput p t) = testOutput p t := by + apply Lp.ext + have hu : ⇑(testInput p t) =ᵐ[muPlus] (Set.Ico 0 t).indicator (fun _ => (1 : ℝ)) := + indicatorConstLp_coeFn + have hw : ⇑(testOutput p t) =ᵐ[muPlus] (Set.Ioc 0 t).indicator (fun _ => (1 : ℝ)) := + indicatorConstLp_coeFn + filter_upwards [inputPhi_congr t (testInput p t) hu, hw] with x e1 e2 + rw [e1, e2] + by_cases hx : 0 < x ∧ x ≤ t + · have h1 : t - x ∈ Set.Ico 0 t := ⟨by linarith [hx.2], by linarith [hx.1]⟩ + have h2 : x ∈ Set.Ioc 0 t := hx + rw [rawPhi_of_mem _ t x hx, Set.indicator_of_mem h1, Set.indicator_of_mem h2] + · have h2 : x ∉ Set.Ioc 0 t := hx + rw [rawPhi_of_not _ t x hx, Set.indicator_of_notMem h2] + +lemma norm_testInput (hp : p ≠ ∞) {t : ℝ} (ht : 0 ≤ t) : + ‖testInput p t‖ = t ^ (1 / p.toReal) := by + rw [testInput, norm_indicatorConstLp p_ne_zero hp, norm_one, one_mul, measureReal_def, + muPlus_Ico, ENNReal.toReal_ofReal ht] + +lemma norm_testOutput (hp : p ≠ ∞) {t : ℝ} (ht : 0 ≤ t) : + ‖testOutput p t‖ = t ^ (1 / p.toReal) := by + rw [testOutput, norm_indicatorConstLp p_ne_zero hp, norm_one, one_mul, measureReal_def, + muPlus_Ioc, ENNReal.toReal_ofReal ht] + +lemma norm_inputPhi_le (t : ℝ) : ‖inputPhi p t‖ ≤ 1 := + norm_op_le (Measure.measurePreserving_sub_left volume t) measurableSet_Ioc + +lemma one_le_norm_inputPhi (hp : p ≠ ∞) {t : ℝ} (ht : 0 < t) : 1 ≤ ‖inputPhi p t‖ := by + -- `‖Φ t u_t‖ = ‖u_t‖ > 0` for the test input `u_t` + have h1 : ‖inputPhi p t (testInput p t)‖ ≤ ‖inputPhi p t‖ * ‖testInput p t‖ := + (inputPhi p t).le_opNorm (testInput p t) + rw [inputPhi_testInput, norm_testOutput hp ht.le, ← norm_testInput hp ht.le] at h1 + have hpos : 0 < ‖testInput p t‖ := by + rw [norm_testInput hp ht.le] + exact Real.rpow_pos_of_pos ht _ + by_contra h + have h2 : ‖inputPhi p t‖ * ‖testInput p t‖ < 1 * ‖testInput p t‖ := + mul_lt_mul_of_pos_right (not_le.1 h) hpos + linarith + +/-- `κ(t) = ‖Φ t‖ = 1` for all `t > 0`. -/ +theorem norm_Phi_eq_one (hp : p ≠ ∞) {t : ℝ} (ht : 0 < t) : ‖(shiftSystem hp).Φ t‖ = 1 := + le_antisymm (norm_inputPhi_le t) (one_le_norm_inputPhi hp ht) + +/-- The system of Proposition 3.1 is not of the zero-class (Definition 1.4). -/ +theorem not_zero_class (hp : p ≠ ∞) : ¬ (shiftSystem hp).IsZeroClass := by + intro h0 + have h : Tendsto (fun t => ‖(shiftSystem hp).Φ t‖) (nhdsWithin 0 (Set.Ici 0)) (𝓝 0) := h0 + have h1 : Tendsto (fun t => ‖(shiftSystem hp).Φ t‖) (nhdsWithin 0 (Set.Ioi 0)) (𝓝 0) := + h.mono_left (nhdsWithin_mono 0 Set.Ioi_subset_Ici_self) + have hev : (fun _ : ℝ => (1 : ℝ)) =ᶠ[nhdsWithin 0 (Set.Ioi 0)] + fun t => ‖(shiftSystem hp).Φ t‖ := by + filter_upwards [self_mem_nhdsWithin] with t ht + exact (norm_Phi_eq_one hp ht).symm + have h2 : Tendsto (fun t => ‖(shiftSystem hp).Φ t‖) (nhdsWithin 0 (Set.Ioi 0)) (𝓝 1) := + tendsto_const_nhds.congr' hev + have h3 : (1 : ℝ) = 0 := tendsto_nhds_unique h2 h1 + exact one_ne_zero h3 + +end Operators + +end ShiftExample + +open ShiftExample + +/-- **Proposition 3.1** (`prop:example-finite-p-not-zero-class`). For `p ∈ [1, ∞)`, there +exist (real) Banach spaces `X`, `U` and an abstract linear control system `(T, Φ)` with +`κ(t) = ‖Φ t‖ = 1` for all `t > 0`. -/ +theorem exists_system_norm_Phi_eq_one (p : ℝ≥0∞) [Fact (1 ≤ p)] (hp : p ≠ ∞) : + ∃ (X : Type) (_ : NormedAddCommGroup X) (_ : NormedSpace ℝ X) (_ : CompleteSpace X) + (U : Type) (_ : NormedAddCommGroup U) (_ : NormedSpace ℝ U) (_ : CompleteSpace U) + (S : ALCS ℝ X U p), ∀ t : ℝ, 0 < t → ‖S.Φ t‖ = 1 := + ⟨Lp ℝ p muPlus, inferInstance, inferInstance, inferInstance, + ℝ, inferInstance, inferInstance, inferInstance, + shiftSystem hp, fun _ ht => norm_Phi_eq_one hp ht⟩ + +end + +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Examples/NoRepresentation.lean b/LeanPool/AbstractLinearControl/Examples/NoRepresentation.lean new file mode 100644 index 0000000000..f0beb6f6d3 --- /dev/null +++ b/LeanPool/AbstractLinearControl/Examples/NoRepresentation.lean @@ -0,0 +1,511 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Definitions +public import LeanPool.AbstractLinearControl.Examples.Periodization + + +/-! +# A system without integral representation (Proposition 3.3) + +**Proposition 3.3** (`prop:no-representation`). There exists an abstract linear control +system `(𝕋, Φ)` with `p = ∞`, `X = U = ℝ` and `𝕋_t = Id` for all `t ≥ 0`, such that +* (i) `κ(t) = t` for every `t ≥ 0`; +* (ii) `(𝕋, Φ)` admits no integral representation; +* (iii) `(𝕋, Φ)` is not `E_F`-admissible, for any Young function `F`. + +The final statement is `ExoticMean.Counterexample.no_representation`. + +## Proof + +* Steps 1–2 (`exists_local_control_from_mean`, using `ALCS/Examples/Periodization.lean`): + with the exotic mean `m` of Lemma 3.2, `J = m ∘ P` and `Φ_t u = J(1_{(0,t]} u)`. +* Step 3 (`LocalControlData.smallIndicators`): for a periodic open dense set `O` of small + measure, `m(1_O) = 1` while `|O ∩ (0, 1]|` is small. (The paper uses a set `E` with + `J(1_E) ≠ |E|`; here the mean vanishes on functions vanishing on an open dense set, + which directly gives inputs of small support with output `1`.) +* Steps 4–5 (`not_integral_of_smallIndicators`, `not_EF_of_smallIndicators`). + +## Formalization choices + +* Since `A = 0`, the extrapolation space `X_{-1}` is `ℝ`, so an integral representation + (`eq:representation`) is given by a real bounded operator `B` (`HasIntegralRepresentation`). +* `YoungFunction` only records `F(0) = 0`, nonnegativity, convexity, continuity and growth + at infinity: it contains all Young functions of the paper, so (iii) is proved for a + larger class. The Luxemburg norm `luxemburg` is defined by its infimum formula. +* `EFAdmissible` asks for `eq:orlicz` at all times `t ≥ 0`, for inputs whose modular is + finite (which is automatic for `L^∞` inputs and finite-valued `F`). +* Intervals `[0, t)` of the paper become `(0, t]`, which only changes null sets. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +noncomputable section +open Set Filter MeasureTheory +open scoped ENNReal NNReal Topology BigOperators + +namespace ExoticMean.Counterexample + +local instance : Fact (1 ≤ (∞ : ℝ≥0∞)) := ⟨le_top⟩ + +/-- Bounded scalar inputs on the nonnegative half-line. -/ +abbrev Input := Lp ℝ ∞ muPlus +/-- Scalar-state, scalar-input systems with bounded inputs. -/ +abbrev ScalarSystem := ALCS ℝ ℝ ℝ ∞ + +/-- The constant unit input. -/ +def inputOne : Input := linftyConst muPlus 1 + +/-- The input represented by the indicator of a measurable set. -/ +def inputIndicator (A : Set ℝ) (hA : MeasurableSet A) : Input := + linftyIndicator muPlus A hA + +/-- The choice `(0,1]` rather than `[0,1)` changes only null endpoints. -/ +def cell : Set ℝ := Ioc 0 1 + +lemma cell_measurable : MeasurableSet cell := measurableSet_Ioc + +lemma cell_subset_halfline : cell ⊆ Ici (0 : ℝ) := fun _ hx => hx.1.le + +lemma inputOne_norm_le : ‖inputOne‖ ≤ 1 := by + apply linfty_norm_le inputOne (by norm_num) + filter_upwards [linftyConst_ae muPlus 1] with r hr + simp [inputOne, hr] + +lemma ae_on_cell {p : ℝ → Prop} (hp : ∀ᵐ r ∂muPlus, p r) : + ∀ᵐ r ∂volume.restrict cell, p r := by + have h := (ae_restrict_iff' (measurableSet_Ici : MeasurableSet (Ici (0 : ℝ)))).mp hp + filter_upwards [ae_restrict_of_ae h, ae_restrict_mem cell_measurable] with r hr hrC + exact hr (cell_subset_halfline hrC) + +lemma cell_measure_ne_top : volume cell ≠ ∞ := by + simp [cell, Real.volume_Ioc] + +lemma measure_ne_top_of_subset_cell {A : Set ℝ} (hA : A ⊆ cell) : volume A ≠ ∞ := + ne_top_of_le_ne_top cell_measure_ne_top (measure_mono hA) + +lemma inputIndicator_integral {A : Set ℝ} (hA : MeasurableSet A) (hAC : A ⊆ cell) : + (∫ r in cell, inputIndicator A hA r) = (volume A).toReal := by + unfold inputIndicator + rw [integral_congr_ae (ae_on_cell (linftyIndicator_ae muPlus A hA))] + rw [MeasureTheory.integral_indicator hA] + simp [Measure.real, Measure.restrict_apply, hA, inter_eq_left.mpr hAC] + +/-! ## Step 2: the input maps `Φ_t u = J(1_{(0,t]} u)` -/ + +/-- The periodization `r ↦ Σ_{k ∈ ℤ} (1_{(0,t]} u)(r + k)` (raw formula). -/ +def rawPeriodization (t : ℝ) (u : Input) (r : ℝ) : ℝ := + ∑' k : ℤ, (Ioc (0 : ℝ) t).indicator (fun s => u s) (r + (k : ℝ)) + +/-- The input maps `Φ_t u = m(P(1_{(0,t]} u))` of Step 2, before packaging as continuous +linear maps, together with the properties used in Steps 3–5. They are constructed in +`exists_local_control_from_mean`. -/ +structure LocalControlData (m : LinftyPer →L[ℝ] ℝ) where + /-- The response at each time, before its continuity bound is bundled. -/ + out : ℝ → Input →ₗ[ℝ] ℝ + /-- The exact formula `m(P(1_(0,t] u))`, on a.e. classes. -/ + formula : ∀ t, 0 ≤ t → ∀ u, + ∃ g : LinftyPer, (⇑g.val =ᵐ[volume] rawPeriodization t u) ∧ out t u = m g + bound : ∀ t, 0 ≤ t → ∀ u, ‖out t u‖ ≤ t * ‖u‖ + one_value : ∀ t, 0 ≤ t → out t inputOne = t + composition : ∀ τ t, 0 ≤ τ → 0 ≤ t → ∀ u v w : Input, + (⇑w =ᵐ[muPlus] concat τ ⇑u ⇑v) → out (τ + t) w = out τ u + out t v + periodic_test : ∀ O : PeriodicSet, + out 1 (inputIndicator (O.carrier ∩ cell) (O.measurable.inter cell_measurable)) = + m O.indicator + +private lemma input_ae_on_halfline {p : ℝ → Prop} (hp : ∀ᵐ r ∂muPlus, p r) : + ∀ᵐ r ∂volume, 0 ≤ r → p r := + (ae_restrict_iff' (measurableSet_Ici : MeasurableSet (Ici (0 : ℝ)))).mp hp + +open Periodization + +/-- The test function `1_{(0,t]} u` (built from the representative of `u`). -/ +private def truncated (t : ℝ) (u : Input) : TestFunction := + supportedInterval 0 t (⇑u) (Lp.stronglyMeasurable u) ‖u‖ (norm_nonneg _) + (by + filter_upwards [input_ae_on_halfline (linfty_ae_norm_le u)] with r hr + intro hrt + exact hr hrt.1.le) + +private lemma truncated_bound (t : ℝ) (u : Input) : + ∀ᵐ r ∂volume, ‖(truncated t u).val r‖ ≤ + (Ioc (0 : ℝ) t).indicator (fun _ => ‖u‖) r := by + filter_upwards [input_ae_on_halfline (linfty_ae_norm_le u)] with r hr + change ‖(Ioc (0 : ℝ) t).indicator (⇑u) r‖ ≤ _ + by_cases h : r ∈ Ioc (0 : ℝ) t + · simpa [h] using hr h.1.le + · simp [h] + +private lemma truncated_add (t : ℝ) (u v : Input) : + periodize (truncated t (u + v)) = + periodize (truncated t u) + periodize (truncated t v) := by + apply periodize_add + filter_upwards [input_ae_on_halfline (Lp.coeFn_add u v)] with r hr + change (Ioc (0 : ℝ) t).indicator (⇑(u + v)) r = + (Ioc (0 : ℝ) t).indicator (⇑u) r + (Ioc (0 : ℝ) t).indicator (⇑v) r + by_cases h : r ∈ Ioc (0 : ℝ) t + · simpa [h] using hr h.1.le + · simp [h] + +private lemma truncated_smul (t c : ℝ) (u : Input) : + periodize (truncated t (c • u)) = c • periodize (truncated t u) := by + apply periodize_smul + filter_upwards [input_ae_on_halfline (Lp.coeFn_smul c u)] with r hr + change (Ioc (0 : ℝ) t).indicator (⇑(c • u)) r = + c * (Ioc (0 : ℝ) t).indicator (⇑u) r + by_cases h : r ∈ Ioc (0 : ℝ) t + · simpa [h] using hr h.1.le + · simp [h] + +private def localOutput (m : LinftyPer →L[ℝ] ℝ) (t : ℝ) : Input →ₗ[ℝ] ℝ where + toFun u := m (periodize (truncated t u)) + map_add' := by intro u v; rw [truncated_add, map_add] + map_smul' := by intro c u; rw [truncated_smul, map_smul]; rfl + +/-- Steps 1–2 of the proof of Proposition 3.3: from a positive, normalized, +translation-invariant mean `m`, the maps `Φ_t u = J(1_{(0,t]} u)` satisfy the bound +`|Φ_t u| ≤ t ‖u‖`, `Φ_t 1 = t`, the composition property with `T = Id`, and recover `m` +on periodic indicators. -/ +theorem exists_local_control_from_mean + (m : LinftyPer →L[ℝ] ℝ) (hpos : Positive m.toLinearMap) + (h1 : m one = 1) (hT : ∀ a f, m (translate a f) = m f) : + Nonempty (LocalControlData m) := by + refine ⟨{ + out := localOutput m + formula := ?_ + bound := ?_ + one_value := ?_ + composition := ?_ + periodic_test := ?_ }⟩ + · intro t ht u + exact ⟨periodize (truncated t u), (truncated t u).periodize_ae, rfl⟩ + · intro t ht u + exact mean_support_bound m hpos h1 hT (truncated t u) 0 t ‖u‖ ht + (norm_nonneg _) (truncated_bound t u) |>.trans_eq (by simp) + · intro t ht + change m (periodize (truncated t inputOne)) = t + have heq : periodize (truncated t inputOne) = periodize (interval 0 t 1) := by + apply periodize_congr + filter_upwards [input_ae_on_halfline (linftyConst_ae muPlus 1)] with r hr + change (Ioc (0 : ℝ) t).indicator (⇑inputOne) r = + (Ioc (0 : ℝ) t).indicator (fun _ => (1 : ℝ)) r + by_cases h : r ∈ Ioc (0 : ℝ) t + · simpa [h, inputOne] using hr h.1.le + · simp [h] + rw [heq, mean_interval m hpos h1 hT 0 t ht, sub_zero] + · intro τ t hτ ht u v w hw + change m (periodize (truncated (τ + t) w)) = + m (periodize (truncated τ u)) + m (periodize (truncated t v)) + have heq : periodize (truncated (τ + t) w) = + periodize (truncated τ u) + periodize (shifted τ (truncated t v)) := by + apply periodize_add + have hne : ∀ᵐ r : ℝ ∂volume, r ≠ τ := by + exact ae_iff.mpr (by simp) + filter_upwards [input_ae_on_halfline hw, hne] with r hr hne + change (Ioc (0 : ℝ) (τ + t)).indicator (⇑w) r = + (Ioc (0 : ℝ) τ).indicator (⇑u) r + + (Ioc (0 : ℝ) t).indicator (⇑v) (-τ + r) + by_cases h0 : 0 < r + · have hwr := hr h0.le + change w r = if r < τ then u r else v (r - τ) at hwr + by_cases hτr : r < τ + · have hleft : r ∈ Ioc (0 : ℝ) τ := ⟨h0, hτr.le⟩ + have hall : r ∈ Ioc (0 : ℝ) (τ + t) := ⟨h0, by linarith⟩ + have hoff : -τ + r ∉ Ioc (0 : ℝ) t := by intro h; linarith [h.1] + simp [hleft, hall, hoff, hwr, hτr] + · have hτlt : τ < r := lt_of_le_of_ne (not_lt.mp hτr) (Ne.symm hne) + have hoff : r ∉ Ioc (0 : ℝ) τ := by intro h; linarith [h.2] + have hiff : -τ + r ∈ Ioc (0 : ℝ) t ↔ r ∈ Ioc (0 : ℝ) (τ + t) := by + constructor <;> intro h <;> constructor <;> linarith [h.1, h.2] + simp only [Set.indicator, hoff, hiff, ite_false, zero_add] + split_ifs with h + · simpa [hτr, sub_eq_neg_add] using hwr + · rfl + · have hoff1 : r ∉ Ioc (0 : ℝ) (τ + t) := fun h => h0 h.1 + have hoff2 : r ∉ Ioc (0 : ℝ) τ := fun h => h0 h.1 + have hoff3 : -τ + r ∉ Ioc (0 : ℝ) t := by intro h; linarith [h.1] + simp [hoff1, hoff2, hoff3] + rw [heq, map_add, periodize_shifted, hT] + · intro O + let u := inputIndicator (O.carrier ∩ cell) (O.measurable.inter cell_measurable) + change m (periodize (truncated 1 u)) = m O.indicator + congr 1 + apply Subtype.ext + apply Lp.ext + have hcut : (truncated 1 u).val =ᵐ[volume] + cell.indicator (O.carrier.indicator (fun _ => (1 : ℝ))) := by + filter_upwards [input_ae_on_halfline + (linftyIndicator_ae muPlus (O.carrier ∩ cell) (O.measurable.inter cell_measurable))] + with r hr + change cell.indicator (⇑u) r = _ + by_cases h : r ∈ cell + · dsimp [u, inputIndicator] + rw [indicator_of_mem h, hr (cell_subset_halfline h), indicator_of_mem h] + by_cases hO : r ∈ O.carrier <;> simp [hO, h] + · simp [h] + have hp : Function.Periodic (O.carrier.indicator (fun _ => (1 : ℝ))) 1 := by + have hmem : Function.Periodic (fun r : ℝ => r ∈ O.carrier) (-1) := by + intro r + exact propext (by simpa [add_comm] using O.period r) + intro r + have h : (r + 1 ∈ O.carrier) = (r ∈ O.carrier) := by simpa using hmem.neg r + by_cases hr : r ∈ O.carrier + · have hr' : r + 1 ∈ O.carrier := Eq.mp h.symm hr + simp [Set.indicator, hr, hr'] + · have hr' : r + 1 ∉ O.carrier := fun hx => hr (Eq.mp h hx) + simp [Set.indicator, hr, hr'] + filter_upwards [(truncated 1 u).periodize_ae, O.indicator_ae, ae_shifts hcut] + with r hr hO hcut + rw [hr, hO] + unfold raw + rw [tsum_congr hcut] + exact raw_cell_recovery _ hp r + +namespace LocalControlData + +variable {m : LinftyPer →L[ℝ] ℝ} (D : LocalControlData m) + +/-- Values at negative times are irrelevant to `ALCS`; set them to zero. -/ +def phi (t : ℝ) : Input →L[ℝ] ℝ := + if ht : 0 ≤ t then (D.out t).mkContinuous t (D.bound t ht) else 0 + +lemma phi_apply (t : ℝ) (ht : 0 ≤ t) (u : Input) : D.phi t u = D.out t u := by + simp [phi, ht] + +/-- The system of Proposition 3.3: `T_t = Id` and the input maps of Step 2. -/ +def system : ScalarSystem where + T := fun _ => ContinuousLinearMap.id ℝ ℝ + T_zero := rfl + T_add := by intros; ext; rfl + T_cont := by intro y; exact tendsto_const_nhds + Φ := D.phi + composition := by + intro τ t hτ ht u v w hw + change D.phi (τ + t) w = D.phi τ u + D.phi t v + rw [D.phi_apply (τ + t) (add_nonneg hτ ht), + D.phi_apply τ hτ, D.phi_apply t ht] + exact D.composition τ t hτ ht u v w hw + +lemma system_T (t : ℝ) : D.system.T t = ContinuousLinearMap.id ℝ ℝ := rfl + +/-- Property (i) of Proposition 3.3: `κ(t) = ‖Φ t‖ = t`. The upper bound is `eq:J-bound`; +the constant input `1` attains it. -/ +theorem kappa (t : ℝ) (ht : 0 ≤ t) : ‖D.system.Φ t‖ = t := by + apply le_antisymm + · apply ContinuousLinearMap.opNorm_le_bound _ ht + intro u + rw [show D.system.Φ t u = D.out t u from D.phi_apply t ht u] + exact D.bound t ht u + · have hone : D.system.Φ t inputOne = t := + (D.phi_apply t ht inputOne).trans (D.one_value t ht) + calc + t = ‖D.system.Φ t inputOne‖ := by rw [hone, Real.norm_eq_abs, abs_of_nonneg ht] + _ ≤ ‖D.system.Φ t‖ * ‖inputOne‖ := (D.system.Φ t).le_opNorm inputOne + _ ≤ ‖D.system.Φ t‖ * 1 := + mul_le_mul_of_nonneg_left inputOne_norm_le (norm_nonneg _) + _ = ‖D.system.Φ t‖ := mul_one _ + +end LocalControlData + +/-! ## Integral representation (`eq:representation`) and `E_F`-admissibility (`eq:orlicz`) -/ + +/-- Integral representation `eq:representation`, `Φ_t u = ∫_0^t T_{t-s} B u(s) ds`, with +`B : ℝ → ℝ`. For `T = Id` the generator is `A = 0` and `X_{-1} = ℝ`, so this is the +representation of the paper specialized to the systems considered here. -/ +def HasIntegralRepresentation (S : ScalarSystem) : Prop := + ∃ B : ℝ →L[ℝ] ℝ, ∀ t : ℝ, 0 ≤ t → ∀ u : Input, + S.Φ t u = ∫ s in Ioc (0 : ℝ) t, S.T (t - s) (B (u s)) + +lemma scalar_form_of_representation (S : ScalarSystem) + (hT : ∀ t, S.T t = ContinuousLinearMap.id ℝ ℝ) + (h : HasIntegralRepresentation S) : + ∃ b : ℝ, ∀ t : ℝ, 0 ≤ t → ∀ u : Input, + S.Φ t u = b * ∫ s in Ioc (0 : ℝ) t, u s := by + obtain ⟨B, hB⟩ := h + refine ⟨B 1, ?_⟩ + have hBx (x : ℝ) : B x = B 1 * x := by + calc + B x = B (x • (1 : ℝ)) := by simp + _ = x • B 1 := B.map_smul x 1 + _ = B 1 * x := by simp [mul_comm] + intro t ht u + rw [hB t ht u] + have heq : (fun s => S.T (t - s) (B (u s))) = (fun s => B 1 * u s) := by + funext s + rw [hT, ContinuousLinearMap.id_apply, hBx] + rw [heq] + exact integral_const_mul _ _ + +/-- Young functions. This class contains the Young functions of the paper (it does not +require `F(r)/r → 0` at `0` nor `F(r)/r → ∞` at `∞`); the proofs only use `F(0) = 0` and +`F ≥ 0`. -/ +structure YoungFunction where + /-- The scalar function defining the Orlicz modular. -/ + toFun : ℝ → ℝ + zero : toFun 0 = 0 + nonneg : ∀ x : ℝ, 0 ≤ x → 0 ≤ toFun x + convex : ConvexOn ℝ (Ici 0) toFun + continuous : ContinuousOn toFun (Ici 0) + growth : Tendsto toFun atTop atTop + +/-- The modular is an extended nonnegative integral, so divergence is not +silently converted to the real number zero. -/ +def modular (F : YoungFunction) (t : ℝ) (u : Input) (lam : ℝ) : ℝ≥0∞ := + ∫⁻ s in Ioc (0 : ℝ) t, ENNReal.ofReal (F.toFun (|u s| / lam)) + +/-- Membership of the restriction to `(0,t]` in the Orlicz heart. -/ +def InHeart (F : YoungFunction) (t : ℝ) (u : Input) : Prop := + ∀ lam : ℝ, 0 < lam → modular F t u lam < ∞ + +/-- The Luxemburg gauge, by its infimum definition, not an abstract norm +postulated to tend to zero. -/ +def luxemburg (F : YoungFunction) (t : ℝ) (u : Input) : ℝ := + sInf {lam : ℝ | 0 < lam ∧ modular F t u lam ≤ 1} + +lemma luxemburg_le (F : YoungFunction) (t : ℝ) (u : Input) + {lam : ℝ} (hlam : 0 < lam) (hmod : modular F t u lam ≤ 1) : + luxemburg F t u ≤ lam := by + exact csInf_le ⟨0, fun _ hx => hx.1.le⟩ ⟨hlam, hmod⟩ + +/-- `E_F`-admissibility, estimate `eq:orlicz`: `|Φ_t u| ≤ C_t ‖u‖_{F,t}` for every `t`. -/ +def EFAdmissible (S : ScalarSystem) (F : YoungFunction) : Prop := + ∀ t : ℝ, 0 ≤ t → ∃ C : ℝ, 0 ≤ C ∧ ∀ u : Input, + InHeart F t u → |S.Φ t u| ≤ C * luxemburg F t u + +lemma indicator_modular (F : YoungFunction) {A : Set ℝ} + (hA : MeasurableSet A) (hAC : A ⊆ cell) (lam : ℝ) : + modular F 1 (inputIndicator A hA) lam = + ENNReal.ofReal ((volume A).toReal * F.toFun (1 / lam)) := by + have hrep := ae_on_cell (linftyIndicator_ae muPlus A hA) + have heq : (fun s => ENNReal.ofReal (F.toFun (|inputIndicator A hA s| / lam))) + =ᵐ[volume.restrict cell] + A.indicator (fun _ => ENNReal.ofReal (F.toFun (1 / lam))) := by + filter_upwards [hrep] with s hs + dsimp [inputIndicator] + rw [hs] + by_cases h : s ∈ A <;> simp [Set.indicator, h, F.zero] + change (∫⁻ s, ENNReal.ofReal (F.toFun (|inputIndicator A hA s| / lam)) + ∂volume.restrict cell) = _ + rw [lintegral_congr_ae heq, lintegral_indicator hA] + simp only [lintegral_const, Measure.restrict_apply MeasurableSet.univ, + univ_inter, Measure.restrict_apply hA, inter_eq_left.mpr hAC] + rw [ENNReal.ofReal_mul (by positivity), ENNReal.ofReal_toReal + (measure_ne_top_of_subset_cell hAC)] + simp [mul_comm] + +lemma indicator_inHeart (F : YoungFunction) {A : Set ℝ} + (hA : MeasurableSet A) (hAC : A ⊆ cell) : + InHeart F 1 (inputIndicator A hA) := by + intro lam hlam + rw [indicator_modular F hA hAC lam] + exact ENNReal.ofReal_lt_top + +/-! ## Steps 4–5: the two obstructions -/ + +/-- Step 3: indicators of sets of arbitrarily small measure with output exactly one. -/ +def SmallIndicators (S : ScalarSystem) : Prop := + ∀ ε : ℝ, 0 < ε → ∃ A : Set ℝ, ∃ hA : MeasurableSet A, + A ⊆ cell ∧ (volume A).toReal < ε ∧ S.Φ 1 (inputIndicator A hA) = 1 + +lemma not_integral_of_smallIndicators (S : ScalarSystem) + (hT : ∀ t, S.T t = ContinuousLinearMap.id ℝ ℝ) + (hsmall : SmallIndicators S) : ¬ HasIntegralRepresentation S := by + intro hrepr + obtain ⟨b, hb⟩ := scalar_form_of_representation S hT hrepr + let ε : ℝ := 1 / (2 * (|b| + 1)) + have hε : 0 < ε := by dsimp [ε]; positivity + obtain ⟨A, hA, hAC, hμ, hout⟩ := hsmall ε hε + have hrep := hb 1 (by norm_num) (inputIndicator A hA) + change S.Φ 1 (inputIndicator A hA) = b * ∫ s in cell, inputIndicator A hA s at hrep + rw [inputIndicator_integral hA hAC, hout] at hrep + have habs : (1 : ℝ) = |b| * (volume A).toReal := by + have h := congrArg abs hrep + simpa [abs_mul, abs_of_nonneg ENNReal.toReal_nonneg] using h + have hscaled := (lt_div_iff₀ (show 0 < 2 * (|b| + 1) by positivity)).mp hμ + have hμ0 : 0 ≤ (volume A).toReal := ENNReal.toReal_nonneg + nlinarith + +lemma not_EF_of_smallIndicators (S : ScalarSystem) + (hsmall : SmallIndicators S) (F : YoungFunction) : ¬ EFAdmissible S F := by + intro hEF + obtain ⟨C, hC, hbound⟩ := hEF 1 (by norm_num) + let lam : ℝ := 1 / (2 * (C + 1)) + have hlam : 0 < lam := by dsimp [lam]; positivity + have hClam : C * lam < 1 := by + dsimp [lam] + rw [mul_one_div, div_lt_iff₀ (by positivity)] + linarith + let K : ℝ := F.toFun (1 / lam) + have hK : 0 ≤ K := F.nonneg _ (by positivity) + let δ : ℝ := 1 / (K + 1) + have hδ : 0 < δ := by dsimp [δ]; positivity + obtain ⟨A, hA, hAC, hμ, hout⟩ := hsmall δ hδ + have hmod : modular F 1 (inputIndicator A hA) lam ≤ 1 := by + rw [indicator_modular F hA hAC lam] + have hμK : (volume A).toReal * K ≤ 1 := by + have hscaled := (lt_div_iff₀ (show 0 < K + 1 by linarith)).mp hμ + have hμ0 : 0 ≤ (volume A).toReal := ENNReal.toReal_nonneg + nlinarith + calc + ENNReal.ofReal ((volume A).toReal * F.toFun (1 / lam)) + ≤ ENNReal.ofReal (1 : ℝ) := ENNReal.ofReal_le_ofReal hμK + _ = 1 := by simp + have hlu := luxemburg_le F 1 (inputIndicator A hA) hlam hmod + have houtbound := hbound (inputIndicator A hA) (indicator_inHeart F hA hAC) + rw [hout, abs_one] at houtbound + have hmul := mul_le_mul_of_nonneg_left hlu hC + linarith + +lemma LocalControlData.smallIndicators + {m : LinftyPer →L[ℝ] ℝ} (D : LocalControlData m) + (h1 : m one = 1) (hV : ∀ v ∈ vanishingOnDenseOpen, m v = 0) : + SmallIndicators D.system := by + intro ε hε + obtain ⟨O, hOo, hOd, hμ⟩ := exists_small_periodic_open ε hε + refine ⟨O.carrier ∩ cell, O.measurable.inter cell_measurable, + inter_subset_right, hμ, ?_⟩ + change D.phi 1 _ = 1 + rw [D.phi_apply 1 (by norm_num), D.periodic_test] + exact O.mean_indicator m h1 hV hOo hOd + +/-- Steps 3–5 of the proof of Proposition 3.3: the system built from `LocalControlData` has +properties (i), (ii), (iii), provided the mean vanishes on `vanishingOnDenseOpen`. -/ +theorem counterexample_from_data + {m : LinftyPer →L[ℝ] ℝ} (D : LocalControlData m) + (h1 : m one = 1) (hV : ∀ v ∈ vanishingOnDenseOpen, m v = 0) : + (∀ t : ℝ, 0 ≤ t → D.system.T t = ContinuousLinearMap.id ℝ ℝ) ∧ + (∀ t : ℝ, 0 ≤ t → ‖D.system.Φ t‖ = t) ∧ + ¬ HasIntegralRepresentation D.system ∧ + ∀ F : YoungFunction, ¬ EFAdmissible D.system F := by + have hsmall := D.smallIndicators h1 hV + exact ⟨fun t _ => D.system_T t, D.kappa, + not_integral_of_smallIndicators D.system D.system_T hsmall, + not_EF_of_smallIndicators D.system hsmall⟩ + +/-- **Proposition 3.3** (`prop:no-representation`). There is an abstract linear control +system with `p = ∞`, `X = U = ℝ` and `T_t = Id` such that (i) `κ(t) = t` for `t ≥ 0`, +(ii) it has no integral representation, (iii) it is not `E_F`-admissible for any Young +function `F`. -/ +theorem no_representation : + ∃ S : ALCS ℝ ℝ ℝ ∞, + (∀ t : ℝ, 0 ≤ t → S.T t = ContinuousLinearMap.id ℝ ℝ) ∧ + (∀ t : ℝ, 0 ≤ t → ‖S.Φ t‖ = t) ∧ + ¬ HasIntegralRepresentation S ∧ + ∀ F : YoungFunction, ¬ EFAdmissible S F := by + obtain ⟨m, hm, hpos, h1, hT, hV⟩ := exists_strong_mean + obtain ⟨D⟩ := exists_local_control_from_mean m hpos h1 hT + exact ⟨D.system, counterexample_from_data D h1 hV⟩ + +end ExoticMean.Counterexample + +end +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Examples/Periodization.lean b/LeanPool/AbstractLinearControl/Examples/Periodization.lean new file mode 100644 index 0000000000..6955fb374a --- /dev/null +++ b/LeanPool/AbstractLinearControl/Examples/Periodization.lean @@ -0,0 +1,425 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Examples.ExoticMean + + +/-! +# Periodization and the invariant functional `J` (Step 1 of Proposition 3.3) + +Let `m` be a positive, normalized, translation-invariant mean on `L^∞_per` (Lemma 3.2). +For a bounded measurable `f` vanishing outside a bounded interval (`TestFunction`), its +periodization `P f (r) = Σ_{k ∈ ℤ} f (r + k)` is a finite sum for every `r`, and +`J(f) = m(P f)` is linear, positive and translation invariant. This file proves: + +* `mean_interval` : `J(1_{(a,b]}) = b - a` (equation `eq:J-intervals`); +* `mean_support_bound` : `|J(f)| ≤ (b - a) ‖f‖_∞` if `f` vanishes outside `(a, b]` + (equation `eq:J-bound`); +* `periodize_shifted`, `periodize_add`, `periodize_smul`, `raw_cell_recovery` : the + compatibility of `P` with translations, sums, scalars and periodic functions. + +All identities involving representatives hold almost everywhere; `ae_shifts` handles +the countably many integer translates of a null set at once. The paper uses intervals +`[a, b)`; here they are `(a, b]`, which only changes null sets. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +noncomputable section +open Set Filter MeasureTheory +open scoped ENNReal Topology BigOperators + +namespace ExoticMean.Periodization + +/-- A bounded measurable function `ℝ → ℝ` vanishing outside a bounded interval. -/ +structure TestFunction where + /-- The bounded measurable test function. -/ + val : ℝ → ℝ + measurable : StronglyMeasurable val + supported : ∃ n : ℕ, ∀ x, x ∉ Icc (-(n : ℝ)) n → val x = 0 + bounded : ∃ C : ℝ, ∀ᵐ x ∂volume, ‖val x‖ ≤ C + +/-- The periodization `P f (r) = Σ_{k ∈ ℤ} f (r + k)` (raw formula). -/ +def raw (f : ℝ → ℝ) (r : ℝ) : ℝ := ∑' k : ℤ, f (r + (k : ℝ)) + +/-- The integers `k` with `r + k ∈ [-n, n]`. -/ +def window (n : ℕ) (r : ℝ) : Finset ℤ := + Finset.Icc ⌈-(n : ℝ) - r⌉ ⌊(n : ℝ) - r⌋ + +lemma outside_window (f : TestFunction) {n : ℕ} + (hn : ∀ x, x ∉ Icc (-(n : ℝ)) n → f.val x = 0) + (r : ℝ) (k : ℤ) (hk : k ∉ window n r) : f.val (r + k) = 0 := by + apply hn + intro hx + apply hk + simp only [window, Finset.mem_Icc] + exact ⟨Int.ceil_le.mpr (by linarith [hx.1]), + Int.le_floor.mpr (by linarith [hx.2])⟩ + +lemma finite_shifts (f : TestFunction) (r : ℝ) : + Function.HasFiniteSupport (fun k : ℤ => f.val (r + k)) := by + obtain ⟨n, hn⟩ := f.supported + apply (window n r).finite_toSet.subset + intro k hk + by_contra h + exact hk (outside_window f hn r k h) + +lemma TestFunction.summable_shifts (f : TestFunction) (r : ℝ) : + Summable (fun k : ℤ => f.val (r + k)) := + summable_of_hasFiniteSupport (finite_shifts f r) + +lemma raw_eq_sum (f : TestFunction) {n : ℕ} + (hn : ∀ x, x ∉ Icc (-(n : ℝ)) n → f.val x = 0) (r : ℝ) : + raw f.val r = ∑ k ∈ window n r, f.val (r + k) := + tsum_eq_sum (outside_window f hn r) + +lemma window_card_le (n : ℕ) (r : ℝ) : (window n r).card ≤ 2 * n + 1 := by + have h : ⌊(n : ℝ) - r⌋ + 1 - ⌈-(n : ℝ) - r⌉ ≤ (2 * n + 1 : ℤ) := by + have hreal : (⌊(n : ℝ) - r⌋ : ℝ) + 1 - (⌈-(n : ℝ) - r⌉ : ℝ) ≤ + (2 * n + 1 : ℝ) := by + linarith [Int.floor_le ((n : ℝ) - r), Int.le_ceil (-(n : ℝ) - r)] + exact_mod_cast hreal + simp only [window, Int.card_Icc] + omega + +lemma raw_int_shift (f : ℝ → ℝ) (r : ℝ) (j : ℤ) : + raw f (r + j) = raw f r := by + unfold raw + convert (Equiv.addLeft j).tsum_eq (fun k : ℤ => f (r + k)) using 1 + congr 1 + funext k + congr 1 + change r + (j : ℝ) + (k : ℝ) = r + ((j + k : ℤ) : ℝ) + push_cast + ring + +lemma TestFunction.raw_measurable (f : TestFunction) : StronglyMeasurable (raw f.val) := by + apply StronglyMeasurable.tsum + intro k + exact f.measurable.comp_measurable (measurable_id.add measurable_const) + +/-- A single exceptional set covers all integer translates. -/ +lemma ae_shifts {p : ℝ → Prop} (hp : ∀ᵐ r ∂volume, p r) : + ∀ᵐ r ∂volume, ∀ k : ℤ, p (r + k) := by + apply ae_all_iff.mpr + intro k + exact (measurePreserving_add_right (volume : Measure ℝ) (k : ℝ)).quasiMeasurePreserving.ae hp + +lemma raw_bound (f : TestFunction) : ∃ C : ℝ, ∀ᵐ r ∂volume, ‖raw f.val r‖ ≤ C := by + obtain ⟨n, hn⟩ := f.supported + obtain ⟨C, hC⟩ := f.bounded + have hC0 : 0 ≤ C := by + obtain ⟨r, hr⟩ := hC.exists + exact (norm_nonneg _).trans hr + refine ⟨(2 * n + 1 : ℕ) * C, ?_⟩ + filter_upwards [ae_shifts hC] with r hr + rw [raw_eq_sum f hn] + calc + ‖∑ k ∈ window n r, f.val (r + k)‖ ≤ + ∑ k ∈ window n r, ‖f.val (r + k)‖ := norm_sum_le _ _ + _ ≤ ∑ _k ∈ window n r, C := Finset.sum_le_sum (fun k _ => hr k) + _ = (window n r).card * C := by simp + _ ≤ (2 * n + 1 : ℕ) * C := + mul_le_mul_of_nonneg_right (by exact_mod_cast window_card_le n r) hC0 + +lemma TestFunction.raw_memLp (f : TestFunction) : MemLp (raw f.val) ∞ volume := by + obtain ⟨C, hC⟩ := raw_bound f + exact memLp_top_of_bound f.raw_measurable.aestronglyMeasurable C hC + +/-- The periodization `P f`, as an element of `L^∞_per`. -/ +def periodize (f : TestFunction) : LinftyPer := + ⟨f.raw_memLp.toLp (raw f.val), by + apply Lp.ext + have hf := f.raw_memLp.coeFn_toLp + have hs := (measurePreserving_add_left (volume : Measure ℝ) (-1)).quasiMeasurePreserving.ae hf + filter_upwards [shift_ae 1 (f.raw_memLp.toLp (raw f.val)), hf, hs] with r h1 h2 h3 + rw [h1, h2, h3] + simpa [add_comm] using raw_int_shift f.val r (-1)⟩ + +lemma TestFunction.periodize_ae (f : TestFunction) : ⇑(periodize f).val =ᵐ[volume] raw f.val := + f.raw_memLp.coeFn_toLp + +lemma periodize_congr (f g : TestFunction) (heq : f.val =ᵐ[volume] g.val) : + periodize f = periodize g := by + apply Subtype.ext + apply Lp.ext + filter_upwards [f.periodize_ae, g.periodize_ae, ae_shifts heq] with r hf hg hr + rw [hf, hg] + exact tsum_congr hr + +lemma periodize_add (f g h : TestFunction) + (heq : f.val =ᵐ[volume] fun r => g.val r + h.val r) : + periodize f = periodize g + periodize h := by + apply Subtype.ext + apply Lp.ext + filter_upwards [f.periodize_ae, g.periodize_ae, h.periodize_ae, + Lp.coeFn_add (periodize g).val (periodize h).val, ae_shifts heq] with r hf hg hh ha he + change (periodize f).val r = ((periodize g).val + (periodize h).val) r + simp only [Pi.add_apply] at ha + rw [ha, hf, hg, hh] + unfold raw + rw [tsum_congr he, (g.summable_shifts r).tsum_add (h.summable_shifts r)] + +lemma periodize_smul (f g : TestFunction) (c : ℝ) + (heq : f.val =ᵐ[volume] fun r => c * g.val r) : + periodize f = c • periodize g := by + apply Subtype.ext + apply Lp.ext + filter_upwards [f.periodize_ae, g.periodize_ae, + Lp.coeFn_smul c (periodize g).val, ae_shifts heq] with r hf hg hs he + change (periodize f).val r = (c • (periodize g).val) r + simp only [Pi.smul_apply] at hs + rw [hf, hs, hg] + unfold raw + rw [tsum_congr he, tsum_mul_left] + rfl + +lemma periodize_le (f g : TestFunction) + (hle : ∀ᵐ r ∂volume, f.val r ≤ g.val r) : + ∀ᵐ r ∂volume, (periodize f).val r ≤ (periodize g).val r := by + filter_upwards [f.periodize_ae, g.periodize_ae, ae_shifts hle] with r hf hg hr + rw [hf, hg] + exact (f.summable_shifts r).tsum_le_tsum hr (g.summable_shifts r) + +lemma mean_le (m : LinftyPer →L[ℝ] ℝ) (hpos : Positive m.toLinearMap) + (f g : TestFunction) (hle : ∀ᵐ r ∂volume, f.val r ≤ g.val r) : + m (periodize f) ≤ m (periodize g) := by + have hp : ∀ᵐ r ∂volume, 0 ≤ (periodize g - periodize f).val r := by + filter_upwards [periodize_le f g hle, + Lp.coeFn_sub (periodize g).val (periodize f).val] with r hr hs + exact hs.symm ▸ sub_nonneg.mpr hr + have hm := hpos (periodize g - periodize f) hp + change 0 ≤ m (periodize g - periodize f) at hm + rw [map_sub] at hm + linarith + +/-- `1_{(a,b]} f`, for `f` bounded on `(a, b]`. -/ +def supportedInterval (a b : ℝ) (f : ℝ → ℝ) (hf : StronglyMeasurable f) + (C : ℝ) (hC : 0 ≤ C) + (hbound : ∀ᵐ r ∂volume, r ∈ Ioc a b → ‖f r‖ ≤ C) : TestFunction where + val := (Ioc a b).indicator f + measurable := hf.indicator measurableSet_Ioc + supported := by + obtain ⟨n, hn⟩ := exists_nat_gt (max |a| |b|) + refine ⟨n, ?_⟩ + intro r hr + apply indicator_of_notMem + intro hab + apply hr + have ha : |a| < (n : ℝ) := (le_max_left _ _).trans_lt hn + have hb : |b| < (n : ℝ) := (le_max_right _ _).trans_lt hn + exact ⟨by linarith [neg_abs_le a, hab.1], by linarith [le_abs_self b, hab.2]⟩ + bounded := by + refine ⟨C, ?_⟩ + filter_upwards [hbound] with r hr + by_cases hab : r ∈ Ioc a b + · simpa [hab] using hr hab + · simpa [hab] using hC + +/-- The constant `c` on `(a, b]`, zero elsewhere. -/ +def interval (a b c : ℝ) : TestFunction := + supportedInterval a b (fun _ => c) stronglyMeasurable_const ‖c‖ (norm_nonneg _) + (Eventually.of_forall (fun _ _ => le_rfl)) + +/-- The translate `f (· - a)`. -/ +def shifted (a : ℝ) (f : TestFunction) : TestFunction where + val r := f.val (-a + r) + measurable := f.measurable.comp_measurable (measurable_const.add measurable_id) + supported := by + obtain ⟨n, hn⟩ := f.supported + obtain ⟨N, hN⟩ := exists_nat_gt ((n : ℝ) + |a|) + refine ⟨N, ?_⟩ + intro r hr + apply hn + intro hx + apply hr + exact ⟨by linarith [neg_abs_le a, hx.1], by linarith [le_abs_self a, hx.2]⟩ + bounded := by + obtain ⟨C, hC⟩ := f.bounded + exact ⟨C, (measurePreserving_add_left (volume : Measure ℝ) (-a)).quasiMeasurePreserving.ae hC⟩ + +lemma periodize_shifted (a : ℝ) (f : TestFunction) : + periodize (shifted a f) = translate a (periodize f) := by + apply Subtype.ext + apply Lp.ext + have hs := (measurePreserving_add_left (volume : Measure ℝ) (-a)).quasiMeasurePreserving.ae + f.periodize_ae + filter_upwards [(shifted a f).periodize_ae, shift_ae a (periodize f).val, hs] + with r hf hg hh + change (periodize (shifted a f)).val r = (shift a (periodize f).val) r + rw [hf, hg, hh] + unfold raw + apply tsum_congr + intro k + change f.val (-a + (r + k)) = f.val ((-a + r) + k) + rw [add_assoc] + +lemma periodize_interval_shift (a b : ℝ) : + periodize (interval a b 1) = translate a (periodize (interval 0 (b - a) 1)) := by + rw [← periodize_shifted] + apply periodize_congr + apply Eventually.of_forall + intro r + change (Ioc a b).indicator (fun _ => (1 : ℝ)) r = + (Ioc 0 (b - a)).indicator (fun _ => (1 : ℝ)) (-a + r) + have heq : (-a + r ∈ Ioc 0 (b - a)) ↔ r ∈ Ioc a b := by + constructor <;> intro h <;> constructor <;> linarith [h.1, h.2] + simp only [Set.indicator, heq] + +lemma interval_split (a b c : ℝ) (hab : a ≤ b) (hbc : b ≤ c) : + (interval a c 1).val =ᵐ[volume] + fun r => (interval a b 1).val r + (interval b c 1).val r := by + apply Eventually.of_forall + intro r + change (Ioc a c).indicator (fun _ => (1 : ℝ)) r = + (Ioc a b).indicator (fun _ => (1 : ℝ)) r + + (Ioc b c).indicator (fun _ => (1 : ℝ)) r + by_cases h1 : a < r <;> by_cases h2 : r ≤ b <;> by_cases h3 : r ≤ c <;> + simp [Set.indicator, h1, h2, h3] <;> linarith + +lemma periodize_unit : periodize (interval 0 1 1) = one := by + apply Subtype.ext + apply Lp.ext + filter_upwards [(interval 0 1 1).periodize_ae, one_ae] with r hr h1 + rw [hr, h1] + obtain ⟨k, hk, huniq⟩ := existsUnique_add_zsmul_mem_Ioc (by norm_num : (0 : ℝ) < 1) r 0 + have hk' : r + (k : ℝ) ∈ Ioc (0 : ℝ) 1 := by simpa using hk + unfold raw + rw [tsum_eq_single k] + · change (Ioc (0 : ℝ) 1).indicator (fun _ => (1 : ℝ)) (r + k) = 1 + exact indicator_of_mem hk' _ + · intro j hj + change (Ioc (0 : ℝ) 1).indicator (fun _ => (1 : ℝ)) (r + j) = 0 + apply indicator_of_notMem + intro hjmem + apply hj + apply huniq + simpa using hjmem + +lemma raw_cell_recovery (f : ℝ → ℝ) (hf : Function.Periodic f 1) (r : ℝ) : + raw ((Ioc (0 : ℝ) 1).indicator f) r = f r := by + obtain ⟨k, hk, huniq⟩ := existsUnique_add_zsmul_mem_Ioc (by norm_num : (0 : ℝ) < 1) r 0 + have hk' : r + (k : ℝ) ∈ Ioc (0 : ℝ) 1 := by simpa using hk + unfold raw + rw [tsum_eq_single k] + · rw [indicator_of_mem hk'] + simpa using hf.int_mul k r + · intro j hj + apply indicator_of_notMem + intro hjmem + exact hj (huniq j (by simpa using hjmem)) + +/-- Interval calibration `J(1_{(a,b]}) = b - a` (equation `eq:J-intervals`), where +`J = m ∘ P`. The function `q(t) = J(1_{(0,t]})` is additive and monotone with `q(1) = 1`; +squeezing between integers gives `q(t) = t`. -/ +theorem mean_interval (m : LinftyPer →L[ℝ] ℝ) (hpos : Positive m.toLinearMap) + (h1 : m one = 1) (hT : ∀ a f, m (translate a f) = m f) + (a b : ℝ) (hab : a ≤ b) : m (periodize (interval a b 1)) = b - a := by + let q : ℝ → ℝ := fun t => m (periodize (interval 0 t 1)) + have q0 : q 0 = 0 := by + have hz : periodize (interval 0 0 1) = 0 := by + apply Subtype.ext + apply Lp.ext + filter_upwards [(interval 0 0 1).periodize_ae, Lp.coeFn_zero ℝ ∞ volume] with r hr hz + change (periodize (interval 0 0 1)).val r = (0 : Ambient) r + rw [hr, hz] + simp [raw, interval, supportedInterval] + simp [q, hz] + have q1 : q 1 = 1 := by simpa [q, periodize_unit] using h1 + have qadd (s t : ℝ) (hs : 0 ≤ s) (ht : 0 ≤ t) : q (s + t) = q s + q t := by + have hp := periodize_add (interval 0 (s + t) 1) (interval 0 s 1) + (interval s (s + t) 1) (interval_split 0 s (s + t) hs (by linarith)) + dsimp [q] + rw [hp, map_add, periodize_interval_shift s (s + t), hT] + simp + have qmono {s t : ℝ} (hst : s ≤ t) : q s ≤ q t := by + apply mean_le m hpos + apply Eventually.of_forall + intro r + change (Ioc 0 s).indicator (fun _ => (1 : ℝ)) r ≤ + (Ioc 0 t).indicator (fun _ => (1 : ℝ)) r + by_cases hr : r ∈ Ioc 0 s + · have ht : r ∈ Ioc 0 t := ⟨hr.1, hr.2.trans hst⟩ + simp [hr, ht] + · simp [hr, indicator_nonneg (fun _ _ => zero_le_one)] + have qmul (t : ℝ) (ht : 0 ≤ t) (n : ℕ) : q ((n : ℝ) * t) = n * q t := by + induction n with + | zero => simpa using q0 + | succ n ih => + rw [Nat.cast_add, Nat.cast_one, add_mul, one_mul, + qadd _ _ (mul_nonneg (Nat.cast_nonneg _) ht) ht, ih] + ring + have qnat (n : ℕ) : q n = n := by simpa [q1] using qmul 1 (by norm_num) n + have qeq (t : ℝ) (ht : 0 ≤ t) : q t = t := by + have squeeze (n : ℕ) : |q t - t| * n ≤ 1 := by + let k := ⌊(n : ℝ) * t⌋₊ + have hlow : (k : ℝ) ≤ (n : ℝ) * q t := by + rw [← qnat k, ← qmul t ht n] + exact qmono (Nat.floor_le (mul_nonneg (Nat.cast_nonneg _) ht)) + have hupp : (n : ℝ) * q t ≤ (k : ℝ) + 1 := by + rw [← qmul t ht n, ← Nat.cast_succ k, ← qnat (k + 1)] + apply qmono + simpa [k] using (Nat.lt_floor_add_one ((n : ℝ) * t)).le + have hk1 := Nat.floor_le (mul_nonneg (Nat.cast_nonneg n) ht) + have hk2 := Nat.lt_floor_add_one ((n : ℝ) * t) + change (k : ℝ) ≤ (n : ℝ) * t at hk1 + change (n : ℝ) * t < (k : ℝ) + 1 at hk2 + have heq : |q t - t| * (n : ℝ) = |(q t - t) * n| := by + rw [abs_mul, abs_of_nonneg (show 0 ≤ (n : ℝ) from Nat.cast_nonneg n)] + rw [heq] + rw [sub_mul] + exact abs_le.mpr ⟨by linarith only [hlow, hk2], by linarith only [hupp, hk1]⟩ + by_contra hne + have hd : 0 < |q t - t| := abs_pos.mpr (sub_ne_zero.mpr hne) + obtain ⟨n, hn⟩ := exists_nat_gt (1 / |q t - t|) + have hlarge := (div_lt_iff₀ hd).mp hn + have hsmall := squeeze n + linarith only [hlarge, hsmall] + rw [periodize_interval_shift, hT] + exact qeq (b - a) (sub_nonneg.mpr hab) + +/-- The support bound `eq:J-bound`: if `|f| ≤ C` on `(a, b]` and `f = 0` elsewhere, +then `|J(f)| ≤ (b - a) C`. -/ +theorem mean_support_bound (m : LinftyPer →L[ℝ] ℝ) (hpos : Positive m.toLinearMap) + (h1 : m one = 1) (hT : ∀ a f, m (translate a f) = m f) + (f : TestFunction) (a b C : ℝ) (hab : a ≤ b) (_hC : 0 ≤ C) + (hf : ∀ᵐ r ∂volume, ‖f.val r‖ ≤ (Ioc a b).indicator (fun _ => C) r) : + ‖m (periodize f)‖ ≤ (b - a) * C := by + have scaling (c : ℝ) : m (periodize (interval a b c)) = c * (b - a) := by + have heq := periodize_smul (interval a b c) (interval a b 1) c + (Eventually.of_forall (fun r => by + change (Ioc a b).indicator (fun _ => c) r = + c * (Ioc a b).indicator (fun _ => (1 : ℝ)) r + by_cases hr : r ∈ Ioc a b <;> simp [hr])) + rw [heq, map_smul, mean_interval m hpos h1 hT a b hab] + rfl + have hlo : m (periodize (interval a b (-C))) ≤ m (periodize f) := by + apply mean_le m hpos + filter_upwards [hf] with r hr + change (Ioc a b).indicator (fun _ => -C) r ≤ f.val r + rw [Real.norm_eq_abs] at hr + by_cases hm : r ∈ Ioc a b + · simpa [hm] using (abs_le.mp hr).1 + · simp only [indicator_of_notMem hm] at * + simpa using (abs_le.mp hr).1 + have hhi : m (periodize f) ≤ m (periodize (interval a b C)) := by + apply mean_le m hpos + filter_upwards [hf] with r hr + exact (le_abs_self _).trans hr + rw [scaling] at hlo hhi + rw [Real.norm_eq_abs] + apply abs_le.mpr + constructor <;> nlinarith + +end ExoticMean.Periodization + +end +end + +end AbstractLinearControl diff --git a/LeanPool/AbstractLinearControl/Imports.lean b/LeanPool/AbstractLinearControl/Imports.lean new file mode 100644 index 0000000000..48a8936065 --- /dev/null +++ b/LeanPool/AbstractLinearControl/Imports.lean @@ -0,0 +1,22 @@ +/- +Copyright (c) 2026 Lean Pool contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Lean Pool contributors +-/ +module -- shake: keep-all --deprecated_module: ignore + +-- Generated project imports; run `lake exe mk_all`. +public import LeanPool.AbstractLinearControl +public import LeanPool.AbstractLinearControl.Background.InvariantHahnBanach +public import LeanPool.AbstractLinearControl.Background.Linfty +public import LeanPool.AbstractLinearControl.Background.Lp +public import LeanPool.AbstractLinearControl.Background.Phillips +public import LeanPool.AbstractLinearControl.Background.Semigroup +public import LeanPool.AbstractLinearControl.ContinuityFiniteP +public import LeanPool.AbstractLinearControl.ContinuityLinfty +public import LeanPool.AbstractLinearControl.Definitions +public import LeanPool.AbstractLinearControl.Examples.ExoticMean +public import LeanPool.AbstractLinearControl.Examples.FinitePNotZeroClass +public import LeanPool.AbstractLinearControl.Examples.NoRepresentation +public import LeanPool.AbstractLinearControl.Examples.Periodization +public import LeanPool.AbstractLinearControl.ZeroClass diff --git a/LeanPool/AbstractLinearControl/ZeroClass.lean b/LeanPool/AbstractLinearControl/ZeroClass.lean new file mode 100644 index 0000000000..7832635c77 --- /dev/null +++ b/LeanPool/AbstractLinearControl/ZeroClass.lean @@ -0,0 +1,724 @@ +/- +Copyright (c) 2026 Frédéric Marbach. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Marbach +-/ +module + +public import LeanPool.AbstractLinearControl.Definitions +public import LeanPool.AbstractLinearControl.Background.Phillips + + +/-! +# Every `L^∞` system is zero-class (Theorem 1.5) + +**Theorem 1.5** (`thm:p-infty-zero-class`). Let `X`, `U` be Banach spaces and `(𝕋, Φ)` +an abstract linear control system with `p = ∞`. Then the system is of the zero-class, +i.e. `‖Φ_t‖ → 0` as `t → 0`. + +The final statement is `ALCS.zero_class`, at the end of this file. The auxiliary +declarations live in the namespace `ALCS.ZeroClassProof` and follow § 2.3 of the paper: + +* `ell` is the limit `ℓ = lim_{t → 0⁺} κ(t) = inf_{t > 0} κ(t)` (`eq:ell`), and + `norm_Phi_tendsto` identifies it as the limit along any positive null sequence. +* Step 1, `doubling`: the doubling inequality `eq:doubling`, + `2 ‖Φ_h u‖ ≤ κ(2h) + ‖(T_h - Id) Φ_h u‖` for `‖u‖ ≤ 1`. +* Step 2, `data`, `h`, `x`: nearly extremal pulses `u_n` on rapidly decreasing time + scales `h_n`, with states `x_n = Φ_{h_n} u_n` (`eq:xn-extremal`, `eq:hn-fast`). +* Step 3, `packing`, `packedOperator`: the pulses are packed into one bounded operator + `S : ℓ^∞ → X`, and `packedOperator_close` is `eq:Sen-xn`. +* Step 4, `x_moves_tendsto`: Lemma 2.3 (`Phillips.uniform`) gives + `‖(T_{h_n} - Id) x_n‖ → 0`, which is the second half of `eq:goal`. + +## Difference with the paper in Step 3 + +The paper plays the pulses one after the other on consecutive intervals +`[s_n, s_{n+1})` and evaluates at the accumulated time `H = Σ h_k`. Here each pulse +gets its own *free-evolution time* `r_n ∈ (0, h_n]`, chosen in Step 2 so that +`‖T_{r_n} x_n - x_n‖ ≤ 2^{-n}`, and the `n`-th pulse is played on +`[1 - r_n - h_n, 1 - r_n)`, with zero input in the gaps; the operator is evaluated at +time `1`. Then `S e_n = T_{r_n} x_n` exactly. This changes the bookkeeping, not the +argument. The scalar field is `ℝ` or `ℂ` (`RCLike 𝕜`), as required by Phillips' lemma. +-/ + +namespace AbstractLinearControl + +@[expose] public section + +open MeasureTheory Filter Topology +open scoped ENNReal + +noncomputable section + +section Endpoint + +open scoped BigOperators + +variable {𝕜 : Type*} [RCLike 𝕜] +variable {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] +variable {U : Type*} [NormedAddCommGroup U] [NormedSpace 𝕜 U] + +namespace ALCS +namespace ZeroClassProof + +/-! ### Step 1: the doubling inequality -/ + +variable (S : ALCS 𝕜 X U ∞) + +/-- Step 1, the doubling inequality `eq:doubling`: for `h ≥ 0` and `‖u‖ ≤ 1`, +`2 ‖Φ_h u‖ ≤ κ(2h) + ‖T_h (Φ_h u) - Φ_h u‖`, obtained by playing `u` twice in a row. -/ +lemma doubling {h : ℝ} (hh : 0 ≤ h) (u : Lp U ∞ muPlus) + (hu : ‖u‖ ≤ 1) : + 2 * ‖S.Φ h u‖ ≤ ‖S.Φ (2 * h)‖ + + ‖S.T h (S.Φ h u) - S.Φ h u‖ := by + obtain ⟨w, hw, hcat⟩ := exists_concat h u u (by norm_num) hu hu + have hcomp := S.composition h h hh hh u u w hcat + have hnorm : ‖S.Φ (2 * h) w‖ ≤ ‖S.Φ (2 * h)‖ := by + exact ((S.Φ (2 * h)).le_opNorm w).trans + (by simpa using mul_le_mul_of_nonneg_left hw (norm_nonneg (S.Φ (2 * h)))) + let x := S.Φ h u + have hid : x + x = S.Φ (2 * h) w - (S.T h x - x) := by + rw [show 2 * h = h + h by ring, hcomp] + dsimp [x] + abel + have htwo : ‖x + x‖ = 2 * ‖x‖ := by + calc + ‖x + x‖ = ‖(2 : 𝕜) • x‖ := by rw [two_smul] + _ = ‖(2 : 𝕜)‖ * ‖x‖ := norm_smul _ _ + _ = 2 * ‖x‖ := by rw [show ‖(2 : 𝕜)‖ = 2 from RCLike.norm_natCast 2] + calc + 2 * ‖S.Φ h u‖ = ‖x + x‖ := htwo.symm + _ ≤ ‖S.Φ (2 * h) w‖ + ‖S.T h x - x‖ := by + rw [hid] + exact norm_sub_le _ _ + _ ≤ ‖S.Φ (2 * h)‖ + ‖S.T h x - x‖ := add_le_add hnorm le_rfl + +/-! ### Step 2: nearly extremal pulses on rapidly decreasing time scales -/ + +/-- An input of norm at most one which almost realizes `κ(h) = ‖Φ h‖`. -/ +lemma exists_near_extremal (h ε : ℝ) (hε : 0 < ε) : + ∃ u : Lp U ∞ muPlus, ‖u‖ ≤ 1 ∧ ‖S.Φ h‖ - ε ≤ ‖S.Φ h u‖ := by + by_cases hc : ‖S.Φ h‖ - ε ≤ 0 + · exact ⟨0, by simp, by simpa using hc⟩ + · by_contra hn + have hbound : ‖S.Φ h‖ ≤ ‖S.Φ h‖ - ε := by + apply ContinuousLinearMap.opNorm_le_of_unit_norm (le_of_lt (lt_of_not_ge hc)) + intro u hu + exact (lt_of_not_ge (fun h => hn ⟨u, hu.le, h⟩)).le + linarith + +/-- A *pulse* of length `h`: a control of norm at most one, given by an actual +(everywhere defined) representative vanishing outside `[0, h)`. -/ +structure Pulse (U : Type*) [NormedAddCommGroup U] (h : ℝ) where + /-- the representative -/ + f : ℝ → U + measurable : StronglyMeasurable f + bound : ∀ t, ‖f t‖ ≤ 1 + off : ∀ t, t < 0 ∨ h ≤ t → f t = 0 + +namespace Pulse + +variable {h : ℝ} (P : Pulse U h) + +/-- The pulse, as an element of `L^∞(ℝ₊; U)`. -/ +def input : Lp U ∞ muPlus := + (memLp_of_bound P.measurable P.bound).toLp P.f + +lemma coe_input : ⇑P.input =ᵐ[muPlus] P.f := + (memLp_of_bound P.measurable P.bound).coeFn_toLp + +lemma norm_input : ‖P.input‖ ≤ 1 := + norm_toLp_le _ (by norm_num) P.bound + +/-- A pulse of length `h` is switched off after time `h`: `P = P ⋄_h 0`. -/ +lemma free_rep : ⇑P.input =ᵐ[muPlus] + concat h ⇑P.input ⇑(0 : Lp U ∞ muPlus) := by + have hraw : P.f = concat h P.f (fun _ => (0 : U)) := by + funext t + by_cases ht : t < h + · simp [concat, ht] + · simp [concat, ht, P.off t (Or.inr (not_lt.1 ht))] + exact P.coe_input.trans + ((Filter.EventuallyEq.of_eq hraw).trans + (concat_congr h P.coe_input (Lp.coeFn_zero U ∞ muPlus)).symm) + +end Pulse + +/-- A nearly extremal input can be chosen to be a pulse (by causality `eq:causality`, +truncating it at time `h` does not change `Φ_h u`). -/ +lemma exists_pulse (h : ℝ) (hh : 0 ≤ h) (ε : ℝ) (hε : 0 < ε) : + ∃ P : Pulse U h, ‖S.Φ h‖ - ε ≤ ‖S.Φ h P.input‖ := by + obtain ⟨u, hu, hnear⟩ := exists_near_extremal S h ε hε + obtain ⟨g, hg, hgb, hug⟩ := exists_bounded_rep u (by norm_num) hu + let f := (Set.Ico 0 h).indicator g + have hf : StronglyMeasurable f := hg.indicator measurableSet_Ico + have hb : ∀ t, ‖f t‖ ≤ 1 := by + intro t + by_cases ht : t ∈ Set.Ico 0 h + · simpa [f, Set.indicator_of_mem ht] using hgb t + · simp [f, Set.indicator_of_notMem ht] + have hoff : ∀ t, t < 0 ∨ h ≤ t → f t = 0 := by + intro t ht + have hnot : t ∉ Set.Ico 0 h := by + intro hin + rcases ht with ht | ht + · exact (not_lt_of_ge hin.1) ht + · exact (not_lt_of_ge ht) hin.2 + exact Set.indicator_of_notMem hnot g + let P : Pulse U h := ⟨f, hf, hb, hoff⟩ + have hraw : f =ᵐ[muPlus] concat h g (fun _ => (0 : U)) := by + have hpos : ∀ᵐ t ∂muPlus, t ∈ Set.Ici (0 : ℝ) := + ae_restrict_mem measurableSet_Ici + filter_upwards [hpos] with t ht + have ht0 : 0 ≤ t := ht + by_cases hth : t < h + · simp [f, concat, hth, Set.mem_Ico, ht0] + · simp [f, concat, hth, Set.mem_Ico] + have hcat : ⇑P.input =ᵐ[muPlus] concat h ⇑u ⇑(0 : Lp U ∞ muPlus) := + P.coe_input.trans (hraw.trans (concat_congr h hug (Lp.coeFn_zero U ∞ muPlus)).symm) + refine ⟨P, ?_⟩ + rwa [S.causality h hh u 0 P.input hcat] + +/-- The accuracy `2^{-n}` of the `n`-th selection. -/ +def err (n : ℕ) : ℝ := (1 / 2 : ℝ) ^ n + +lemma err_pos (n : ℕ) : 0 < err n := by + unfold err + positivity + +lemma err_tendsto : Tendsto err atTop (𝓝 0) := by + exact tendsto_pow_atTop_nhds_zero_of_lt_one (by norm_num) (by norm_num) + +/-- The data selected at step `n` of Step 2: a nearly extremal pulse of length `h` +(`eq:xn-extremal`), and a free-evolution time `r ∈ (0, h]` during which its state is +essentially frozen by the semigroup (the analogue of `eq:hn-fast`). -/ +structure FrozenPulse (S : ALCS 𝕜 X U ∞) (n : ℕ) (h : ℝ) where + /-- The bounded input pulse whose output nearly attains the operator norm. -/ + pulse : Pulse U h + near : ‖S.Φ h‖ - err n ≤ ‖S.Φ h pulse.input‖ + /-- the free-evolution time -/ + r : ℝ + r_pos : 0 < r + r_le : r ≤ h + close : ‖S.T r (S.Φ h pulse.input) - S.Φ h pulse.input‖ ≤ err n + +lemma frozenPulse_nonempty (n : ℕ) (h : ℝ) (hh : 0 < h) : + Nonempty (FrozenPulse S n h) := by + obtain ⟨P, hP⟩ := exists_pulse S h hh.le (err n) (err_pos n) + obtain ⟨δ, hδ, hc⟩ := Metric.tendsto_nhdsWithin_nhds.1 + (S.T_cont (S.Φ h P.input)) (err n) (err_pos n) + let r := min h (δ / 2) + have hr : 0 < r := lt_min hh (by positivity) + have hrh : r ≤ h := min_le_left _ _ + have hrδ : r < δ := lt_of_le_of_lt (min_le_right _ _) (by linarith) + refine ⟨⟨P, hP, r, hr, hrh, ?_⟩⟩ + have hc' := hc (Set.mem_Ici.2 hr.le) + (show dist r 0 < δ by simpa [Real.dist_eq, abs_of_pos hr] using hrδ) + have hclose : ‖S.T r (S.Φ h P.input) - S.Φ h P.input‖ < err n := by + simpa only [dist_eq_norm] using hc' + exact hclose.le + +/-- Classical choice is used only to choose actual witnesses to proved existences. -/ +def choosePulse (n : ℕ) (h : ℝ) (hh : 0 < h) : FrozenPulse S n h := + Classical.choice (frozenPulse_nonempty S n h hh) + +/-- The time scales, defined recursively: `h 0 = 1/4` and `h (n + 1) = r n / 4`, so that +the next pulse fits inside the free-evolution interval of the previous one. -/ +def positiveTimes : ℕ → {h : ℝ // 0 < h} := + Nat.rec ⟨1 / 4, by norm_num⟩ + (fun n h => + ⟨(choosePulse S n h.1 h.2).r / 4, + div_pos (choosePulse S n h.1 h.2).r_pos (by norm_num)⟩) + +/-- The time scale `h_n`. -/ +def h (n : ℕ) : ℝ := (positiveTimes S n).1 + +/-- The pulse `u_n` and the free-evolution time `r_n` selected at step `n`. -/ +def data (n : ℕ) : FrozenPulse S n (h S n) := + choosePulse S n (h S n) (positiveTimes S n).2 + +/-- The free-evolution time `r_n ∈ (0, h_n]`. -/ +def r (n : ℕ) : ℝ := (data S n).r + +/-- The state `x_n = Φ_{h_n} u_n`. -/ +def x (n : ℕ) : X := S.Φ (h S n) (data S n).pulse.input + +lemma h_pos (n : ℕ) : 0 < h S n := (positiveTimes S n).2 +lemma r_pos (n : ℕ) : 0 < r S n := (data S n).r_pos +lemma r_le_h (n : ℕ) : r S n ≤ h S n := (data S n).r_le +lemma h_zero : h S 0 = 1 / 4 := rfl +lemma h_succ (n : ℕ) : h S (n + 1) = r S n / 4 := rfl + +lemma h_succ_le (n : ℕ) : h S (n + 1) ≤ h S n / 2 := by + rw [h_succ] + have := r_le_h S n + have := (h_pos S n).le + linarith + +lemma h_le_quarter (n : ℕ) : h S n ≤ 1 / 4 := by + induction n with + | zero => simp [h_zero] + | succ n ih => + have := h_succ_le S n + linarith + +lemma h_geometric (n : ℕ) : h S n ≤ err n / 4 := by + induction n with + | zero => simp [h_zero, err] + | succ n ih => + have := h_succ_le S n + dsimp [err] at ih ⊢ + rw [pow_succ] + linarith + +lemma h_tendsto : Tendsto (h S) atTop (𝓝 0) := by + exact squeeze_zero (fun n => (h_pos S n).le) (h_geometric S) + (by simpa using err_tendsto.div_const 4) + +lemma x_near (n : ℕ) : ‖S.Φ (h S n)‖ - err n ≤ ‖x S n‖ := + (data S n).near + +lemma x_le (n : ℕ) : ‖x S n‖ ≤ ‖S.Φ (h S n)‖ := by + exact ((S.Φ (h S n)).le_opNorm _).trans + (by simpa using + mul_le_mul_of_nonneg_left (data S n).pulse.norm_input (norm_nonneg (S.Φ (h S n)))) + +lemma x_frozen (n : ℕ) : ‖S.T (r S n) (x S n) - x S n‖ ≤ err n := + (data S n).close + +/-! ### Step 3: packing the pulses into one bounded operator `ℓ^∞ → X` -/ + +/-- The `n`-th pulse is played on `window n = [start n, start n + h n)`, where +`start n = 1 - r n - h n`. These windows are pairwise disjoint subsets of `[0, 1)`. -/ +def start (n : ℕ) : ℝ := 1 - r S n - h S n + +/-- The interval on which the `n`-th pulse is played. -/ +def window (n : ℕ) : Set ℝ := Set.Ico (start S n) (start S n + h S n) + +/-- The `n`-th pulse, delayed so that it is played on `window n`. -/ +def block (n : ℕ) (t : ℝ) : U := (data S n).pulse.f (t - start S n) + +lemma start_nonneg (n : ℕ) : 0 ≤ start S n := by + have := r_le_h S n + have := h_le_quarter S n + dsimp [start] + linarith + +lemma finish_le_next (n : ℕ) : start S n + h S n ≤ start S (n + 1) := by + have h₁ := r_le_h S (n + 1) + have h₂ := h_succ S n + have h₃ := (r_pos S n).le + dsimp [start] + linarith + +lemma start_mono : Monotone (start S) := by + apply monotone_nat_of_le_succ + intro n + have := finish_le_next S n + have := (h_pos S n).le + linarith + +lemma finish_le_start {i j : ℕ} (hij : i < j) : + start S i + h S i ≤ start S j := + (finish_le_next S i).trans (start_mono S (Nat.succ_le_of_lt hij)) + +lemma window_unique {i j : ℕ} {t : ℝ} + (hi : t ∈ window S i) (hj : t ∈ window S j) : i = j := by + rcases lt_trichotomy i j with hij | hij | hji + · have := finish_le_start S hij + have hi' := hi.2 + have hj' := hj.1 + linarith + · exact hij + · have := finish_le_start S hji + have hj' := hj.2 + have hi' := hi.1 + linarith + +lemma block_measurable (n : ℕ) : StronglyMeasurable (block S n) := + (data S n).pulse.measurable.comp_measurable (measurable_id.sub_const _) + +lemma block_bound (n : ℕ) (t : ℝ) : ‖block S n t‖ ≤ 1 := + (data S n).pulse.bound _ + +lemma block_off (n : ℕ) {t : ℝ} (ht : t ∉ window S n) : block S n t = 0 := by + apply (data S n).pulse.off + by_cases hs : t < start S n + · left + linarith + · right + by_contra hh + apply ht + constructor + · exact not_lt.1 hs + · change t < start S n + h S n + linarith + +/-- The packed control `u^α` (raw function): on `window n` it is `α_n` times the `n`-th +pulse, and it vanishes outside the windows. -/ +def packRaw (a : Phillips.Linfty 𝕜) : ℝ → U := by + classical + exact fun t => if ht : ∃ n, t ∈ window S n then + a (Classical.choose ht) • block S (Classical.choose ht) t else 0 + +lemma packRaw_on (a : Phillips.Linfty 𝕜) {n : ℕ} {t : ℝ} + (ht : t ∈ window S n) : packRaw S a t = a n • block S n t := by + classical + have hex : ∃ j, t ∈ window S j := ⟨n, ht⟩ + have heq : Classical.choose hex = n := + window_unique S (Classical.choose_spec hex) ht + simp only [packRaw, dite_eq_left hex, heq] + +lemma packRaw_off (a : Phillips.Linfty 𝕜) {t : ℝ} + (ht : ¬ ∃ n, t ∈ window S n) : packRaw S a t = 0 := by + classical + simp [packRaw, ht] + +lemma packRaw_add (a b : Phillips.Linfty 𝕜) (t : ℝ) : + packRaw S (a + b) t = packRaw S a t + packRaw S b t := by + classical + by_cases ht : ∃ n, t ∈ window S n + · obtain ⟨n, hn⟩ := ht + rw [packRaw_on S (a + b) hn, packRaw_on S a hn, packRaw_on S b hn] + simp only [BoundedContinuousFunction.add_apply, add_smul] + · simp only [packRaw_off S (a + b) ht, packRaw_off S a ht, + packRaw_off S b ht, add_zero] + +lemma packRaw_smul (c : 𝕜) (a : Phillips.Linfty 𝕜) (t : ℝ) : + packRaw S (c • a) t = c • packRaw S a t := by + classical + by_cases ht : ∃ n, t ∈ window S n + · obtain ⟨n, hn⟩ := ht + rw [packRaw_on S (c • a) hn, packRaw_on S a hn] + simp only [BoundedContinuousFunction.smul_apply, smul_eq_mul, smul_smul] + · simp only [packRaw_off S (c • a) ht, packRaw_off S a ht, smul_zero] + +lemma packRaw_bound (a : Phillips.Linfty 𝕜) (t : ℝ) : + ‖packRaw S a t‖ ≤ ‖a‖ := by + classical + by_cases ht : ∃ n, t ∈ window S n + · obtain ⟨n, hn⟩ := ht + rw [packRaw_on S a hn, norm_smul] + have ha : ‖a n‖ ≤ ‖a‖ := + (BoundedContinuousFunction.norm_le (norm_nonneg a)).1 le_rfl n + calc + ‖a n‖ * ‖block S n t‖ ≤ ‖a n‖ * 1 := + mul_le_mul_of_nonneg_left (block_bound S n t) (norm_nonneg _) + _ ≤ ‖a‖ := by simpa using ha + · rw [packRaw_off S a ht, norm_zero] + exact norm_nonneg _ + +/-- At every time the partial sums eventually equal the glued function. This +uses pointwise disjointness, not convergence of a series in the L-infinity norm. -/ +lemma partial_sums_eventually (a : Phillips.Linfty 𝕜) (t : ℝ) : + ∀ᶠ N : ℕ in atTop, + (∑ n ∈ Finset.range N, a n • block S n t) = packRaw S a t := by + classical + by_cases ht : ∃ n, t ∈ window S n + · obtain ⟨n, hn⟩ := ht + filter_upwards [eventually_ge_atTop (n + 1)] with N hN + rw [packRaw_on S a hn] + apply Finset.sum_eq_single n + · intro j _ hjn + have hj : t ∉ window S j := + fun hj => hjn (window_unique S hj hn) + simp [block_off S j hj] + · intro hnN + exact (hnN (Finset.mem_range.2 (by omega))).elim + · filter_upwards [] with N + rw [packRaw_off S a ht] + apply Finset.sum_eq_zero + intro n _ + have hn : t ∉ window S n := fun hn => ht ⟨n, hn⟩ + simp [block_off S n hn] + +lemma packRaw_measurable (a : Phillips.Linfty 𝕜) : + StronglyMeasurable (packRaw S a) := by + classical + apply stronglyMeasurable_of_tendsto atTop + (f := fun N t => ∑ n ∈ Finset.range N, a n • block S n t) + · intro N + exact Finset.stronglyMeasurable_fun_sum (Finset.range N) + (fun n _ => (block_measurable S n).const_smul (a n)) + · apply tendsto_pi_nhds.2 + intro t + exact tendsto_const_nhds.congr' (Filter.EventuallyEq.symm (partial_sums_eventually S a t)) + +lemma packRaw_memLp (a : Phillips.Linfty 𝕜) : MemLp (packRaw S a) ∞ muPlus := + memLp_of_bound (packRaw_measurable S a) (packRaw_bound S a) + +/-- The packed control `u^α ∈ L^∞(ℝ₊; U)`. -/ +def packedInput (a : Phillips.Linfty 𝕜) : Lp U ∞ muPlus := + (packRaw_memLp S a).toLp (packRaw S a) + +lemma packedInput_ae (a : Phillips.Linfty 𝕜) : + ⇑(packedInput S a) =ᵐ[muPlus] packRaw S a := + (packRaw_memLp S a).coeFn_toLp + +lemma packedInput_norm (a : Phillips.Linfty 𝕜) : ‖packedInput S a‖ ≤ ‖a‖ := + norm_toLp_le _ (norm_nonneg _) (packRaw_bound S a) + +lemma packedInput_add (a b : Phillips.Linfty 𝕜) : + packedInput S (a + b) = packedInput S a + packedInput S b := by + apply Lp.ext + filter_upwards [packedInput_ae S (a + b), packedInput_ae S a, + packedInput_ae S b, Lp.coeFn_add (packedInput S a) (packedInput S b)] + with t hab ha hb hsum + rw [hab, hsum] + simpa only [Pi.add_apply, ha, hb] using packRaw_add S a b t + +lemma packedInput_smul (c : 𝕜) (a : Phillips.Linfty 𝕜) : + packedInput S (c • a) = c • packedInput S a := by + apply Lp.ext + filter_upwards [packedInput_ae S (c • a), packedInput_ae S a, + Lp.coeFn_smul c (packedInput S a)] with t hca ha hsmul + rw [hca, hsmul] + simpa only [Pi.smul_apply, ha] using packRaw_smul S c a t + +/-- The contraction `α ↦ u^α` from `ℓ^∞` to `L^∞(ℝ₊; U)`. -/ +def packing : Phillips.Linfty 𝕜 →L[𝕜] Lp U ∞ muPlus := + LinearMap.mkContinuous + { toFun := packedInput S + map_add' := packedInput_add S + map_smul' := fun c a => by + simpa using packedInput_smul S c a } + 1 (fun a => by simpa using packedInput_norm S a) + +lemma packing_ae (a : Phillips.Linfty 𝕜) : + ⇑(packing S a) =ᵐ[muPlus] packRaw S a := packedInput_ae S a + +lemma packRaw_e (n : ℕ) (t : ℝ) : + packRaw S (Phillips.e n) t = block S n t := by + classical + by_cases hn : t ∈ window S n + · rw [packRaw_on S _ hn] + simp + · rw [block_off S n hn] + by_cases ht : ∃ j, t ∈ window S j + · obtain ⟨j, hj⟩ := ht + have hjn : j ≠ n := by + intro heq + subst j + exact hn hj + rw [packRaw_on S _ hj] + simp [Phillips.e_apply, hjn] + · exact packRaw_off S _ ht + +/-- The operator `S : ℓ^∞ → X`, `S α = Φ_1 u^α`. -/ +def packedOperator : Phillips.Linfty 𝕜 →L[𝕜] X := + (S.Φ 1).comp (packing S) + +/-- `S e_n = T_{r_n} x_n`: the `n`-th state, after it has evolved freely during the +time `r_n` (by `eq:delay` and then `eq:free`). -/ +lemma packedOperator_e (n : ℕ) : + packedOperator S (Phillips.e n) = S.T (r S n) (x S n) := by + let P := (data S n).pulse + have hraw : packRaw S (Phillips.e n) = + concat (start S n) (fun _ => (0 : U)) P.f := by + funext t + rw [packRaw_e] + by_cases ht : t < start S n + · have hoff : P.f (t - start S n) = 0 := + P.off _ (Or.inl (by linarith)) + simpa [concat, ht, block, P] using hoff + · simp [concat, ht, block, P] + have hw : ⇑(packing S (Phillips.e n)) =ᵐ[muPlus] + concat (start S n) ⇑(0 : Lp U ∞ muPlus) ⇑P.input := + (packing_ae S _).trans + ((Filter.EventuallyEq.of_eq hraw).trans + (concat_congr (start S n) (Lp.coeFn_zero U ∞ muPlus) P.coe_input).symm) + have hsum : start S n + (h S n + r S n) = 1 := by + unfold start + ring + change S.Φ 1 (packing S (Phillips.e n)) = _ + rw [← hsum] + rw [S.delay (start S n) (h S n + r S n) (start_nonneg S n) + (add_nonneg (h_pos S n).le (r_pos S n).le) P.input _ hw] + exact S.free (h S n) (r S n) (h_pos S n).le (r_pos S n).le + P.input P.input P.free_rep + +/-- `‖S e_n - x_n‖ ≤ 2^{-n}`, equation `eq:Sen-xn`. -/ +lemma packedOperator_close (n : ℕ) : + ‖packedOperator S (Phillips.e n) - x S n‖ ≤ err n := by + rw [packedOperator_e] + exact x_frozen S n + +/-! ### The limit `ℓ` of `κ(t)` as `t → 0⁺` (`eq:ell`) -/ + +/-- The possible input-map norms at strictly positive times. -/ +def normRange : Set ℝ := (fun t : ℝ => ‖S.Φ t‖) '' Set.Ioi 0 + +lemma normRange_nonempty : (normRange S).Nonempty := + ⟨‖S.Φ 1‖, 1, by norm_num, rfl⟩ + +lemma normRange_bddBelow : BddBelow (normRange S) := by + refine ⟨0, ?_⟩ + rintro y ⟨t, _, rfl⟩ + exact norm_nonneg _ + +/-- `ℓ = inf_{t > 0} κ(t)`, equation `eq:ell`. -/ +def ell : ℝ := sInf (normRange S) + +lemma ell_nonneg : 0 ≤ ell S := by + apply le_csInf (normRange_nonempty S) + rintro y ⟨t, _, rfl⟩ + exact norm_nonneg _ + +lemma ell_le (t : ℝ) (ht : 0 < t) : ell S ≤ ‖S.Φ t‖ := + csInf_le (normRange_bddBelow S) ⟨t, ht, rfl⟩ + +lemma exists_norm_lt (ε : ℝ) (hε : 0 < ε) : + ∃ t : ℝ, 0 < t ∧ ‖S.Φ t‖ < ell S + ε := by + by_contra hn + have hbad : ell S + ε ≤ ell S := by + apply le_csInf (normRange_nonempty S) + rintro y ⟨t, ht, rfl⟩ + exact le_of_not_gt (fun hlt => hn ⟨t, ht, hlt⟩) + linarith + +/-- Monotonicity identifies the norm limit along every positive null sequence. -/ +lemma norm_Phi_tendsto (t : ℕ → ℝ) (htpos : ∀ n, 0 < t n) + (ht : Tendsto t atTop (𝓝 0)) : + Tendsto (fun n => ‖S.Φ (t n)‖) atTop (𝓝 (ell S)) := by + rw [Metric.tendsto_atTop] + intro ε hε + obtain ⟨τ, hτ, hτnorm⟩ := exists_norm_lt S ε hε + obtain ⟨N, hN⟩ := Metric.tendsto_atTop.1 ht τ hτ + refine ⟨N, fun n hn => ?_⟩ + have htn : t n < τ := by + have hdist := hN n hn + simpa only [Real.dist_eq, sub_zero, abs_of_pos (htpos n)] using hdist + have hupper := norm_Phi_mono S (htpos n).le htn.le + have hlower := ell_le S (t n) (htpos n) + rw [Real.dist_eq, abs_of_nonneg (sub_nonneg.2 hlower)] + linarith + +/-- First half of `eq:goal`: `‖x_n‖ → ℓ`. -/ +lemma x_norm_tendsto : Tendsto (fun n => ‖x S n‖) atTop (𝓝 (ell S)) := by + have hk := norm_Phi_tendsto S (h S) (h_pos S) (h_tendsto S) + rw [Metric.tendsto_atTop] + intro ε hε + obtain ⟨N₁, hN₁⟩ := Metric.tendsto_atTop.1 hk ε hε + obtain ⟨N₂, hN₂⟩ := Metric.tendsto_atTop.1 err_tendsto ε hε + refine ⟨max N₁ N₂, fun n hn => ?_⟩ + have hkdist := hN₁ n (le_trans (le_max_left _ _) hn) + have hedist := hN₂ n (le_trans (le_max_right _ _) hn) + have hkabs : |‖S.Φ (h S n)‖ - ell S| < ε := by + simpa only [Real.dist_eq] using hkdist + have he : err n < ε := by + simpa only [Real.dist_eq, sub_zero, abs_of_pos (err_pos n)] using hedist + have hupper := x_le S n + have hnear := x_near S n + have hlower := ell_le S (h S n) (h_pos S n) + rw [Real.dist_eq] + obtain ⟨_, hkright⟩ := abs_lt.1 hkabs + exact abs_lt.2 ⟨by linarith, by linarith⟩ + +/-! ### Step 4: conclusion with Lemma 2.3 -/ + +/-- Second half of `eq:goal`: `‖T_{h_n} x_n - x_n‖ → 0`. By Lemma 2.3 +(`Phillips.uniform`), `‖(T_{h_n} - Id) S e_n‖ → 0`, and `S e_n` is `2^{-n}`-close to `x_n`. -/ +lemma x_moves_tendsto [CompleteSpace X] : + Tendsto (fun n => ‖S.T (h S n) (x S n) - x S n‖) atTop (𝓝 0) := by + obtain ⟨ω, hω, M, hM, hbound⟩ := S.toC0Semigroup.exists_exp_bound + let K : ℝ := M * Real.exp ω + have hM0 : 0 ≤ M := le_trans (by norm_num) hM + have hK : 0 ≤ K := mul_nonneg hM0 (Real.exp_pos _).le + have hTbound : ∀ n, ‖S.T (h S n)‖ ≤ K := by + intro n + calc + ‖S.T (h S n)‖ ≤ M * Real.exp (ω * h S n) := + hbound _ (h_pos S n).le + _ ≤ M * Real.exp ω := by + apply mul_le_mul_of_nonneg_left _ hM0 + apply Real.exp_le_exp.2 + have hn : h S n ≤ 1 := le_trans (h_le_quarter S n) (by norm_num) + simpa only [mul_one] using mul_le_mul_of_nonneg_left hn hω + _ = K := rfl + let A : ℕ → X →L[𝕜] X := + fun n => S.T (h S n) - ContinuousLinearMap.id 𝕜 X + have hAbound : ∀ n, ‖A n‖ ≤ K + 1 := by + intro n + calc + ‖A n‖ ≤ ‖S.T (h S n)‖ + ‖ContinuousLinearMap.id 𝕜 X‖ := norm_sub_le _ _ + _ ≤ K + 1 := add_le_add (hTbound n) (ContinuousLinearMap.norm_id_le) + have hPhillips : Tendsto + (fun n => ‖A n (packedOperator S (Phillips.e n))‖) atTop (𝓝 0) := by + exact Phillips.uniform (packedOperator S) S.T S.T_cont + (h S) (fun n => (h_pos S n).le) (h_tendsto S) + have herror : ∀ n, ‖S.T (h S n) (x S n) - x S n‖ ≤ + ‖A n (packedOperator S (Phillips.e n))‖ + (K + 1) * err n := by + intro n + let y := packedOperator S (Phillips.e n) + have hxy : ‖x S n - y‖ ≤ err n := by + rw [norm_sub_rev] + exact packedOperator_close S n + have hsplit : A n (x S n) = A n y + A n (x S n - y) := by + rw [map_sub] + abel + calc + ‖S.T (h S n) (x S n) - x S n‖ = ‖A n (x S n)‖ := rfl + _ = ‖A n y + A n (x S n - y)‖ := congrArg norm hsplit + _ ≤ ‖A n y‖ + ‖A n (x S n - y)‖ := norm_add_le _ _ + _ ≤ ‖A n y‖ + ‖A n‖ * ‖x S n - y‖ := + add_le_add le_rfl ((A n).le_opNorm _) + _ ≤ ‖A n y‖ + (K + 1) * err n := by + apply add_le_add le_rfl + exact mul_le_mul (hAbound n) hxy (norm_nonneg _) (by linarith) + apply squeeze_zero (fun n => norm_nonneg _) herror + simpa only [mul_zero, add_zero] using + hPhillips.add (err_tendsto.const_mul (K + 1)) + +end ZeroClassProof + +open ZeroClassProof + +/-- **Theorem 1.5** (`thm:p-infty-zero-class`). Let `X`, `U` be real or complex Banach +spaces and `S = (𝕋, Φ)` an abstract linear control system with `p = ∞`. Then `S` is of +the zero-class: `‖Φ t‖ → 0` as `t → 0⁺`. + +Proof: by Steps 2–4, `‖x_n‖ → ℓ` and `‖T_{h_n} x_n - x_n‖ → 0`; passing to the limit in +the doubling inequality of Step 1 gives `2ℓ ≤ ℓ`, hence `ℓ = 0`. -/ +theorem zero_class [CompleteSpace X] (S : ALCS 𝕜 X U ∞) : + S.IsZeroClass := by + have hx := x_norm_tendsto S + have hm := x_moves_tendsto S + have htwo : Tendsto (fun n => ‖S.Φ (2 * h S n)‖) atTop (𝓝 (ell S)) := + norm_Phi_tendsto S (fun n => 2 * h S n) + (fun n => mul_pos (by norm_num) (h_pos S n)) + (by simpa only [mul_zero] using (h_tendsto S).const_mul 2) + have hineq : ∀ n, 2 * ‖x S n‖ ≤ ‖S.Φ (2 * h S n)‖ + + ‖S.T (h S n) (x S n) - x S n‖ := by + intro n + exact doubling S (h_pos S n).le (data S n).pulse.input + (data S n).pulse.norm_input + have hlimit : 2 * ell S ≤ ell S := by + have hleft := hx.const_mul 2 + have hright := htwo.add hm + have hle := le_of_tendsto_of_tendsto hleft hright + (Filter.Eventually.of_forall hineq) + simpa only [add_zero] using hle + have hell : ell S = 0 := by + have := ell_nonneg S + linarith + rw [IsZeroClass, Metric.tendsto_nhdsWithin_nhds] + intro ε hε + obtain ⟨τ, hτ, hnormτ⟩ := exists_norm_lt S ε hε + rw [hell, zero_add] at hnormτ + refine ⟨τ, hτ, fun t ht hdist => ?_⟩ + have ht0 : 0 ≤ t := ht + have htτ : t < τ := by + simpa only [Real.dist_eq, sub_zero, abs_of_nonneg ht0] using hdist + have hsmall : ‖S.Φ t‖ < ε := + lt_of_le_of_lt (norm_Phi_mono S ht0 htτ.le) hnormτ + simpa using hsmall + +end ALCS + +end Endpoint + +end + +end + +end AbstractLinearControl diff --git a/LeanPool/projects/abstract-linear-control.yaml b/LeanPool/projects/abstract-linear-control.yaml new file mode 100644 index 0000000000..2e82975591 --- /dev/null +++ b/LeanPool/projects/abstract-linear-control.yaml @@ -0,0 +1,68 @@ +slug: abstract-linear-control +title: Continuity and zero-class properties of abstract linear control systems +summary: Proves that every abstract linear control system with bounded L-infinity + inputs between real or complex Banach spaces is zero-class, and hence has continuous + input-response trajectories. No integral representation or reflexivity assumption + is required. Includes finite-p continuity, a finite-p system with constant response + norm, and a scalar zero-class system without integral representation or Orlicz-heart + admissibility. Reusable infrastructure includes Phillips' lemma, strongly continuous + semigroup bounds, half-line Lp concatenation and shifts, invariant Hahn-Banach + extensions, and periodic invariant means. +branch: functional analysis and control theory +entry_module: LeanPool.AbstractLinearControl +authors: +- Frédéric Marbach +- GPT-6 Pro +- Claude Opus 5.5 +source: + title: Continuity of solutions to abstract linear control systems + url: https://github.com/frederic-marbach/alcs/tree/bda56576f8b2730b73a55f273511c80fabbe56f4 + github_repo: frederic-marbach/alcs + commit: bda56576f8b2730b73a55f273511c80fabbe56f4 + paper: https://hexagonmath.org/pdf/2610.00022v2 +license: Apache-2.0 +status: verified +provenance: AI +main_declarations: +- AbstractLinearControl.ALCS.zero_class +main_results: +- declaration: AbstractLinearControl.ALCS.zero_class + informal: For every abstract linear control system with L-infinity inputs between + real or complex Banach spaces, the norms of its input-response operators tend + to zero as time tends to zero from the right. + source_ref: Theorem 1.5 of version 2, completed in Lean on 2026-10-03. +- declaration: AbstractLinearControl.ALCS.continuousOn_Phi + informal: For every bounded input of such a system, its input-response trajectory + is continuous on the nonnegative half-line. + source_ref: Corollary 1.6. +- declaration: AbstractLinearControl.ALCS.continuousOn_Phi_of_ne_top + informal: For every abstract linear control system with finite exponent p at + least one and complete state space, each Lp input has a continuous input-response + trajectory on the nonnegative half-line. + source_ref: Proposition 1.3. +- declaration: AbstractLinearControl.exists_system_norm_Phi_eq_one + informal: For every finite exponent p at least one, there exist real Banach input + and state spaces and an abstract linear control system whose input-response + operator has norm one at every positive time. + source_ref: Proposition 3.1. +- declaration: AbstractLinearControl.ExoticMean.Counterexample.no_representation + informal: There exists a scalar abstract linear control system with identity + semigroup and response norm equal to time, which has no integral representation + and is not admissible for any of the formalized Young-function Orlicz hearts. + source_ref: Proposition 3.3; formal Young functions include the paper's class. +- declaration: AbstractLinearControl.Phillips.full + informal: For a pointwise null sequence of bounded linear functionals on real or + complex bounded sequences, each sequence of atomic coefficients is absolutely + summable, its sum of norms tends to zero, and its diagonal coefficient tends + to zero. + source_ref: Lemma 2.2. +tags: +- functional-analysis +- control-theory +- semigroups +- lp-spaces +- hahn-banach +msc: +- 47D06 +- 93C25 +- 46E30