From de6a6f3e42c4c95ce42b63a95977142e5aadfe45 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Sun, 17 Aug 2025 15:17:20 +0200 Subject: [PATCH 01/93] feat(SymbolicDynamics): basic setup of Zd, full shift, cylinders, patterns, subshifts, entropy --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 357 +++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 Mathlib/Dynamics/SymbolicDynamics/Basic.lean diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean new file mode 100644 index 00000000000000..a32eba2dccc66b --- /dev/null +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -0,0 +1,357 @@ +import Mathlib.Data.Fintype.Basic +import Mathlib.Data.Fin.VecNotation +import Mathlib.Data.Int.Basic +import Mathlib.Algebra.Module.Basic +import Mathlib.Topology.Basic +import Mathlib.Topology.UniformSpace.Pi +import Mathlib.Topology.UniformSpace.Basic +import Mathlib.Topology.Sets.Opens +import Mathlib.Topology.Instances.Discrete +import Mathlib.Algebra.Group.Basic +import Mathlib.Data.Int.Interval +import Mathlib.Data.Real.Basic +import Mathlib.Order.Filter.Basic +import Mathlib.Analysis.SpecialFunctions.Log.Basic +import Mathlib.Topology.Instances.EReal.Lemmas +import Mathlib.Data.Finset.Basic +import Mathlib.Logic.Equiv.Defs + +open Set Topology +open Filter + +namespace SymbolicDynamics + +/-! +# Symbolic dynamics over `ℤ^d` + +We set up a minimal API for the full shift over a finite discrete alphabet, cylinders, +patterns, and subshifts defined by forbidden patterns. We also define a language size on +boxes and a (limsup-based) notion of topological entropy. + +## Main definitions + +* `Zd d` : the lattice `ℤ^d` as functions `Fin d → ℤ`. +* `FullShiftZd A d` : configurations `Zd d → A` with the product topology. +* `FullShiftZd.shift` : the `ℤ^d`-action by translation. +* `cylinder U x` : cylinder set fixing the coordinates in `U ⊆ Zd d` to those of `x`. +* `Pattern A d` : finite patterns (support + values). +* `Pattern.occursIn` : occurrence of a pattern at a position. +* `forbids F` : configurations avoiding every pattern in `F`. +* `Subshift` : closed, shift‑invariant subsets of the full shift. +* `box n` : the cube `[-n,n]^d` as a finset of `Zd d`. +* `languageCard` / `patternCount` : number of patterns seen on a box. +* `limsupAtTop` : `limsup` of a real sequence along `atTop` (infimum of eventual upper bounds). +* `entropy` : limsup language growth per unit volume. + +## Notation/Conventions + +* The alphabet `A` is assumed finite, discrete, and inhabited throughout. The product topology + on configurations is used. +* Cylinders are defined by equality on finitely many coordinates, hence are clopen. + +-/ + +variable {A : Type*} [Fintype A] [DecidableEq A] [Inhabited A] + [TopologicalSpace A] [DiscreteTopology A] + +variable {d : ℕ} + +/-- The lattice `ℤ^d` as functions `Fin d → ℤ`. -/ +def Zd (d : ℕ) := Fin d → ℤ + +@[instance] +/-- Decidable equality on `Zd d`. -/ +def Zd.decidableEq (d : ℕ) : DecidableEq (Zd d) := + inferInstanceAs (DecidableEq (Fin d → ℤ)) + +/-- Pointwise addition on `ℤ^d`. -/ +instance : Add (Zd d) where + add := fun u v i ↦ u i + v i + +/-- `ℤ^d` is an additive commutative group (pointwise). -/ +instance : AddCommGroup (Zd d) := Pi.addCommGroup + +/-! ## Full shift -/ + +/-- The full shift over `ℤ^d` with alphabet `A`. -/ +@[reducible] +def FullShiftZd (A : Type*) (d : ℕ) := Zd d → A + +/-- Product topology on the full shift. -/ +instance : TopologicalSpace (FullShiftZd A d) := Pi.topologicalSpace + +/-- Default configuration: constantly `default`. -/ +instance : Inhabited (FullShiftZd A d) := ⟨fun _ ↦ default⟩ + +namespace FullShiftZd + +/-! ### Shift action -/ + +/-- Shift by `v`: translate a configuration by `v`. -/ +def shift (v : Zd d) (x : FullShiftZd A d) : FullShiftZd A d := + fun u ↦ x (u + v) + +section +variable {A : Type*} {d : ℕ} + +@[simp] lemma shift_zero (x : FullShiftZd A d) : + shift (0 : Zd d) x = x := by + ext u; simp [shift] + +/-- Compatibility of shifts with addition. -/ +lemma shift_add (v w : Zd d) (x : FullShiftZd A d) : + shift (v + w) x = shift v (shift w x) := by + ext u; simp [shift, add_assoc] +end + +section +variable {A : Type*} [TopologicalSpace A] +variable {d : ℕ} + +/-- The shift map is continuous. -/ +lemma shift_continuous (v : Zd d) : + Continuous (shift v : FullShiftZd A d → FullShiftZd A d) := by + continuity +end + +/-! ### Cylinders and clopen basis -/ + +/-- Cylinder fixing `x` on a finite set `U`. -/ +@[reducible] +def cylinder (U : Finset (Zd d)) (x : Zd d → A) : Set (FullShiftZd A d) := + { y | ∀ i ∈ U, y i = x i } + +section +variable {A : Type*} {d : ℕ} + +@[simp] lemma mem_cylinder {U : Finset (Zd d)} {x y : FullShiftZd A d} : + y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := by rfl +end + +section +variable {A : Type*} [TopologicalSpace A] [DiscreteTopology A] +variable {d : ℕ} + +/-- Cylinders are open. -/ +lemma cylinder_is_open (U : Finset (Zd d)) (x : Zd d → A) : + IsOpen (cylinder U x) := by + let S : Set (FullShiftZd A d) := ⋂ i ∈ U, { y | y i = x i } + have : cylinder U x = S := by + ext y; simp [cylinder, mem_iInter₂] + rw [this] + apply isOpen_biInter_finset + intro i _ + have : { y : FullShiftZd A d | y i = x i } = (fun y ↦ y i) ⁻¹' {x i} := rfl + simpa [this] using + (Continuous.isOpen_preimage (continuous_apply i) (isOpen_discrete ({x i} : Set A))) +end + +section +variable {A : Type*} [TopologicalSpace A] [DiscreteTopology A] +variable [Fintype A] [DecidableEq A] +variable {d : ℕ} + +/-- Cylinders are closed (hence clopen). -/ +lemma cylinder_is_closed (d : ℕ) (U : Finset (Zd d)) (x : Zd d → A) : + IsClosed (cylinder U x) := by + have h : (cylinder U x)ᶜ = ⋃ (i ∈ U) (a ∈ (Finset.univ \ {x i} : Finset A)), + cylinder {i} (Function.update x i a) := by + ext y; simp [mem_cylinder, exists_prop, mem_iUnion, mem_compl_iff] + have : IsOpen ((cylinder U x)ᶜ) := by + simpa [h] using + (isOpen_iUnion fun i ↦ + isOpen_iUnion fun _ ↦ + isOpen_iUnion fun _ ↦ + isOpen_iUnion fun _ ↦ cylinder_is_open {i} (Function.update x i ·)) + simpa [isOpen_compl_iff] using this +end + +/-! ## Subshifts and patterns -/ + +/-- A subshift is a closed, shift‑invariant subset of the full shift. -/ +structure Subshift (A : Type*) [TopologicalSpace A] [Inhabited A] (d : ℕ) where + /-- The underlying set. -/ + carrier : Set (FullShiftZd A d) + /-- Closedness of the carrier. -/ + is_closed : IsClosed carrier + /-- Shift invariance. -/ + shift_invariant : ∀ v : Zd d, ∀ x ∈ carrier, shift v x ∈ carrier + +/-- The full shift is a subshift. -/ +example : Subshift A d := +{ carrier := Set.univ, + is_closed := isClosed_univ, + shift_invariant := by intro _ _ _; simp } + +/-- A finite pattern: a finite support `U` together with values on `U`. -/ +structure Pattern (A : Type*) (d : ℕ) where + support : Finset (Zd d) + data : support → A + +/-- The domino supported on `{i,j}` with values `ai`,`aj`. -/ +def domino {A : Type*} {d : ℕ} + (i j : Zd d) (ai aj : A) : Pattern A d := by + refine + { support := ({i, j} : Finset (Zd d)) + , data := fun ⟨z, hz⟩ => if z = i then ai else aj } + +/-- `p` occurs in `x` at position `v`. -/ +def Pattern.occursIn (p : Pattern A d) (x : FullShiftZd A d) (v : Zd d) : Prop := + ∀ u (hu : u ∈ p.support), x (u + v) = p.data ⟨u, hu⟩ + +/-! ### Forbidden patterns -/ + +/-- Configurations avoiding all patterns of `F`. -/ +def forbids (F : Set (Pattern A d)) : Set (FullShiftZd A d) := + { x | ∀ p ∈ F, ∀ v : Zd d, ¬ p.occursIn x v } + +section +variable {A : Type*} {d : ℕ} + +lemma occurs_shift (p : Pattern A d) (x : FullShiftZd A d) (v w : Zd d) : + Pattern.occursIn p (shift w x) v ↔ Pattern.occursIn p x (v + w) := by + constructor + · intro h u hu; simpa [← add_assoc] using h u hu + · intro h u hu; simpa [shift, add_assoc] using h u hu + +/-- `forbids F` is shift invariant. -/ +lemma forbids_shift_invariant (F : Set (Pattern A d)) : + ∀ v : Zd d, ∀ x ∈ forbids F, shift v x ∈ forbids F := by + intro w x hx p hp v; specialize hx p hp (v + w); contrapose! hx; rwa [← occurs_shift] +end + +/-- Extend a pattern by `default` away from its support (anchored at the origin). -/ +def patternToOriginConfig (p : Pattern A d) : FullShiftZd A d := + fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default + +/-- Translate a pattern to occur at `v`. -/ +def patternToConfig (p : Pattern A d) (v : Zd d) : FullShiftZd A d := + shift (-v) (patternToOriginConfig p) + +/-- Restrict a configuration to a finite support, seen as a pattern. -/ +def patternFromConfig (x : Zd d → A) (U : Finset (Zd d)) : Pattern A d := + { support := U, + data := fun i => x i.1 } + +set_option linter.unusedSectionVars false +/-- Occurrences are cylinders translated by `v`. -/ +lemma occursAt_eq_cylinder (p : Pattern A d) (v : Zd d) : + { x | p.occursIn x v } + = cylinder (p.support.image (· + v)) (patternToConfig p v) := by + ext x + constructor + · intro H u hu + obtain ⟨w, hw, rfl⟩ := Finset.mem_image.mp hu + dsimp [patternToConfig, patternToOriginConfig, shift] + simp [add_neg_cancel_right, dif_pos hw, H w hw] + · intro H u hu + have := H (u + v) (Finset.mem_image_of_mem _ hu) + dsimp [patternToConfig, patternToOriginConfig, shift] at this + simpa [add_neg_cancel_right, dif_pos hu] using this + +/-- Occurrence sets are closed. -/ +lemma occursAt_closed (p : Pattern A d) (v : Zd d) : + IsClosed { x | p.occursIn x v } := by + rw [occursAt_eq_cylinder]; exact cylinder_is_closed d _ _ + +/-- Occurrence sets are open. -/ +lemma occursAt_open (p : Pattern A d) (v : Zd d) : + IsOpen { x | p.occursIn x v } := by + rw [occursAt_eq_cylinder]; exact cylinder_is_open _ _ + +/-- Avoiding a fixed set of patterns is a closed condition. -/ +lemma forbids_closed (F : Set (Pattern A d)) : + IsClosed (forbids F) := by + rw [forbids] + have : {x | ∀ p ∈ F, ∀ v : Zd d, ¬ p.occursIn x v} + = ⋂ (p : Pattern A d) (h : p ∈ F), ⋂ (v : Zd d), {x | ¬ p.occursIn x v} := by + ext x; simp + rw [this] + refine isClosed_iInter ?_; + intro p; refine isClosed_iInter ?_; + intro _; refine isClosed_iInter ?_; + intro v; have : {x | ¬p.occursIn x v} = {x | p.occursIn x v}ᶜ := by ext x; simp + simpa [this, isClosed_compl_iff] using occursAt_open p v + +/-- Subshift defined by forbidden patterns. -/ +def X_F (F : Set (Pattern A d)) : Subshift A d := +{ carrier := forbids F, + is_closed := forbids_closed F, + shift_invariant := forbids_shift_invariant F } + +/-- Subshift of finite type defined by a finite family of forbidden patterns. -/ +def SFT (F : Finset (Pattern A d)) : Subshift A d := + X_F (F : Set (Pattern A d)) + +/-! ## Boxes, language, and entropy -/ + +/-- The box `[-n,n]^d` as a finset of `Zd d`. -/ +def box (n : ℕ) : Finset (Zd d) := + Fintype.piFinset (fun _ ↦ Finset.Icc (-↑n : ℤ) ↑n) + +/-- Language on the box `[-n,n]^d`: patterns obtained by restricting some `x ∈ X`. -/ +def language_box (X : Set (Zd d → A)) (n : ℕ) : Set (Pattern A d) := + { p | ∃ x ∈ X, patternFromConfig x (box n) = p } + +/-- Patterns with fixed support `U`. -/ +def FixedSupport (A : Type*) (d : ℕ) (U : Finset (Zd d)) := + { p : Pattern A d // p.support = U } + +set_option linter.unnecessarySimpa false +/-- Equivalence `FixedSupport A d U ≃ (U → A)`. -/ +def equivFun {U : Finset (Zd d)} : FixedSupport A d U ≃ (U → A) where + toFun := fun p => fun i => + p.val.data ⟨i.1, by simpa [p.property] using i.2⟩ + invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ + left_inv := by + rintro ⟨p, hp⟩; apply Subtype.ext; cases hp; rfl + right_inv := by intro f; rfl + +/-- Finiteness of `FixedSupport A d U`. -/ +instance fintypeFixedSupport (U : Finset (Zd d)) : + Fintype (FixedSupport A d U) := by + classical + exact Fintype.ofEquiv (U → A) (equivFun (A:=A) (d:=d) (U:=U)).symm + +/-- Cardinality of the box language (as a finite set), defined via images into +`FixedSupport`. This version is `noncomputable` since it goes through `Set.finite_univ`. -/ +noncomputable def languageCard (X : Set (Zd d → A)) (n : ℕ) : ℕ := by + classical + let U : Finset (Zd d) := box (d:=d) n + let f : {x : Zd d → A // x ∈ X} → FixedSupport A d U := + fun x => ⟨patternFromConfig (A:=A) (d:=d) x.1 U, rfl⟩ + have hfin_univ : (Set.univ : Set (FixedSupport A d U)).Finite := Set.finite_univ + have hfin : (Set.range f).Finite := hfin_univ.subset (by intro y hy; simp) + exact hfin.toFinset.card + +/-- Number of patterns of a subshift on the box of size `n`. -/ +noncomputable def patternCount (Y : Subshift A d) (n : ℕ) : ℕ := + languageCard (A:=A) (d:=d) Y.carrier n + +/-- The box `[-n,n]^d` is nonempty. -/ +@[simp] lemma box_card_pos (d n : ℕ) : 0 < (box (d:=d) n).card := by + classical + have hcoord : + ∀ i : Fin d, (0 : ℤ) ∈ Finset.Icc (-(n : ℤ)) (n : ℤ) := by + intro i + have h0n : (0 : ℤ) ≤ (n : ℤ) := by exact_mod_cast (Nat.zero_le n) + have hneg : -(n : ℤ) ≤ 0 := neg_nonpos.mpr h0n + simp [Finset.mem_Icc, hneg] + have hmem : (0 : Zd d) ∈ box (d:=d) n := + Fintype.mem_piFinset.mpr hcoord + exact Finset.card_pos.mpr ⟨0, hmem⟩ + +/-- `limsup` along `atTop` as the infimum of eventual upper bounds. -/ +noncomputable def limsupAtTop (u : ℕ → ℝ) : ℝ := + sInf { L : ℝ | ∀ᶠ n in Filter.atTop, u n ≤ L } + +/-- Topological entropy via limsup language growth on cubes. +We use `+ 1` inside the logarithm to avoid `log 0`. -/ +noncomputable def entropy (Y : Subshift A d) : ℝ := + limsupAtTop (fun n => + (Real.log ((patternCount (A:=A) (d:=d) Y n + 1 : ℕ))) / + ((box (d:=d) n).card : ℝ)) + +end FullShiftZd + +end SymbolicDynamics From e673892c4bb65d4449008098ee18af9a03287159 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Sun, 17 Aug 2025 21:37:45 +0200 Subject: [PATCH 02/93] chore: update import all files --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index a7b39215134d7c..46dcfcb2abd617 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3856,6 +3856,7 @@ import Mathlib.Dynamics.Newton import Mathlib.Dynamics.OmegaLimit import Mathlib.Dynamics.PeriodicPts.Defs import Mathlib.Dynamics.PeriodicPts.Lemmas +import Mathlib.Dynamics.SymbolicDynamics.Basic import Mathlib.Dynamics.TopologicalEntropy.CoverEntropy import Mathlib.Dynamics.TopologicalEntropy.DynamicalEntourage import Mathlib.Dynamics.TopologicalEntropy.NetEntropy From 99d0732718d90e9d66b0106f896ac727627ea903 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Sun, 17 Aug 2025 22:02:24 +0200 Subject: [PATCH 03/93] symbolic dynamics: fix header/docstring order; cylinder lemmas; classical instances --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 71 +++++++++++++++----- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index a32eba2dccc66b..895d1474256bac 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -1,3 +1,9 @@ +/- +Copyright (c) 2025 S. Gangloff. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: S. Gangloff +-/ + import Mathlib.Data.Fintype.Basic import Mathlib.Data.Fin.VecNotation import Mathlib.Data.Int.Basic @@ -16,11 +22,6 @@ import Mathlib.Topology.Instances.EReal.Lemmas import Mathlib.Data.Finset.Basic import Mathlib.Logic.Equiv.Defs -open Set Topology -open Filter - -namespace SymbolicDynamics - /-! # Symbolic dynamics over `ℤ^d` @@ -51,6 +52,12 @@ boxes and a (limsup-based) notion of topological entropy. -/ +open Set Topology +open Filter + +namespace SymbolicDynamics + + variable {A : Type*} [Fintype A] [DecidableEq A] [Inhabited A] [TopologicalSpace A] [DiscreteTopology A] @@ -59,8 +66,8 @@ variable {d : ℕ} /-- The lattice `ℤ^d` as functions `Fin d → ℤ`. -/ def Zd (d : ℕ) := Fin d → ℤ -@[instance] /-- Decidable equality on `Zd d`. -/ +@[instance] def Zd.decidableEq (d : ℕ) : DecidableEq (Zd d) := inferInstanceAs (DecidableEq (Fin d → ℤ)) @@ -137,13 +144,18 @@ lemma cylinder_is_open (U : Finset (Zd d)) (x : Zd d → A) : IsOpen (cylinder U x) := by let S : Set (FullShiftZd A d) := ⋂ i ∈ U, { y | y i = x i } have : cylinder U x = S := by - ext y; simp [cylinder, mem_iInter₂] + ext y + rw [cylinder, mem_setOf_eq] + rw [mem_iInter₂] + simp only [mem_setOf_eq] rw [this] apply isOpen_biInter_finset intro i _ have : { y : FullShiftZd A d | y i = x i } = (fun y ↦ y i) ⁻¹' {x i} := rfl - simpa [this] using - (Continuous.isOpen_preimage (continuous_apply i) (isOpen_discrete ({x i} : Set A))) + rw [this] + apply Continuous.isOpen_preimage + · exact continuous_apply i + · exact isOpen_discrete ({x i} : Set A) end section @@ -156,14 +168,41 @@ lemma cylinder_is_closed (d : ℕ) (U : Finset (Zd d)) (x : Zd d → A) : IsClosed (cylinder U x) := by have h : (cylinder U x)ᶜ = ⋃ (i ∈ U) (a ∈ (Finset.univ \ {x i} : Finset A)), cylinder {i} (Function.update x i a) := by - ext y; simp [mem_cylinder, exists_prop, mem_iUnion, mem_compl_iff] + · ext y + simp only [mem_compl_iff] + simp only [mem_iUnion] + simp only [mem_cylinder] + simp only [Finset.mem_univ, Finset.mem_sdiff] + simp only [not_forall] + simp only [exists_prop] + constructor + · intro hy + push_neg at hy + obtain ⟨i, hiU, hiy⟩ := hy + use i, hiU, y i + constructor + · simp [hiy] + · simp [Function.update_apply] + · rintro ⟨i, hiU, a, ha, hy⟩ + simp only [true_and] at ha + use i, hiU + rw [hy] + simp only [Function.update_apply] + have hne : a ≠ x i := by + intro h + apply ha + rw [h] + exact Finset.mem_singleton_self _ + exact hne + exact Finset.mem_singleton_self i have : IsOpen ((cylinder U x)ᶜ) := by - simpa [h] using - (isOpen_iUnion fun i ↦ - isOpen_iUnion fun _ ↦ - isOpen_iUnion fun _ ↦ - isOpen_iUnion fun _ ↦ cylinder_is_open {i} (Function.update x i ·)) - simpa [isOpen_compl_iff] using this + rw [h] + apply isOpen_iUnion; intro i + apply isOpen_iUnion; intro hi + apply isOpen_iUnion; intro a + apply isOpen_iUnion; intro ha + exact cylinder_is_open {i} (Function.update x i a) + exact isOpen_compl_iff.mp this end /-! ## Subshifts and patterns -/ From c65fa7a1db691e2488b758c980588d99d60604d2 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Mon, 18 Aug 2025 09:19:47 +0200 Subject: [PATCH 04/93] refactor(symbolic-dynamics): group-generic subshifts, abbrev FullShift, cleanup cylinders and instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use abbrev FullShift := G → A - remove redundant topology/inhabited instances - relate cylinder to Set.pi - reorganize lemmas to avoid unused variables - separate ℤ^d-specific geometry/entropy --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 433 ++++++++---------- .../EntropyFinitelyGenerated.lean | 193 ++++++++ 2 files changed, 386 insertions(+), 240 deletions(-) create mode 100644 Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 895d1474256bac..18c125f5755a28 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -4,145 +4,124 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: S. Gangloff -/ -import Mathlib.Data.Fintype.Basic -import Mathlib.Data.Fin.VecNotation -import Mathlib.Data.Int.Basic -import Mathlib.Algebra.Module.Basic import Mathlib.Topology.Basic import Mathlib.Topology.UniformSpace.Pi -import Mathlib.Topology.UniformSpace.Basic -import Mathlib.Topology.Sets.Opens import Mathlib.Topology.Instances.Discrete -import Mathlib.Algebra.Group.Basic -import Mathlib.Data.Int.Interval -import Mathlib.Data.Real.Basic -import Mathlib.Order.Filter.Basic -import Mathlib.Analysis.SpecialFunctions.Log.Basic -import Mathlib.Topology.Instances.EReal.Lemmas import Mathlib.Data.Finset.Basic import Mathlib.Logic.Equiv.Defs /-! -# Symbolic dynamics over `ℤ^d` +# Symbolic dynamics on groups -We set up a minimal API for the full shift over a finite discrete alphabet, cylinders, -patterns, and subshifts defined by forbidden patterns. We also define a language size on -boxes and a (limsup-based) notion of topological entropy. +This file develops a minimal API for symbolic dynamics over an arbitrary group `G`. +The ambient space is the full shift +`FullShift A G := G → A` (an `abbrev`), hence it inherits the product topology +from the Π-type. We define the right-translation action, cylinders, finite patterns, +their occurrences, forbidden sets, and subshifts (closed, shift-invariant subsets). +Basic topological statements (e.g. cylinders are clopen, occurrence sets are clopen, +forbidden sets are closed) are proved under discreteness assumptions on the alphabet. -## Main definitions +The file is group-generic. Geometry specific to `ℤ^d` (boxes/cubes and the +box-based entropy) is kept in a separate specialization. -* `Zd d` : the lattice `ℤ^d` as functions `Fin d → ℤ`. -* `FullShiftZd A d` : configurations `Zd d → A` with the product topology. -* `FullShiftZd.shift` : the `ℤ^d`-action by translation. -* `cylinder U x` : cylinder set fixing the coordinates in `U ⊆ Zd d` to those of `x`. -* `Pattern A d` : finite patterns (support + values). -* `Pattern.occursIn` : occurrence of a pattern at a position. -* `forbids F` : configurations avoiding every pattern in `F`. -* `Subshift` : closed, shift‑invariant subsets of the full shift. -* `box n` : the cube `[-n,n]^d` as a finset of `Zd d`. -* `languageCard` / `patternCount` : number of patterns seen on a box. -* `limsupAtTop` : `limsup` of a real sequence along `atTop` (infimum of eventual upper bounds). -* `entropy` : limsup language growth per unit volume. - -## Notation/Conventions - -* The alphabet `A` is assumed finite, discrete, and inhabited throughout. The product topology - on configurations is used. -* Cylinders are defined by equality on finitely many coordinates, hence are clopen. +## Main definitions +* `FullShift A G := G → A`. +* `shift g x` — right translation: `(shift g x) h = x (h * g)`. +* `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. +* `Pattern A G` — finite support together with values on that support. +* `Pattern.occursIn p x g` — occurrence of `p` in `x` at translate `g`. +* `forbids F` — configurations avoiding every pattern in `F`. +* `Subshift A G` — closed, shift-invariant subsets of the full shift. + +## Conventions + +We use a **right** action of `G` on configurations: +`(shift g x) h = x (h * g)`. In additive notation (e.g. for `ℤ^d`) this is +`(shift v x) u = x (u + v)`. + +## Implementation notes + +* Since `FullShift A G` is an `abbrev` for `G → A`, instances such as + `TopologicalSpace (FullShift A G)` and `Inhabited (FullShift A G)` are inherited + automatically from the Π-type; no explicit instances are declared here. +* Openness/closedness results for cylinders and occurrence sets use + `[DiscreteTopology A]`. The closedness proofs that enumerate values additionally + require `[Fintype A]`, `[DecidableEq A]`, and `[DecidableEq G]` (for `Finset` manipulations + and `Function.update`). -/ +-- TODO: +-- In entropy, match the namespaces of basic2 ? +-- 3. Rewrite documentation +-- 4. CI checks +-- 5. Rewrite the PR description ? Make comments ? + +noncomputable section open Set Topology -open Filter namespace SymbolicDynamics +variable {A : Type*} [Fintype A] [Fintype A] [DecidableEq A] [Inhabited A] +variable {G : Type*} +variable [TopologicalSpace A] [DiscreteTopology A] +variable [Group G] [DecidableEq G] -variable {A : Type*} [Fintype A] [DecidableEq A] [Inhabited A] - [TopologicalSpace A] [DiscreteTopology A] - -variable {d : ℕ} - -/-- The lattice `ℤ^d` as functions `Fin d → ℤ`. -/ -def Zd (d : ℕ) := Fin d → ℤ - -/-- Decidable equality on `Zd d`. -/ -@[instance] -def Zd.decidableEq (d : ℕ) : DecidableEq (Zd d) := - inferInstanceAs (DecidableEq (Fin d → ℤ)) - -/-- Pointwise addition on `ℤ^d`. -/ -instance : Add (Zd d) where - add := fun u v i ↦ u i + v i - -/-- `ℤ^d` is an additive commutative group (pointwise). -/ -instance : AddCommGroup (Zd d) := Pi.addCommGroup +/-! ## Full shift and shift action -/ -/-! ## Full shift -/ -/-- The full shift over `ℤ^d` with alphabet `A`. -/ -@[reducible] -def FullShiftZd (A : Type*) (d : ℕ) := Zd d → A +/-- Full shift over a group `G` with alphabet `A` (product topology). -/ +abbrev FullShift (A G) := G → A -/-- Product topology on the full shift. -/ -instance : TopologicalSpace (FullShiftZd A d) := Pi.topologicalSpace +/-- Right-translation shift: `(shift g x)(h) = x (h * g)`. -/ +def shift (g : G) (x : FullShift A G) : FullShift A G := + fun h => x (h * g) -/-- Default configuration: constantly `default`. -/ -instance : Inhabited (FullShiftZd A d) := ⟨fun _ ↦ default⟩ +section ShiftAlgebra +variable {A G : Type*} [Group G] +@[simp] lemma shift_apply (g h : G) (x : FullShift A G) : + shift g x h = x (h * g) := rfl -namespace FullShiftZd +@[simp] lemma shift_one (x : FullShift A G) : shift (1 : G) x = x := by + ext h; simp [shift] -/-! ### Shift action -/ +lemma shift_mul (g₁ g₂ : G) (x : FullShift A G) : + shift (g₁ * g₂) x = shift g₁ (shift g₂ x) := by + ext h; simp [shift, mul_assoc] +end ShiftAlgebra -/-- Shift by `v`: translate a configuration by `v`. -/ -def shift (v : Zd d) (x : FullShiftZd A d) : FullShiftZd A d := - fun u ↦ x (u + v) - -section -variable {A : Type*} {d : ℕ} - -@[simp] lemma shift_zero (x : FullShiftZd A d) : - shift (0 : Zd d) x = x := by - ext u; simp [shift] +section ShiftTopology -- add only topology on A +variable {A G : Type*} [Group G] [TopologicalSpace A] +lemma shift_continuous (g : G) : Continuous (shift (A:=A) (G:=G) g) := by + -- coordinate projections are continuous; composition preserves continuity + continuity +end ShiftTopology -/-- Compatibility of shifts with addition. -/ -lemma shift_add (v w : Zd d) (x : FullShiftZd A d) : - shift (v + w) x = shift v (shift w x) := by - ext u; simp [shift, add_assoc] -end -section -variable {A : Type*} [TopologicalSpace A] -variable {d : ℕ} -/-- The shift map is continuous. -/ -lemma shift_continuous (v : Zd d) : - Continuous (shift v : FullShiftZd A d → FullShiftZd A d) := by - continuity -end +/-! ## Cylinders -/ -/-! ### Cylinders and clopen basis -/ +section CylindersDefs +variable {A G : Type*} -/-- Cylinder fixing `x` on a finite set `U`. -/ -@[reducible] -def cylinder (U : Finset (Zd d)) (x : Zd d → A) : Set (FullShiftZd A d) := +/-- Cylinder fixing `x` on the finite set `U`. -/ +def cylinder (U : Finset G) (x : FullShift A G) : Set (FullShift A G) := { y | ∀ i ∈ U, y i = x i } -section -variable {A : Type*} {d : ℕ} +lemma cylinder_eq_set_pi (U : Finset (G)) (x : G → A) : + cylinder U x = Set.pi (↑U : Set (G)) (fun i => ({x i} : Set A)) := by + ext y; simp [cylinder, Set.pi, Finset.mem_coe] -@[simp] lemma mem_cylinder {U : Finset (Zd d)} {x y : FullShiftZd A d} : - y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := by rfl -end +@[simp] lemma mem_cylinder {U : Finset G} {x y : FullShift A G} : + y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl +end CylindersDefs -section -variable {A : Type*} [TopologicalSpace A] [DiscreteTopology A] -variable {d : ℕ} - -/-- Cylinders are open. -/ -lemma cylinder_is_open (U : Finset (Zd d)) (x : Zd d → A) : +section CylindersOpen +variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] +/-- Cylinders are open (and, dually, closed) when `A` is discrete. -/ +lemma cylinder_is_open (U : Finset (G)) (x : G → A) : IsOpen (cylinder U x) := by - let S : Set (FullShiftZd A d) := ⋂ i ∈ U, { y | y i = x i } + let S : Set (FullShift A G) := ⋂ i ∈ U, { y | y i = x i } have : cylinder U x = S := by ext y rw [cylinder, mem_setOf_eq] @@ -151,20 +130,17 @@ lemma cylinder_is_open (U : Finset (Zd d)) (x : Zd d → A) : rw [this] apply isOpen_biInter_finset intro i _ - have : { y : FullShiftZd A d | y i = x i } = (fun y ↦ y i) ⁻¹' {x i} := rfl + have : { y : FullShift A G | y i = x i } = (fun y ↦ y i) ⁻¹' {x i} := rfl rw [this] apply Continuous.isOpen_preimage · exact continuous_apply i · exact isOpen_discrete ({x i} : Set A) -end - -section -variable {A : Type*} [TopologicalSpace A] [DiscreteTopology A] -variable [Fintype A] [DecidableEq A] -variable {d : ℕ} +end CylindersOpen -/-- Cylinders are closed (hence clopen). -/ -lemma cylinder_is_closed (d : ℕ) (U : Finset (Zd d)) (x : Zd d → A) : +section CylindersClosed +variable {A G : Type*} +[TopologicalSpace A] [DiscreteTopology A] [Fintype A] [DecidableEq A] [DecidableEq G] +lemma cylinder_is_closed (U : Finset (G)) (x : G → A) : IsClosed (cylinder U x) := by have h : (cylinder U x)ᶜ = ⋃ (i ∈ U) (a ∈ (Finset.univ \ {x i} : Finset A)), cylinder {i} (Function.update x i a) := by @@ -203,107 +179,108 @@ lemma cylinder_is_closed (d : ℕ) (U : Finset (Zd d)) (x : Zd d → A) : apply isOpen_iUnion; intro ha exact cylinder_is_open {i} (Function.update x i a) exact isOpen_compl_iff.mp this -end +end CylindersClosed -/-! ## Subshifts and patterns -/ +/-! ## Patterns and occurrences -/ -/-- A subshift is a closed, shift‑invariant subset of the full shift. -/ -structure Subshift (A : Type*) [TopologicalSpace A] [Inhabited A] (d : ℕ) where - /-- The underlying set. -/ - carrier : Set (FullShiftZd A d) - /-- Closedness of the carrier. -/ - is_closed : IsClosed carrier - /-- Shift invariance. -/ - shift_invariant : ∀ v : Zd d, ∀ x ∈ carrier, shift v x ∈ carrier +/-- A subshift is a closed, shift-invariant subset. -/ +structure Subshift (A : Type*) [TopologicalSpace A] [Inhabited A] (G : Type*) [Group G] where + carrier : Set (FullShift A G) + isClosed : IsClosed carrier + shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift (A:=A) (G:=G) g x ∈ carrier /-- The full shift is a subshift. -/ -example : Subshift A d := +example : Subshift A G := { carrier := Set.univ, - is_closed := isClosed_univ, - shift_invariant := by intro _ _ _; simp } + isClosed := isClosed_univ, + shiftInvariant := by intro _ _ _; simp } -/-- A finite pattern: a finite support `U` together with values on `U`. -/ -structure Pattern (A : Type*) (d : ℕ) where - support : Finset (Zd d) + +/-- A finite pattern: finite support in `G` and values on it. -/ +structure Pattern (A : Type*) (G : Type*) [Group G] where + support : Finset G data : support → A /-- The domino supported on `{i,j}` with values `ai`,`aj`. -/ -def domino {A : Type*} {d : ℕ} - (i j : Zd d) (ai aj : A) : Pattern A d := by +def domino {A : Type*} + (i j : G) (ai aj : A) : Pattern A G := by refine - { support := ({i, j} : Finset (Zd d)) + { support := ({i, j} : Finset (G)) , data := fun ⟨z, hz⟩ => if z = i then ai else aj } -/-- `p` occurs in `x` at position `v`. -/ -def Pattern.occursIn (p : Pattern A d) (x : FullShiftZd A d) (v : Zd d) : Prop := - ∀ u (hu : u ∈ p.support), x (u + v) = p.data ⟨u, hu⟩ +/-- Occurrence of a pattern `p` in `x` at position `g`. -/ +def Pattern.occursIn (p : Pattern A G) (x : FullShift A G) (g : G) : Prop := + ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ -/-! ### Forbidden patterns -/ +/-- Configurations avoiding every pattern in `F`. -/ +def forbids (F : Set (Pattern A G)) : Set (FullShift A G) := + { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } -/-- Configurations avoiding all patterns of `F`. -/ -def forbids (F : Set (Pattern A d)) : Set (FullShiftZd A d) := - { x | ∀ p ∈ F, ∀ v : Zd d, ¬ p.occursIn x v } -section -variable {A : Type*} {d : ℕ} +section ShiftInvariance +variable {A G : Type*} [Group G] +/-- Shifts move occurrences as expected. -/ +lemma occurs_shift (p : Pattern A G) (x : FullShift A G) (g h : G) : + p.occursIn (shift h x) g ↔ p.occursIn x (g * h) := by + constructor <;> intro H u hu <;> simpa [shift, mul_assoc] using H u hu -lemma occurs_shift (p : Pattern A d) (x : FullShiftZd A d) (v w : Zd d) : - Pattern.occursIn p (shift w x) v ↔ Pattern.occursIn p x (v + w) := by - constructor - · intro h u hu; simpa [← add_assoc] using h u hu - · intro h u hu; simpa [shift, add_assoc] using h u hu - -/-- `forbids F` is shift invariant. -/ -lemma forbids_shift_invariant (F : Set (Pattern A d)) : - ∀ v : Zd d, ∀ x ∈ forbids F, shift v x ∈ forbids F := by - intro w x hx p hp v; specialize hx p hp (v + w); contrapose! hx; rwa [← occurs_shift] -end +lemma forbids_shift_invariant (F : Set (Pattern A G)) : + ∀ h : G, ∀ x ∈ forbids (A:=A) (G:=G) F, shift h x ∈ forbids F := by + intro h x hx p hp g + specialize hx p hp (g * h) + -- contraposition + contrapose! hx + simpa [occurs_shift] using hx +end ShiftInvariance /-- Extend a pattern by `default` away from its support (anchored at the origin). -/ -def patternToOriginConfig (p : Pattern A d) : FullShiftZd A d := +def patternToOriginConfig (p : Pattern A G) : FullShift A G := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default /-- Translate a pattern to occur at `v`. -/ -def patternToConfig (p : Pattern A d) (v : Zd d) : FullShiftZd A d := - shift (-v) (patternToOriginConfig p) +def patternToConfig (p : Pattern A G) (v : G) : FullShift A G := + shift (v⁻¹) (patternToOriginConfig p) /-- Restrict a configuration to a finite support, seen as a pattern. -/ -def patternFromConfig (x : Zd d → A) (U : Finset (Zd d)) : Pattern A d := +def patternFromConfig (x : G → A) (U : Finset (G)) : Pattern A G := { support := U, data := fun i => x i.1 } -set_option linter.unusedSectionVars false -/-- Occurrences are cylinders translated by `v`. -/ -lemma occursAt_eq_cylinder (p : Pattern A d) (v : Zd d) : - { x | p.occursIn x v } - = cylinder (p.support.image (· + v)) (patternToConfig p v) := by +section OccursAtEqCylinder +variable {A G : Type*} [Group G] [Inhabited A] [DecidableEq G] +/-- “Occurrence = cylinder translated by `g`”. -/ +lemma occursAt_eq_cylinder (p : Pattern A G) (g : G) : + { x | p.occursIn x g } + = cylinder (p.support.image (· * g)) (patternToConfig p g) := by ext x constructor · intro H u hu obtain ⟨w, hw, rfl⟩ := Finset.mem_image.mp hu dsimp [patternToConfig, patternToOriginConfig, shift] - simp [add_neg_cancel_right, dif_pos hw, H w hw] + simp [dif_pos hw, H w hw] · intro H u hu - have := H (u + v) (Finset.mem_image_of_mem _ hu) + have := H (u * g) (Finset.mem_image_of_mem _ hu) dsimp [patternToConfig, patternToOriginConfig, shift] at this simpa [add_neg_cancel_right, dif_pos hu] using this +end OccursAtEqCylinder -/-- Occurrence sets are closed. -/ -lemma occursAt_closed (p : Pattern A d) (v : Zd d) : - IsClosed { x | p.occursIn x v } := by - rw [occursAt_eq_cylinder]; exact cylinder_is_closed d _ _ +/-! ## Forbidden sets and subshifts -/ + +section OccSetsOpen +variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] + [Inhabited A] [DecidableEq G] /-- Occurrence sets are open. -/ -lemma occursAt_open (p : Pattern A d) (v : Zd d) : - IsOpen { x | p.occursIn x v } := by +lemma occursAt_open (p : Pattern A G) (g : G) : + IsOpen { x | p.occursIn x g } := by rw [occursAt_eq_cylinder]; exact cylinder_is_open _ _ /-- Avoiding a fixed set of patterns is a closed condition. -/ -lemma forbids_closed (F : Set (Pattern A d)) : +lemma forbids_closed (F : Set (Pattern A G)) : IsClosed (forbids F) := by rw [forbids] - have : {x | ∀ p ∈ F, ∀ v : Zd d, ¬ p.occursIn x v} - = ⋂ (p : Pattern A d) (h : p ∈ F), ⋂ (v : Zd d), {x | ¬ p.occursIn x v} := by + have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.occursIn x v} + = ⋂ (p : Pattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.occursIn x v} := by ext x; simp rw [this] refine isClosed_iInter ?_; @@ -312,85 +289,61 @@ lemma forbids_closed (F : Set (Pattern A d)) : intro v; have : {x | ¬p.occursIn x v} = {x | p.occursIn x v}ᶜ := by ext x; simp simpa [this, isClosed_compl_iff] using occursAt_open p v -/-- Subshift defined by forbidden patterns. -/ -def X_F (F : Set (Pattern A d)) : Subshift A d := -{ carrier := forbids F, - is_closed := forbids_closed F, - shift_invariant := forbids_shift_invariant F } +end OccSetsOpen -/-- Subshift of finite type defined by a finite family of forbidden patterns. -/ -def SFT (F : Finset (Pattern A d)) : Subshift A d := - X_F (F : Set (Pattern A d)) +section OccSetsClosed +variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] + [Inhabited A] [DecidableEq G] [Fintype A] [DecidableEq A] -/-! ## Boxes, language, and entropy -/ +/-- Occurrence sets are closed. -/ +lemma occursAt_closed (p : Pattern A G) (g : G) : + IsClosed { x | p.occursIn x g } := by + rw [occursAt_eq_cylinder]; exact cylinder_is_closed _ _ -/-- The box `[-n,n]^d` as a finset of `Zd d`. -/ -def box (n : ℕ) : Finset (Zd d) := - Fintype.piFinset (fun _ ↦ Finset.Icc (-↑n : ℤ) ↑n) +end OccSetsClosed -/-- Language on the box `[-n,n]^d`: patterns obtained by restricting some `x ∈ X`. -/ -def language_box (X : Set (Zd d → A)) (n : ℕ) : Set (Pattern A d) := - { p | ∃ x ∈ X, patternFromConfig x (box n) = p } +/-- Subshift defined by forbidden patterns. -/ +def X_F (F : Set (Pattern A G)) : Subshift A G := +{ carrier := forbids F, + isClosed := forbids_closed F, + shiftInvariant := forbids_shift_invariant F } + +/-- Subshift of finite type defined by a finite family of forbidden patterns. -/ +def SFT (F : Finset (Pattern A G)) : Subshift A G := + X_F (F : Set (Pattern A G)) /-- Patterns with fixed support `U`. -/ -def FixedSupport (A : Type*) (d : ℕ) (U : Finset (Zd d)) := - { p : Pattern A d // p.support = U } - -set_option linter.unnecessarySimpa false -/-- Equivalence `FixedSupport A d U ≃ (U → A)`. -/ -def equivFun {U : Finset (Zd d)} : FixedSupport A d U ≃ (U → A) where - toFun := fun p => fun i => - p.val.data ⟨i.1, by simpa [p.property] using i.2⟩ - invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ - left_inv := by - rintro ⟨p, hp⟩; apply Subtype.ext; cases hp; rfl +def FixedSupport (A : Type*) (G : Type*) [Group G] (U : Finset G) := + { p : Pattern A G // p.support = U } + +/-- `FixedSupport A G U ≃ (U → A)`; gives finiteness immediately. -/ +def equivFun {U : Finset G} : + FixedSupport A G U ≃ (U → A) where + toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ + invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ + left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl right_inv := by intro f; rfl -/-- Finiteness of `FixedSupport A d U`. -/ -instance fintypeFixedSupport (U : Finset (Zd d)) : - Fintype (FixedSupport A d U) := by - classical - exact Fintype.ofEquiv (U → A) (equivFun (A:=A) (d:=d) (U:=U)).symm +instance fintypeFixedSupport {U : Finset G} : + Fintype (FixedSupport A G U) := by + classical exact Fintype.ofEquiv (U → A) (equivFun (A:=A) (G:=G) (U:=U)).symm -/-- Cardinality of the box language (as a finite set), defined via images into -`FixedSupport`. This version is `noncomputable` since it goes through `Set.finite_univ`. -/ -noncomputable def languageCard (X : Set (Zd d → A)) (n : ℕ) : ℕ := by +/-- Language on a finite set `U ⊆ G`: patterns obtained by restricting some `x ∈ X`. -/ +def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := + { p | ∃ x ∈ X, patternFromConfig x U = p } + +/-- Cardinality of the finite-support language. -/ +noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by classical - let U : Finset (Zd d) := box (d:=d) n - let f : {x : Zd d → A // x ∈ X} → FixedSupport A d U := - fun x => ⟨patternFromConfig (A:=A) (d:=d) x.1 U, rfl⟩ - have hfin_univ : (Set.univ : Set (FixedSupport A d U)).Finite := Set.finite_univ - have hfin : (Set.range f).Finite := hfin_univ.subset (by intro y hy; simp) + -- Image of a map into the finite type `FixedSupport A G U` + let f : {x : G → A // x ∈ X} → FixedSupport A G U := + fun x => ⟨patternFromConfig x.1 U, rfl⟩ + have hfin : (Set.range f).Finite := (Set.finite_univ : + (Set.univ : Set (FixedSupport A G U)).Finite) + |>.subset (by intro y hy; simp) exact hfin.toFinset.card -/-- Number of patterns of a subshift on the box of size `n`. -/ -noncomputable def patternCount (Y : Subshift A d) (n : ℕ) : ℕ := - languageCard (A:=A) (d:=d) Y.carrier n - -/-- The box `[-n,n]^d` is nonempty. -/ -@[simp] lemma box_card_pos (d n : ℕ) : 0 < (box (d:=d) n).card := by - classical - have hcoord : - ∀ i : Fin d, (0 : ℤ) ∈ Finset.Icc (-(n : ℤ)) (n : ℤ) := by - intro i - have h0n : (0 : ℤ) ≤ (n : ℤ) := by exact_mod_cast (Nat.zero_le n) - have hneg : -(n : ℤ) ≤ 0 := neg_nonpos.mpr h0n - simp [Finset.mem_Icc, hneg] - have hmem : (0 : Zd d) ∈ box (d:=d) n := - Fintype.mem_piFinset.mpr hcoord - exact Finset.card_pos.mpr ⟨0, hmem⟩ - -/-- `limsup` along `atTop` as the infimum of eventual upper bounds. -/ -noncomputable def limsupAtTop (u : ℕ → ℝ) : ℝ := - sInf { L : ℝ | ∀ᶠ n in Filter.atTop, u n ≤ L } - -/-- Topological entropy via limsup language growth on cubes. -We use `+ 1` inside the logarithm to avoid `log 0`. -/ -noncomputable def entropy (Y : Subshift A d) : ℝ := - limsupAtTop (fun n => - (Real.log ((patternCount (A:=A) (d:=d) Y n + 1 : ℕ))) / - ((box (d:=d) n).card : ℝ)) - -end FullShiftZd +noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := + languageCardOn (A:=A) (G:=G) Y.carrier U end SymbolicDynamics diff --git a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean new file mode 100644 index 00000000000000..821aac58508b30 --- /dev/null +++ b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean @@ -0,0 +1,193 @@ +/- +Copyright (c) 2025 S. Gangloff. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: S. Gangloff +-/ + +import Mathlib.Topology.Basic +import Mathlib.Topology.Instances.Discrete +import Mathlib.Topology.UniformSpace.Pi +import Mathlib.Analysis.SpecialFunctions.Log.Basic +import Mathlib.Order.Filter.Basic +import Mathlib.Data.Finset.Basic +import Mathlib.Data.Int.Basic +import Mathlib.Data.Int.Interval +import Mathlib.Data.Fin.VecNotation + +import Mathlib.Dynamics.SymbolicDynamics.Basic2 + +/-! +# Entropy for subshifts via finite shape systems + +This file defines a limsup-style **topological entropy** for subshifts over a (multiplicative) +group `G`, measured along a chosen sequence of **finite shapes**. The interface is intentionally +lightweight: we parameterize entropy by a family `F : ℕ → Finset G` with nonempty shapes, +and we also package such families into a small record `WordMetricShapes` intended to model +word-metric balls for a finitely generated group. + +The file also provides convenient specializations for `ℤ` and `ℤ^d`, using the standard +segments `[-n,n]` and boxes `[-n,n]^d` (transported to a multiplicative group via +`Multiplicative` to match the right-action convention). + +## Main definitions + +* `limsupAtTop` : `limsup` of a real sequence along `atTop` (as an `sInf` of eventual upper bounds). +* `entropyAlong X F hF` : entropy of a subshift `X : Subshift A G` along finite shapes + `F : ℕ → Finset G` with `hF : ∀ n, 0 < (F n).card`, defined as +`limsup ( log (patternCountOn X (F n) + 1) / |F n| )`. + +The `+ 1` inside the logarithm avoids `log 0`. + +* `WordMetricShapes` : a minimal record consisting of +- `S : Finset G` (a chosen finite generating set, for documentation), +- `F : ℕ → Finset G` (the shapes, e.g. Cayley balls), +- `F_pos : ∀ n, 0 < (F n).card`. +It is purposely small; further axioms (monotonicity, invariance, …) can be added later. + +* `entropy_word Y shapes` : entropy of a subshift `Y` along a `WordMetricShapes` family. + +## Specializations + +* `IntShapes.seg` and `IntShapes.shapesZ` give shapes on `Multiplicative ℤ` corresponding to +the segments `[-n,n]`. `IntShapes.entropy_Z` is the associated entropy. + +* `ZdShapes.box` and `ZdShapes.boxMul` give the boxes `[-n,n]^d` on `ℤ^d` and their image in +`Multiplicative (ℤ^d)`. `ZdShapes.shapesZd` and `ZdShapes.entropy_Zd` are the corresponding +shape system and entropy. + +## Mathematical remarks + +* On **amenable** groups, taking a **Følner sequence** of shapes makes the entropy value +canonical: the limsup is a limit and does not depend on the chosen Følner sequence +(Ornstein–Weiss). This file does not assume amenability; the shape family is an input. + +* For general groups, the value may depend on the chosen shapes/generators; hence the API +keeps the shapes explicit. + +## Conventions + +* We use a **right** action for shifts on configurations: `(shift g x) h = x (h * g)`. +The `ℤ`/`ℤ^d` specializations use `Multiplicative` to align additive intuition with this +right-action convention. + +* Counting of patterns on a finite shape uses `patternCountOn` from the basic group-generic +symbolic dynamics file; discreteness/finite-alphabet assumptions are imported there. +-/ + +noncomputable section +open Set Topology Filter + +namespace SymbolicDynamics +namespace FullShift + +/-! ## Language on finite shapes -/ + +variable {A G : Type*} +variable [Group G] [DecidableEq G] +variable [TopologicalSpace A] +variable [DiscreteTopology A] +variable [Fintype A] [DecidableEq A] [Inhabited A] + +/-! ## Entropy along arbitrary finite shapes -/ + +/-- `limsup` along `atTop` as the infimum of eventual upper bounds. -/ +noncomputable def limsupAtTop (u : ℕ → ℝ) : ℝ := + sInf { L : ℝ | ∀ᶠ n in atTop, u n ≤ L } + +/-- Entropy of a subshift `X` along a sequence of finite shapes `F` with nonempty shapes. -/ +noncomputable def entropyAlong (X : Subshift A G) + (F : ℕ → Finset G) (_ : ∀ n, 0 < (F n).card) : ℝ := + limsupAtTop (fun n => + Real.log (patternCountOn (A:=A) (G:=G) X (F n) + 1) / ((F n).card : ℝ)) + +/-! ## Word-metric style shape systems for finitely generated groups -/ + +/-- A minimal interface for a word-metric shape system (e.g. Cayley balls). +We keep only what we need for `entropy_word`: a sequence of finite shapes and their +nonemptiness. More axioms (monotonicity, invariance properties) can be added later. -/ +structure WordMetricShapes (G : Type*) [Group G] [DecidableEq G] where + (S : Finset G) -- chosen finite generating set (intended symmetric) + (F : ℕ → Finset G) -- shapes, e.g. word-metric balls + (F_pos : ∀ n, 0 < (F n).card) -- nonempty shapes + +/-- Entropy of a subshift along a given word-metric shape system. -/ +noncomputable def entropy_word [DecidableEq G] + (Y : Subshift A G) (shapes : WordMetricShapes G) : ℝ := + entropyAlong (A:=A) (G:=G) Y shapes.F shapes.F_pos + +/-! ## Specializations: `ℤ` and `ℤ^d` -/ + +namespace IntShapes +/-- Segments `[-n,n]` as shapes in `Multiplicative ℤ`. -/ +def seg (n : ℕ) : Finset (Multiplicative ℤ) := + (Finset.Icc (-(n : ℤ)) (n : ℤ)).image Multiplicative.ofAdd + +lemma seg_card_pos (n : ℕ) : 0 < (seg n).card := by + classical + have h0 : (0 : ℤ) ∈ Finset.Icc (-(n : ℤ)) (n : ℤ) := by + have h1 : (0 : ℤ) ≤ (n : ℤ) := by exact_mod_cast Nat.zero_le n + have h2 : -(n : ℤ) ≤ 0 := by simp [neg_nonpos.mpr h1] + simp [Finset.mem_Icc] + refine Finset.card_pos.mpr ?_ + exact ⟨Multiplicative.ofAdd 0, Finset.mem_image.mpr ⟨0, h0, rfl⟩⟩ + +/-- Word-metric style shapes for `ℤ`. -/ +def shapesZ : WordMetricShapes (Multiplicative ℤ) := + { S := {Multiplicative.ofAdd (1 : ℤ), Multiplicative.ofAdd (-1 : ℤ)} + , F := seg + , F_pos := seg_card_pos } + +/-- Entropy on `ℤ` with standard segments. -/ +noncomputable def entropy_Z (Y : Subshift A (Multiplicative ℤ)) : ℝ := + entropy_word (A:=A) (G:=Multiplicative ℤ) Y shapesZ +end IntShapes + +namespace ZdShapes + +variable {d : ℕ} + +/-- The lattice `ℤ^d` as functions `Fin d → ℤ`. -/ +abbrev Zd (d : ℕ) := Fin d → ℤ + + +def box (d : ℕ) (n : ℕ) : Finset (Zd d) := + Fintype.piFinset (fun _ => Finset.Icc (-(n : ℤ)) (n : ℤ)) + +/-- Boxes transported to the multiplicative copy to fit the generic `G`. -/ +def boxMul (d : ℕ) (n : ℕ) : Finset (Multiplicative (Zd d)) := + (box d n).image Multiplicative.ofAdd + +lemma box_card_pos (d n : ℕ) : 0 < (box d n).card := by + classical + have hcoord : ∀ i : Fin d, (0 : ℤ) ∈ Finset.Icc (-(n : ℤ)) (n : ℤ) := by + intro i + have h1 : (0 : ℤ) ≤ (n : ℤ) := by exact_mod_cast Nat.zero_le n + have h2 : -(n : ℤ) ≤ 0 := by simp [neg_nonpos.mpr h1] + simp [Finset.mem_Icc] + have h0 : (fun _ : Fin d => (0 : ℤ)) ∈ box d n := Fintype.mem_piFinset.mpr hcoord + exact Finset.card_pos.mpr ⟨_, h0⟩ + +lemma boxMul_card_pos (d n : ℕ) : 0 < (boxMul d n).card := by + classical + rcases Finset.card_pos.mp (box_card_pos d n) with ⟨z, hz⟩ + refine Finset.card_pos.mpr ?_ + exact ⟨Multiplicative.ofAdd z, Finset.mem_image.mpr ⟨z, hz, rfl⟩⟩ + +/-- Word-metric style shapes for `ℤ^d` using boxes. -/ +def shapesZd (d : ℕ) : WordMetricShapes (Multiplicative (Zd d)) := + { S := + -- ±e_j generators (not used by `entropy_word`, included for completeness) + (Finset.univ.image (fun j : Fin d => Multiplicative.ofAdd + (fun k => if k = j then (1 : ℤ) else 0))) ∪ + (Finset.univ.image (fun j : Fin d => Multiplicative.ofAdd + (fun k => if k = j then (-1 : ℤ) else 0))) + , F := fun n => boxMul d n + , F_pos := boxMul_card_pos d } + +/-- Entropy on `ℤ^d` with standard boxes. -/ +noncomputable def entropy_Zd (Y : Subshift A (Multiplicative (Zd d))) : ℝ := + entropy_word (A:=A) (G:=Multiplicative (Zd d)) Y (shapesZd d) +end ZdShapes + +end FullShift +end SymbolicDynamics From ccb6bd98269658602ede7398865e34290ad14834 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Mon, 18 Aug 2025 10:54:04 +0200 Subject: [PATCH 05/93] chore: update import-all (lake exe mk_all) --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index 46dcfcb2abd617..21ce0c1671a408 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3857,6 +3857,7 @@ import Mathlib.Dynamics.OmegaLimit import Mathlib.Dynamics.PeriodicPts.Defs import Mathlib.Dynamics.PeriodicPts.Lemmas import Mathlib.Dynamics.SymbolicDynamics.Basic +import Mathlib.Dynamics.SymbolicDynamics.EntropyFinitelyGenerated import Mathlib.Dynamics.TopologicalEntropy.CoverEntropy import Mathlib.Dynamics.TopologicalEntropy.DynamicalEntourage import Mathlib.Dynamics.TopologicalEntropy.NetEntropy From e2ef52188e60b9295aab76079cb7b8d3a8486cfe Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Mon, 18 Aug 2025 11:00:05 +0200 Subject: [PATCH 06/93] typo --- Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean index 821aac58508b30..78a90ed37d6a5c 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean @@ -14,7 +14,7 @@ import Mathlib.Data.Int.Basic import Mathlib.Data.Int.Interval import Mathlib.Data.Fin.VecNotation -import Mathlib.Dynamics.SymbolicDynamics.Basic2 +import Mathlib.Dynamics.SymbolicDynamics.Basic /-! # Entropy for subshifts via finite shape systems From 9e74c6b6072be21bc3c731fd77a0847ff266b813 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Mon, 18 Aug 2025 11:13:25 +0200 Subject: [PATCH 07/93] refactor(symbolic-dynamics): cylinder_is_open via isOpen_set_pi using cylinder_eq_set_pi (no logic change) --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 26 ++++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 18c125f5755a28..ed52ddca0c109b 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -119,22 +119,16 @@ end CylindersDefs section CylindersOpen variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] /-- Cylinders are open (and, dually, closed) when `A` is discrete. -/ -lemma cylinder_is_open (U : Finset (G)) (x : G → A) : - IsOpen (cylinder U x) := by - let S : Set (FullShift A G) := ⋂ i ∈ U, { y | y i = x i } - have : cylinder U x = S := by - ext y - rw [cylinder, mem_setOf_eq] - rw [mem_iInter₂] - simp only [mem_setOf_eq] - rw [this] - apply isOpen_biInter_finset - intro i _ - have : { y : FullShift A G | y i = x i } = (fun y ↦ y i) ⁻¹' {x i} := rfl - rw [this] - apply Continuous.isOpen_preimage - · exact continuous_apply i - · exact isOpen_discrete ({x i} : Set A) +lemma cylinder_is_open (U : Finset G) (x : G → A) : + IsOpen (cylinder (A:=A) (G:=G) U x) := by + classical + have hopen : ∀ i ∈ (↑U : Set G), IsOpen ({x i} : Set A) := by + intro i _; simp + have hpi : + IsOpen (Set.pi (s := (↑U : Set G)) + (t := fun i => ({x i} : Set A))) := + isOpen_set_pi (U.finite_toSet) hopen + simpa [cylinder_eq_set_pi (A:=A) (G:=G) U x] using hpi end CylindersOpen section CylindersClosed From 88dbf5fd47e3347ae723e1fca7d396f7ae7d6e5b Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Mon, 18 Aug 2025 11:19:30 +0200 Subject: [PATCH 08/93] chore(symbolic-dynamics): replace Pi/Discrete imports with Topology.Constructions --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index ed52ddca0c109b..1493f01fdfa976 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -5,8 +5,7 @@ Authors: S. Gangloff -/ import Mathlib.Topology.Basic -import Mathlib.Topology.UniformSpace.Pi -import Mathlib.Topology.Instances.Discrete +import Mathlib.Topology.Constructions import Mathlib.Data.Finset.Basic import Mathlib.Logic.Equiv.Defs From c3c201c725b5bbe97b12b8c6904a1b41f14182fd Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Mon, 18 Aug 2025 12:15:37 +0200 Subject: [PATCH 09/93] refactor(symbolic-dynamics): prove via --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 59 ++++++------------- .../EntropyFinitelyGenerated.lean | 16 ++--- 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 1493f01fdfa976..d5e2a61e05fdd7 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -132,54 +132,28 @@ end CylindersOpen section CylindersClosed variable {A G : Type*} -[TopologicalSpace A] [DiscreteTopology A] [Fintype A] [DecidableEq A] [DecidableEq G] -lemma cylinder_is_closed (U : Finset (G)) (x : G → A) : - IsClosed (cylinder U x) := by - have h : (cylinder U x)ᶜ = ⋃ (i ∈ U) (a ∈ (Finset.univ \ {x i} : Finset A)), - cylinder {i} (Function.update x i a) := by - · ext y - simp only [mem_compl_iff] - simp only [mem_iUnion] - simp only [mem_cylinder] - simp only [Finset.mem_univ, Finset.mem_sdiff] - simp only [not_forall] - simp only [exists_prop] - constructor - · intro hy - push_neg at hy - obtain ⟨i, hiU, hiy⟩ := hy - use i, hiU, y i - constructor - · simp [hiy] - · simp [Function.update_apply] - · rintro ⟨i, hiU, a, ha, hy⟩ - simp only [true_and] at ha - use i, hiU - rw [hy] - simp only [Function.update_apply] - have hne : a ≠ x i := by - intro h - apply ha - rw [h] - exact Finset.mem_singleton_self _ - exact hne - exact Finset.mem_singleton_self i - have : IsOpen ((cylinder U x)ᶜ) := by - rw [h] - apply isOpen_iUnion; intro i - apply isOpen_iUnion; intro hi - apply isOpen_iUnion; intro a - apply isOpen_iUnion; intro ha - exact cylinder_is_open {i} (Function.update x i a) - exact isOpen_compl_iff.mp this +[TopologicalSpace A] [DiscreteTopology A] +lemma cylinder_is_closed (U : Finset G) (x : G → A) : + IsClosed (cylinder (A:=A) (G:=G) U x) := by + classical + have hclosed : ∀ i ∈ (↑U : Set G), IsClosed ({x i} : Set A) := by + intro i _; simp + have hpi : + IsClosed (Set.pi (s := (↑U : Set G)) + (t := fun i => ({x i} : Set A))) := + isClosed_set_pi hclosed + simpa [cylinder_eq_set_pi (A:=A) (G:=G) U x] using hpi end CylindersClosed /-! ## Patterns and occurrences -/ /-- A subshift is a closed, shift-invariant subset. -/ structure Subshift (A : Type*) [TopologicalSpace A] [Inhabited A] (G : Type*) [Group G] where + /-- The underlying set of configurations. -/ carrier : Set (FullShift A G) + /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier + /-- Shift invariance of `carrier`. -/ shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift (A:=A) (G:=G) g x ∈ carrier /-- The full shift is a subshift. -/ @@ -191,7 +165,9 @@ example : Subshift A G := /-- A finite pattern: finite support in `G` and values on it. -/ structure Pattern (A : Type*) (G : Type*) [Group G] where + /-- Finite support of the pattern. -/ support : Finset G + /-- The value (symbol) at each point of the support. -/ data : support → A /-- The domino supported on `{i,j}` with values `ai`,`aj`. -/ @@ -286,7 +262,7 @@ end OccSetsOpen section OccSetsClosed variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] - [Inhabited A] [DecidableEq G] [Fintype A] [DecidableEq A] + [Inhabited A] [DecidableEq G] /-- Occurrence sets are closed. -/ lemma occursAt_closed (p : Pattern A G) (g : G) : @@ -336,6 +312,7 @@ noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by |>.subset (by intro y hy; simp) exact hfin.toFinset.card +/-- Number of patterns of a subshift on a finite shape `U`. -/ noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := languageCardOn (A:=A) (G:=G) Y.carrier U diff --git a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean index 78a90ed37d6a5c..57cdfcb856561a 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean @@ -13,7 +13,6 @@ import Mathlib.Data.Finset.Basic import Mathlib.Data.Int.Basic import Mathlib.Data.Int.Interval import Mathlib.Data.Fin.VecNotation - import Mathlib.Dynamics.SymbolicDynamics.Basic /-! @@ -96,7 +95,7 @@ noncomputable def limsupAtTop (u : ℕ → ℝ) : ℝ := /-- Entropy of a subshift `X` along a sequence of finite shapes `F` with nonempty shapes. -/ noncomputable def entropyAlong (X : Subshift A G) - (F : ℕ → Finset G) (_ : ∀ n, 0 < (F n).card) : ℝ := + (F : ℕ → Finset G) : ℝ := limsupAtTop (fun n => Real.log (patternCountOn (A:=A) (G:=G) X (F n) + 1) / ((F n).card : ℝ)) @@ -106,14 +105,17 @@ noncomputable def entropyAlong (X : Subshift A G) We keep only what we need for `entropy_word`: a sequence of finite shapes and their nonemptiness. More axioms (monotonicity, invariance properties) can be added later. -/ structure WordMetricShapes (G : Type*) [Group G] [DecidableEq G] where - (S : Finset G) -- chosen finite generating set (intended symmetric) - (F : ℕ → Finset G) -- shapes, e.g. word-metric balls - (F_pos : ∀ n, 0 < (F n).card) -- nonempty shapes + /-- A chosen finite generating set (intended symmetric). -/ + (S : Finset G) + /-- The finite shapes, typically word-metric balls. -/ + (F : ℕ → Finset G) + /-- Nonemptiness of each shape. -/ + (F_pos : ∀ n, 0 < (F n).card) /-- Entropy of a subshift along a given word-metric shape system. -/ noncomputable def entropy_word [DecidableEq G] (Y : Subshift A G) (shapes : WordMetricShapes G) : ℝ := - entropyAlong (A:=A) (G:=G) Y shapes.F shapes.F_pos + entropyAlong (A:=A) (G:=G) Y shapes.F /-! ## Specializations: `ℤ` and `ℤ^d` -/ @@ -149,7 +151,7 @@ variable {d : ℕ} /-- The lattice `ℤ^d` as functions `Fin d → ℤ`. -/ abbrev Zd (d : ℕ) := Fin d → ℤ - +/-- The axis-aligned box `[-n,n]^d` in `ℤ^d` (as a `Finset`). -/ def box (d : ℕ) (n : ℕ) : Finset (Zd d) := Fintype.piFinset (fun _ => Finset.Icc (-(n : ℤ)) (n : ℤ)) From 628716e5faf321ceb6b74537443ff3f7ef0d3058 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Fri, 5 Sep 2025 09:28:04 +0200 Subject: [PATCH 10/93] changed full shift to G -> A and wrote the full shift as example of subshift --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 31 +++++++++----------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index d5e2a61e05fdd7..cb3da4287fc02b 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -69,22 +69,19 @@ variable [Group G] [DecidableEq G] /-! ## Full shift and shift action -/ -/-- Full shift over a group `G` with alphabet `A` (product topology). -/ -abbrev FullShift (A G) := G → A - /-- Right-translation shift: `(shift g x)(h) = x (h * g)`. -/ -def shift (g : G) (x : FullShift A G) : FullShift A G := +def shift (g : G) (x : G → A) : G → A := fun h => x (h * g) section ShiftAlgebra variable {A G : Type*} [Group G] -@[simp] lemma shift_apply (g h : G) (x : FullShift A G) : +@[simp] lemma shift_apply (g h : G) (x : G → A) : shift g x h = x (h * g) := rfl -@[simp] lemma shift_one (x : FullShift A G) : shift (1 : G) x = x := by +@[simp] lemma shift_one (x : G → A) : shift (1 : G) x = x := by ext h; simp [shift] -lemma shift_mul (g₁ g₂ : G) (x : FullShift A G) : +lemma shift_mul (g₁ g₂ : G) (x : G → A) : shift (g₁ * g₂) x = shift g₁ (shift g₂ x) := by ext h; simp [shift, mul_assoc] end ShiftAlgebra @@ -104,14 +101,14 @@ section CylindersDefs variable {A G : Type*} /-- Cylinder fixing `x` on the finite set `U`. -/ -def cylinder (U : Finset G) (x : FullShift A G) : Set (FullShift A G) := +def cylinder (U : Finset G) (x : G → A) : Set (G → A) := { y | ∀ i ∈ U, y i = x i } lemma cylinder_eq_set_pi (U : Finset (G)) (x : G → A) : cylinder U x = Set.pi (↑U : Set (G)) (fun i => ({x i} : Set A)) := by ext y; simp [cylinder, Set.pi, Finset.mem_coe] -@[simp] lemma mem_cylinder {U : Finset G} {x y : FullShift A G} : +@[simp] lemma mem_cylinder {U : Finset G} {x y : G → A} : y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl end CylindersDefs @@ -150,14 +147,14 @@ end CylindersClosed /-- A subshift is a closed, shift-invariant subset. -/ structure Subshift (A : Type*) [TopologicalSpace A] [Inhabited A] (G : Type*) [Group G] where /-- The underlying set of configurations. -/ - carrier : Set (FullShift A G) + carrier : Set (G → A) /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier /-- Shift invariance of `carrier`. -/ shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift (A:=A) (G:=G) g x ∈ carrier -/-- The full shift is a subshift. -/ -example : Subshift A G := +/-- Example: the full shift on alphabet A. -/ +def fullShift (A G) [TopologicalSpace A] [Inhabited A] [Group G] : Subshift A G := { carrier := Set.univ, isClosed := isClosed_univ, shiftInvariant := by intro _ _ _; simp } @@ -178,18 +175,18 @@ def domino {A : Type*} , data := fun ⟨z, hz⟩ => if z = i then ai else aj } /-- Occurrence of a pattern `p` in `x` at position `g`. -/ -def Pattern.occursIn (p : Pattern A G) (x : FullShift A G) (g : G) : Prop := +def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ /-- Configurations avoiding every pattern in `F`. -/ -def forbids (F : Set (Pattern A G)) : Set (FullShift A G) := +def forbids (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } section ShiftInvariance variable {A G : Type*} [Group G] /-- Shifts move occurrences as expected. -/ -lemma occurs_shift (p : Pattern A G) (x : FullShift A G) (g h : G) : +lemma occurs_shift (p : Pattern A G) (x : G → A) (g h : G) : p.occursIn (shift h x) g ↔ p.occursIn x (g * h) := by constructor <;> intro H u hu <;> simpa [shift, mul_assoc] using H u hu @@ -203,11 +200,11 @@ lemma forbids_shift_invariant (F : Set (Pattern A G)) : end ShiftInvariance /-- Extend a pattern by `default` away from its support (anchored at the origin). -/ -def patternToOriginConfig (p : Pattern A G) : FullShift A G := +def patternToOriginConfig (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default /-- Translate a pattern to occur at `v`. -/ -def patternToConfig (p : Pattern A G) (v : G) : FullShift A G := +def patternToConfig (p : Pattern A G) (v : G) : G → A := shift (v⁻¹) (patternToOriginConfig p) /-- Restrict a configuration to a finite support, seen as a pattern. -/ From 9308c83ba3232052431c965ad892f534dc176368 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 09:03:14 +0200 Subject: [PATCH 11/93] chore(Dynamics/SymbolicDynamics/Basic): drop references --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 22 ++++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index cb3da4287fc02b..e68f20ad1c21bf 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -13,19 +13,18 @@ import Mathlib.Logic.Equiv.Defs # Symbolic dynamics on groups This file develops a minimal API for symbolic dynamics over an arbitrary group `G`. -The ambient space is the full shift -`FullShift A G := G → A` (an `abbrev`), hence it inherits the product topology -from the Π-type. We define the right-translation action, cylinders, finite patterns, -their occurrences, forbidden sets, and subshifts (closed, shift-invariant subsets). -Basic topological statements (e.g. cylinders are clopen, occurrence sets are clopen, -forbidden sets are closed) are proved under discreteness assumptions on the alphabet. +Provided a finite set `A`, the ambient space is the space of functions from `G` to `A`, +hence it inherits the product topology from the Π-type. We define the right-translation action, +cylinders, finite patterns, their occurrences, forbidden sets, and subshifts (closed, +shift-invariant subsets). Basic topological statements (e.g. cylinders are clopen, +occurrence sets are clopen, forbidden sets are closed) are proved under discreteness +assumptions on the alphabet. The file is group-generic. Geometry specific to `ℤ^d` (boxes/cubes and the box-based entropy) is kept in a separate specialization. ## Main definitions -* `FullShift A G := G → A`. * `shift g x` — right translation: `(shift g x) h = x (h * g)`. * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. * `Pattern A G` — finite support together with values on that support. @@ -41,21 +40,12 @@ We use a **right** action of `G` on configurations: ## Implementation notes -* Since `FullShift A G` is an `abbrev` for `G → A`, instances such as - `TopologicalSpace (FullShift A G)` and `Inhabited (FullShift A G)` are inherited - automatically from the Π-type; no explicit instances are declared here. * Openness/closedness results for cylinders and occurrence sets use `[DiscreteTopology A]`. The closedness proofs that enumerate values additionally require `[Fintype A]`, `[DecidableEq A]`, and `[DecidableEq G]` (for `Finset` manipulations and `Function.update`). -/ --- TODO: --- In entropy, match the namespaces of basic2 ? --- 3. Rewrite documentation --- 4. CI checks --- 5. Rewrite the PR description ? Make comments ? - noncomputable section open Set Topology From a934d4b4901b5b9578800912a8d4b5ed84e4d3f6 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 09:12:52 +0200 Subject: [PATCH 12/93] style(Dynamics/SymbolicDynamics/Basic): fix indentation in lemmas --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index e68f20ad1c21bf..f76ba8fbd1e055 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -95,18 +95,18 @@ def cylinder (U : Finset G) (x : G → A) : Set (G → A) := { y | ∀ i ∈ U, y i = x i } lemma cylinder_eq_set_pi (U : Finset (G)) (x : G → A) : - cylinder U x = Set.pi (↑U : Set (G)) (fun i => ({x i} : Set A)) := by + cylinder U x = Set.pi (↑U : Set (G)) (fun i => ({x i} : Set A)) := by ext y; simp [cylinder, Set.pi, Finset.mem_coe] @[simp] lemma mem_cylinder {U : Finset G} {x y : G → A} : - y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl + y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl end CylindersDefs section CylindersOpen variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] /-- Cylinders are open (and, dually, closed) when `A` is discrete. -/ lemma cylinder_is_open (U : Finset G) (x : G → A) : - IsOpen (cylinder (A:=A) (G:=G) U x) := by + IsOpen (cylinder (A:=A) (G:=G) U x) := by classical have hopen : ∀ i ∈ (↑U : Set G), IsOpen ({x i} : Set A) := by intro i _; simp @@ -121,7 +121,7 @@ section CylindersClosed variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] lemma cylinder_is_closed (U : Finset G) (x : G → A) : - IsClosed (cylinder (A:=A) (G:=G) U x) := by + IsClosed (cylinder (A:=A) (G:=G) U x) := by classical have hclosed : ∀ i ∈ (↑U : Set G), IsClosed ({x i} : Set A) := by intro i _; simp @@ -177,11 +177,11 @@ section ShiftInvariance variable {A G : Type*} [Group G] /-- Shifts move occurrences as expected. -/ lemma occurs_shift (p : Pattern A G) (x : G → A) (g h : G) : - p.occursIn (shift h x) g ↔ p.occursIn x (g * h) := by + p.occursIn (shift h x) g ↔ p.occursIn x (g * h) := by constructor <;> intro H u hu <;> simpa [shift, mul_assoc] using H u hu lemma forbids_shift_invariant (F : Set (Pattern A G)) : - ∀ h : G, ∀ x ∈ forbids (A:=A) (G:=G) F, shift h x ∈ forbids F := by + ∀ h : G, ∀ x ∈ forbids (A:=A) (G:=G) F, shift h x ∈ forbids F := by intro h x hx p hp g specialize hx p hp (g * h) -- contraposition @@ -206,8 +206,7 @@ section OccursAtEqCylinder variable {A G : Type*} [Group G] [Inhabited A] [DecidableEq G] /-- “Occurrence = cylinder translated by `g`”. -/ lemma occursAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.occursIn x g } - = cylinder (p.support.image (· * g)) (patternToConfig p g) := by + { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (patternToConfig p g) := by ext x constructor · intro H u hu @@ -233,7 +232,7 @@ lemma occursAt_open (p : Pattern A G) (g : G) : /-- Avoiding a fixed set of patterns is a closed condition. -/ lemma forbids_closed (F : Set (Pattern A G)) : - IsClosed (forbids F) := by + IsClosed (forbids F) := by rw [forbids] have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.occursIn x v} = ⋂ (p : Pattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.occursIn x v} := by From ffec9dd5b6bcd27fa335b95c8be9efd219c7daaa Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 09:18:40 +0200 Subject: [PATCH 13/93] style(Dynamics/SymbolicDynamics/Basic): add spaces around in variable declarations --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index f76ba8fbd1e055..61c3ec206bf7e3 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -78,7 +78,7 @@ end ShiftAlgebra section ShiftTopology -- add only topology on A variable {A G : Type*} [Group G] [TopologicalSpace A] -lemma shift_continuous (g : G) : Continuous (shift (A:=A) (G:=G) g) := by +lemma continuous_shift (g : G) : Continuous (shift (A := A) (G := G) g) := by -- coordinate projections are continuous; composition preserves continuity continuity end ShiftTopology @@ -94,8 +94,8 @@ variable {A G : Type*} def cylinder (U : Finset G) (x : G → A) : Set (G → A) := { y | ∀ i ∈ U, y i = x i } -lemma cylinder_eq_set_pi (U : Finset (G)) (x : G → A) : - cylinder U x = Set.pi (↑U : Set (G)) (fun i => ({x i} : Set A)) := by +lemma cylinder_eq_set_pi (U : Finset G) (x : G → A) : + cylinder U x = Set.pi (↑U : Set G) (fun i => ({x i} : Set A)) := by ext y; simp [cylinder, Set.pi, Finset.mem_coe] @[simp] lemma mem_cylinder {U : Finset G} {x y : G → A} : @@ -106,7 +106,7 @@ section CylindersOpen variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] /-- Cylinders are open (and, dually, closed) when `A` is discrete. -/ lemma cylinder_is_open (U : Finset G) (x : G → A) : - IsOpen (cylinder (A:=A) (G:=G) U x) := by + IsOpen (cylinder (A := A) (G := G) U x) := by classical have hopen : ∀ i ∈ (↑U : Set G), IsOpen ({x i} : Set A) := by intro i _; simp @@ -114,14 +114,14 @@ lemma cylinder_is_open (U : Finset G) (x : G → A) : IsOpen (Set.pi (s := (↑U : Set G)) (t := fun i => ({x i} : Set A))) := isOpen_set_pi (U.finite_toSet) hopen - simpa [cylinder_eq_set_pi (A:=A) (G:=G) U x] using hpi + simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi end CylindersOpen section CylindersClosed variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] lemma cylinder_is_closed (U : Finset G) (x : G → A) : - IsClosed (cylinder (A:=A) (G:=G) U x) := by + IsClosed (cylinder (A := A) (G := G) U x) := by classical have hclosed : ∀ i ∈ (↑U : Set G), IsClosed ({x i} : Set A) := by intro i _; simp @@ -129,7 +129,7 @@ lemma cylinder_is_closed (U : Finset G) (x : G → A) : IsClosed (Set.pi (s := (↑U : Set G)) (t := fun i => ({x i} : Set A))) := isClosed_set_pi hclosed - simpa [cylinder_eq_set_pi (A:=A) (G:=G) U x] using hpi + simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi end CylindersClosed /-! ## Patterns and occurrences -/ @@ -141,7 +141,7 @@ structure Subshift (A : Type*) [TopologicalSpace A] [Inhabited A] (G : Type*) [G /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier /-- Shift invariance of `carrier`. -/ - shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift (A:=A) (G:=G) g x ∈ carrier + shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift (A := A) (G := G) g x ∈ carrier /-- Example: the full shift on alphabet A. -/ def fullShift (A G) [TopologicalSpace A] [Inhabited A] [Group G] : Subshift A G := @@ -161,7 +161,7 @@ structure Pattern (A : Type*) (G : Type*) [Group G] where def domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by refine - { support := ({i, j} : Finset (G)) + { support := ({i, j} : Finset G) , data := fun ⟨z, hz⟩ => if z = i then ai else aj } /-- Occurrence of a pattern `p` in `x` at position `g`. -/ @@ -181,7 +181,7 @@ lemma occurs_shift (p : Pattern A G) (x : G → A) (g h : G) : constructor <;> intro H u hu <;> simpa [shift, mul_assoc] using H u hu lemma forbids_shift_invariant (F : Set (Pattern A G)) : - ∀ h : G, ∀ x ∈ forbids (A:=A) (G:=G) F, shift h x ∈ forbids F := by + ∀ h : G, ∀ x ∈ forbids (A := A) (G := G) F, shift h x ∈ forbids F := by intro h x hx p hp g specialize hx p hp (g * h) -- contraposition @@ -198,7 +198,7 @@ def patternToConfig (p : Pattern A G) (v : G) : G → A := shift (v⁻¹) (patternToOriginConfig p) /-- Restrict a configuration to a finite support, seen as a pattern. -/ -def patternFromConfig (x : G → A) (U : Finset (G)) : Pattern A G := +def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := { support := U, data := fun i => x i.1 } @@ -281,7 +281,7 @@ def equivFun {U : Finset G} : instance fintypeFixedSupport {U : Finset G} : Fintype (FixedSupport A G U) := by - classical exact Fintype.ofEquiv (U → A) (equivFun (A:=A) (G:=G) (U:=U)).symm + classical exact Fintype.ofEquiv (U → A) (equivFun (A := A) (G := G) (U := U)).symm /-- Language on a finite set `U ⊆ G`: patterns obtained by restricting some `x ∈ X`. -/ def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := @@ -300,6 +300,6 @@ noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by /-- Number of patterns of a subshift on a finite shape `U`. -/ noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := - languageCardOn (A:=A) (G:=G) Y.carrier U + languageCardOn (A := A) (G := G) Y.carrier U end SymbolicDynamics From 6701825f4dc61c822c35602a2a80410c05cf5aa2 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 09:34:15 +0200 Subject: [PATCH 14/93] style(Dynamics/SymbolicDynamics/Basic): apply remaining style changes --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 28 +++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 61c3ec206bf7e3..b63b81ba0d097f 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -51,7 +51,7 @@ open Set Topology namespace SymbolicDynamics -variable {A : Type*} [Fintype A] [Fintype A] [DecidableEq A] [Inhabited A] +variable {A : Type*} [Fintype A] [Inhabited A] variable {G : Type*} variable [TopologicalSpace A] [DiscreteTopology A] variable [Group G] [DecidableEq G] @@ -59,12 +59,14 @@ variable [Group G] [DecidableEq G] /-! ## Full shift and shift action -/ -/-- Right-translation shift: `(shift g x)(h) = x (h * g)`. -/ +/-- Right-translation shift: `(shift g x) (h) = x (h * g)`. -/ def shift (g : G) (x : G → A) : G → A := fun h => x (h * g) section ShiftAlgebra + variable {A G : Type*} [Group G] + @[simp] lemma shift_apply (g h : G) (x : G → A) : shift g x h = x (h * g) := rfl @@ -74,13 +76,16 @@ variable {A G : Type*} [Group G] lemma shift_mul (g₁ g₂ : G) (x : G → A) : shift (g₁ * g₂) x = shift g₁ (shift g₂ x) := by ext h; simp [shift, mul_assoc] + end ShiftAlgebra section ShiftTopology -- add only topology on A + variable {A G : Type*} [Group G] [TopologicalSpace A] lemma continuous_shift (g : G) : Continuous (shift (A := A) (G := G) g) := by -- coordinate projections are continuous; composition preserves continuity continuity + end ShiftTopology @@ -88,6 +93,7 @@ end ShiftTopology /-! ## Cylinders -/ section CylindersDefs + variable {A G : Type*} /-- Cylinder fixing `x` on the finite set `U`. -/ @@ -100,10 +106,13 @@ lemma cylinder_eq_set_pi (U : Finset G) (x : G → A) : @[simp] lemma mem_cylinder {U : Finset G} {x y : G → A} : y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl + end CylindersDefs section CylindersOpen + variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] + /-- Cylinders are open (and, dually, closed) when `A` is discrete. -/ lemma cylinder_is_open (U : Finset G) (x : G → A) : IsOpen (cylinder (A := A) (G := G) U x) := by @@ -115,11 +124,13 @@ lemma cylinder_is_open (U : Finset G) (x : G → A) : (t := fun i => ({x i} : Set A))) := isOpen_set_pi (U.finite_toSet) hopen simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi + end CylindersOpen section CylindersClosed -variable {A G : Type*} -[TopologicalSpace A] [DiscreteTopology A] + +variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] + lemma cylinder_is_closed (U : Finset G) (x : G → A) : IsClosed (cylinder (A := A) (G := G) U x) := by classical @@ -130,6 +141,7 @@ lemma cylinder_is_closed (U : Finset G) (x : G → A) : (t := fun i => ({x i} : Set A))) := isClosed_set_pi hclosed simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi + end CylindersClosed /-! ## Patterns and occurrences -/ @@ -174,7 +186,9 @@ def forbids (F : Set (Pattern A G)) : Set (G → A) := section ShiftInvariance + variable {A G : Type*} [Group G] + /-- Shifts move occurrences as expected. -/ lemma occurs_shift (p : Pattern A G) (x : G → A) (g h : G) : p.occursIn (shift h x) g ↔ p.occursIn x (g * h) := by @@ -187,6 +201,7 @@ lemma forbids_shift_invariant (F : Set (Pattern A G)) : -- contraposition contrapose! hx simpa [occurs_shift] using hx + end ShiftInvariance /-- Extend a pattern by `default` away from its support (anchored at the origin). -/ @@ -203,7 +218,9 @@ def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := data := fun i => x i.1 } section OccursAtEqCylinder + variable {A G : Type*} [Group G] [Inhabited A] [DecidableEq G] + /-- “Occurrence = cylinder translated by `g`”. -/ lemma occursAt_eq_cylinder (p : Pattern A G) (g : G) : { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (patternToConfig p g) := by @@ -217,11 +234,13 @@ lemma occursAt_eq_cylinder (p : Pattern A G) (g : G) : have := H (u * g) (Finset.mem_image_of_mem _ hu) dsimp [patternToConfig, patternToOriginConfig, shift] at this simpa [add_neg_cancel_right, dif_pos hu] using this + end OccursAtEqCylinder /-! ## Forbidden sets and subshifts -/ section OccSetsOpen + variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] [DecidableEq G] @@ -247,6 +266,7 @@ lemma forbids_closed (F : Set (Pattern A G)) : end OccSetsOpen section OccSetsClosed + variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] [DecidableEq G] From 4ee2fbc4020bbc8b067c60a5c98c29e4ebefb1d9 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 09:36:03 +0200 Subject: [PATCH 15/93] style(Dynamics/SymbolicDynamics/Basic): removed entropy part --- .../EntropyFinitelyGenerated.lean | 195 ------------------ 1 file changed, 195 deletions(-) delete mode 100644 Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean diff --git a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean deleted file mode 100644 index 57cdfcb856561a..00000000000000 --- a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean +++ /dev/null @@ -1,195 +0,0 @@ -/- -Copyright (c) 2025 S. Gangloff. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: S. Gangloff --/ - -import Mathlib.Topology.Basic -import Mathlib.Topology.Instances.Discrete -import Mathlib.Topology.UniformSpace.Pi -import Mathlib.Analysis.SpecialFunctions.Log.Basic -import Mathlib.Order.Filter.Basic -import Mathlib.Data.Finset.Basic -import Mathlib.Data.Int.Basic -import Mathlib.Data.Int.Interval -import Mathlib.Data.Fin.VecNotation -import Mathlib.Dynamics.SymbolicDynamics.Basic - -/-! -# Entropy for subshifts via finite shape systems - -This file defines a limsup-style **topological entropy** for subshifts over a (multiplicative) -group `G`, measured along a chosen sequence of **finite shapes**. The interface is intentionally -lightweight: we parameterize entropy by a family `F : ℕ → Finset G` with nonempty shapes, -and we also package such families into a small record `WordMetricShapes` intended to model -word-metric balls for a finitely generated group. - -The file also provides convenient specializations for `ℤ` and `ℤ^d`, using the standard -segments `[-n,n]` and boxes `[-n,n]^d` (transported to a multiplicative group via -`Multiplicative` to match the right-action convention). - -## Main definitions - -* `limsupAtTop` : `limsup` of a real sequence along `atTop` (as an `sInf` of eventual upper bounds). -* `entropyAlong X F hF` : entropy of a subshift `X : Subshift A G` along finite shapes - `F : ℕ → Finset G` with `hF : ∀ n, 0 < (F n).card`, defined as -`limsup ( log (patternCountOn X (F n) + 1) / |F n| )`. - -The `+ 1` inside the logarithm avoids `log 0`. - -* `WordMetricShapes` : a minimal record consisting of -- `S : Finset G` (a chosen finite generating set, for documentation), -- `F : ℕ → Finset G` (the shapes, e.g. Cayley balls), -- `F_pos : ∀ n, 0 < (F n).card`. -It is purposely small; further axioms (monotonicity, invariance, …) can be added later. - -* `entropy_word Y shapes` : entropy of a subshift `Y` along a `WordMetricShapes` family. - -## Specializations - -* `IntShapes.seg` and `IntShapes.shapesZ` give shapes on `Multiplicative ℤ` corresponding to -the segments `[-n,n]`. `IntShapes.entropy_Z` is the associated entropy. - -* `ZdShapes.box` and `ZdShapes.boxMul` give the boxes `[-n,n]^d` on `ℤ^d` and their image in -`Multiplicative (ℤ^d)`. `ZdShapes.shapesZd` and `ZdShapes.entropy_Zd` are the corresponding -shape system and entropy. - -## Mathematical remarks - -* On **amenable** groups, taking a **Følner sequence** of shapes makes the entropy value -canonical: the limsup is a limit and does not depend on the chosen Følner sequence -(Ornstein–Weiss). This file does not assume amenability; the shape family is an input. - -* For general groups, the value may depend on the chosen shapes/generators; hence the API -keeps the shapes explicit. - -## Conventions - -* We use a **right** action for shifts on configurations: `(shift g x) h = x (h * g)`. -The `ℤ`/`ℤ^d` specializations use `Multiplicative` to align additive intuition with this -right-action convention. - -* Counting of patterns on a finite shape uses `patternCountOn` from the basic group-generic -symbolic dynamics file; discreteness/finite-alphabet assumptions are imported there. --/ - -noncomputable section -open Set Topology Filter - -namespace SymbolicDynamics -namespace FullShift - -/-! ## Language on finite shapes -/ - -variable {A G : Type*} -variable [Group G] [DecidableEq G] -variable [TopologicalSpace A] -variable [DiscreteTopology A] -variable [Fintype A] [DecidableEq A] [Inhabited A] - -/-! ## Entropy along arbitrary finite shapes -/ - -/-- `limsup` along `atTop` as the infimum of eventual upper bounds. -/ -noncomputable def limsupAtTop (u : ℕ → ℝ) : ℝ := - sInf { L : ℝ | ∀ᶠ n in atTop, u n ≤ L } - -/-- Entropy of a subshift `X` along a sequence of finite shapes `F` with nonempty shapes. -/ -noncomputable def entropyAlong (X : Subshift A G) - (F : ℕ → Finset G) : ℝ := - limsupAtTop (fun n => - Real.log (patternCountOn (A:=A) (G:=G) X (F n) + 1) / ((F n).card : ℝ)) - -/-! ## Word-metric style shape systems for finitely generated groups -/ - -/-- A minimal interface for a word-metric shape system (e.g. Cayley balls). -We keep only what we need for `entropy_word`: a sequence of finite shapes and their -nonemptiness. More axioms (monotonicity, invariance properties) can be added later. -/ -structure WordMetricShapes (G : Type*) [Group G] [DecidableEq G] where - /-- A chosen finite generating set (intended symmetric). -/ - (S : Finset G) - /-- The finite shapes, typically word-metric balls. -/ - (F : ℕ → Finset G) - /-- Nonemptiness of each shape. -/ - (F_pos : ∀ n, 0 < (F n).card) - -/-- Entropy of a subshift along a given word-metric shape system. -/ -noncomputable def entropy_word [DecidableEq G] - (Y : Subshift A G) (shapes : WordMetricShapes G) : ℝ := - entropyAlong (A:=A) (G:=G) Y shapes.F - -/-! ## Specializations: `ℤ` and `ℤ^d` -/ - -namespace IntShapes -/-- Segments `[-n,n]` as shapes in `Multiplicative ℤ`. -/ -def seg (n : ℕ) : Finset (Multiplicative ℤ) := - (Finset.Icc (-(n : ℤ)) (n : ℤ)).image Multiplicative.ofAdd - -lemma seg_card_pos (n : ℕ) : 0 < (seg n).card := by - classical - have h0 : (0 : ℤ) ∈ Finset.Icc (-(n : ℤ)) (n : ℤ) := by - have h1 : (0 : ℤ) ≤ (n : ℤ) := by exact_mod_cast Nat.zero_le n - have h2 : -(n : ℤ) ≤ 0 := by simp [neg_nonpos.mpr h1] - simp [Finset.mem_Icc] - refine Finset.card_pos.mpr ?_ - exact ⟨Multiplicative.ofAdd 0, Finset.mem_image.mpr ⟨0, h0, rfl⟩⟩ - -/-- Word-metric style shapes for `ℤ`. -/ -def shapesZ : WordMetricShapes (Multiplicative ℤ) := - { S := {Multiplicative.ofAdd (1 : ℤ), Multiplicative.ofAdd (-1 : ℤ)} - , F := seg - , F_pos := seg_card_pos } - -/-- Entropy on `ℤ` with standard segments. -/ -noncomputable def entropy_Z (Y : Subshift A (Multiplicative ℤ)) : ℝ := - entropy_word (A:=A) (G:=Multiplicative ℤ) Y shapesZ -end IntShapes - -namespace ZdShapes - -variable {d : ℕ} - -/-- The lattice `ℤ^d` as functions `Fin d → ℤ`. -/ -abbrev Zd (d : ℕ) := Fin d → ℤ - -/-- The axis-aligned box `[-n,n]^d` in `ℤ^d` (as a `Finset`). -/ -def box (d : ℕ) (n : ℕ) : Finset (Zd d) := - Fintype.piFinset (fun _ => Finset.Icc (-(n : ℤ)) (n : ℤ)) - -/-- Boxes transported to the multiplicative copy to fit the generic `G`. -/ -def boxMul (d : ℕ) (n : ℕ) : Finset (Multiplicative (Zd d)) := - (box d n).image Multiplicative.ofAdd - -lemma box_card_pos (d n : ℕ) : 0 < (box d n).card := by - classical - have hcoord : ∀ i : Fin d, (0 : ℤ) ∈ Finset.Icc (-(n : ℤ)) (n : ℤ) := by - intro i - have h1 : (0 : ℤ) ≤ (n : ℤ) := by exact_mod_cast Nat.zero_le n - have h2 : -(n : ℤ) ≤ 0 := by simp [neg_nonpos.mpr h1] - simp [Finset.mem_Icc] - have h0 : (fun _ : Fin d => (0 : ℤ)) ∈ box d n := Fintype.mem_piFinset.mpr hcoord - exact Finset.card_pos.mpr ⟨_, h0⟩ - -lemma boxMul_card_pos (d n : ℕ) : 0 < (boxMul d n).card := by - classical - rcases Finset.card_pos.mp (box_card_pos d n) with ⟨z, hz⟩ - refine Finset.card_pos.mpr ?_ - exact ⟨Multiplicative.ofAdd z, Finset.mem_image.mpr ⟨z, hz, rfl⟩⟩ - -/-- Word-metric style shapes for `ℤ^d` using boxes. -/ -def shapesZd (d : ℕ) : WordMetricShapes (Multiplicative (Zd d)) := - { S := - -- ±e_j generators (not used by `entropy_word`, included for completeness) - (Finset.univ.image (fun j : Fin d => Multiplicative.ofAdd - (fun k => if k = j then (1 : ℤ) else 0))) ∪ - (Finset.univ.image (fun j : Fin d => Multiplicative.ofAdd - (fun k => if k = j then (-1 : ℤ) else 0))) - , F := fun n => boxMul d n - , F_pos := boxMul_card_pos d } - -/-- Entropy on `ℤ^d` with standard boxes. -/ -noncomputable def entropy_Zd (Y : Subshift A (Multiplicative (Zd d))) : ℝ := - entropy_word (A:=A) (G:=Multiplicative (Zd d)) Y (shapesZd d) -end ZdShapes - -end FullShift -end SymbolicDynamics From bed2399e809b83f0574900be9add35b460f4fee6 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 11:21:47 +0200 Subject: [PATCH 16/93] refactor(Dynamics/SymbolicDynamics/Basic): prepare and add additive API via --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 152 +++++++++++++++---- 1 file changed, 126 insertions(+), 26 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index b63b81ba0d097f..98fdfdbb36706b 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -25,7 +25,8 @@ box-based entropy) is kept in a separate specialization. ## Main definitions -* `shift g x` — right translation: `(shift g x) h = x (h * g)`. +* `shift g x` — right translation: in the multiplicative notation: `(shift g x) h = x (h * g)`; + additive notation (e.g. for `ℤ^d`): `(addShift v x) u = x (u + v)`. * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. * `Pattern A G` — finite support together with values on that support. * `Pattern.occursIn p x g` — occurrence of `p` in `x` at translate `g`. @@ -51,38 +52,44 @@ open Set Topology namespace SymbolicDynamics -variable {A : Type*} [Fintype A] [Inhabited A] -variable {G : Type*} -variable [TopologicalSpace A] [DiscreteTopology A] -variable [Group G] [DecidableEq G] - /-! ## Full shift and shift action -/ +section ShiftDefinition + +variable {A : Type*} +variable {G : Type*} +variable [Group G] -/-- Right-translation shift: `(shift g x) (h) = x (h * g)`. -/ -def shift (g : G) (x : G → A) : G → A := +/-- Right-translation shift: +* In multiplicative notation: `(mulShift g x) h = x (h * g)`. +* In additive notation (e.g. for `ℤ^d`): `(addShift v x) u = x (u + v)` -/ +@[to_additive] +def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) +end ShiftDefinition + section ShiftAlgebra variable {A G : Type*} [Group G] -@[simp] lemma shift_apply (g h : G) (x : G → A) : - shift g x h = x (h * g) := rfl +@[to_additive (attr := simp)] lemma mulShift_apply (g h : G) (x : G → A) : + mulShift g x h = x (h * g) := rfl -@[simp] lemma shift_one (x : G → A) : shift (1 : G) x = x := by - ext h; simp [shift] +@[to_additive (attr := simp)] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by + ext h; simp [mulShift] -lemma shift_mul (g₁ g₂ : G) (x : G → A) : - shift (g₁ * g₂) x = shift g₁ (shift g₂ x) := by - ext h; simp [shift, mul_assoc] +@[to_additive] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : + mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by + ext h; simp [mulShift, mul_assoc] end ShiftAlgebra section ShiftTopology -- add only topology on A variable {A G : Type*} [Group G] [TopologicalSpace A] -lemma continuous_shift (g : G) : Continuous (shift (A := A) (G := G) g) := by + +@[to_additive] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) (G := G) g) := by -- coordinate projections are continuous; composition preserves continuity continuity @@ -146,22 +153,43 @@ end CylindersClosed /-! ## Patterns and occurrences -/ +section SubshiftDef +variable (A : Type*) [TopologicalSpace A] [Inhabited A] +variable (G : Type*) [Group G] + /-- A subshift is a closed, shift-invariant subset. -/ -structure Subshift (A : Type*) [TopologicalSpace A] [Inhabited A] (G : Type*) [Group G] where +structure Subshift : Type _ where /-- The underlying set of configurations. -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier /-- Shift invariance of `carrier`. -/ - shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift (A := A) (G := G) g x ∈ carrier + shiftInvariant : ∀ g : G, ∀ x ∈ carrier, mulShift g x ∈ carrier + +end SubshiftDef + + +section AddSubshiftDef +variable (A : Type*) [TopologicalSpace A] [Inhabited A] +variable (G : Type*) [AddGroup G] + +/-- Additive version of the definition of subshift -/ +structure AddSubshift : Type _ where + carrier : Set (G → A) + isClosed : IsClosed carrier + shiftInvariant : ∀ g : G, ∀ x ∈ carrier, addShift g x ∈ carrier +end AddSubshiftDef + +attribute [to_additive existing SymbolicDynamics.AddSubshift] + SymbolicDynamics.Subshift /-- Example: the full shift on alphabet A. -/ +@[to_additive SymbolicDynamics.addFullShift] def fullShift (A G) [TopologicalSpace A] [Inhabited A] [Group G] : Subshift A G := { carrier := Set.univ, isClosed := isClosed_univ, shiftInvariant := by intro _ _ _; simp } - /-- A finite pattern: finite support in `G` and values on it. -/ structure Pattern (A : Type*) (G : Type*) [Group G] where /-- Finite support of the pattern. -/ @@ -169,33 +197,64 @@ structure Pattern (A : Type*) (G : Type*) [Group G] where /-- The value (symbol) at each point of the support. -/ data : support → A +/-- Additive version of `Pattern`. -/ +structure AddPattern (A : Type*) (G : Type*) [AddGroup G] : Type _ where + support : Finset G + data : support → A + +attribute [to_additive existing SymbolicDynamics.AddPattern] + SymbolicDynamics.Pattern + +section Dominos + +variable (G : Type*) [Group G] [DecidableEq G] + /-- The domino supported on `{i,j}` with values `ai`,`aj`. -/ +@[to_additive addDomino] def domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by refine { support := ({i, j} : Finset G) , data := fun ⟨z, hz⟩ => if z = i then ai else aj } +end Dominos + +section Forbids + +variable {A : Type*} +variable {G : Type*} +variable [Group G] + /-- Occurrence of a pattern `p` in `x` at position `g`. -/ +@[to_additive Pattern.addOccursIn] def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ /-- Configurations avoiding every pattern in `F`. -/ +@[to_additive addForbids] def forbids (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } +end Forbids + +-- variable {A : Type*} [Fintype A] [Inhabited A] +-- variable {G : Type*} +-- variable [TopologicalSpace A] [DiscreteTopology A] +-- variable [Group G] [DecidableEq G] section ShiftInvariance variable {A G : Type*} [Group G] /-- Shifts move occurrences as expected. -/ +@[to_additive addOccurs_addShift] lemma occurs_shift (p : Pattern A G) (x : G → A) (g h : G) : - p.occursIn (shift h x) g ↔ p.occursIn x (g * h) := by - constructor <;> intro H u hu <;> simpa [shift, mul_assoc] using H u hu + p.occursIn (mulShift h x) g ↔ p.occursIn x (g * h) := by + constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu +@[to_additive addForbids_addShift_invariant] lemma forbids_shift_invariant (F : Set (Pattern A G)) : - ∀ h : G, ∀ x ∈ forbids (A := A) (G := G) F, shift h x ∈ forbids F := by + ∀ h : G, ∀ x ∈ forbids (A := A) (G := G) F, mulShift h x ∈ forbids F := by intro h x hx p hp g specialize hx p hp (g * h) -- contraposition @@ -204,36 +263,48 @@ lemma forbids_shift_invariant (F : Set (Pattern A G)) : end ShiftInvariance +section PatternFromToConfig + +variable {A : Type*} [Inhabited A] +variable {G : Type*} +variable [Group G] [DecidableEq G] + /-- Extend a pattern by `default` away from its support (anchored at the origin). -/ +@[to_additive addPatternToOriginConfig] def patternToOriginConfig (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default /-- Translate a pattern to occur at `v`. -/ +@[to_additive addPatternToConfig] def patternToConfig (p : Pattern A G) (v : G) : G → A := - shift (v⁻¹) (patternToOriginConfig p) + mulShift (v⁻¹) (patternToOriginConfig p) /-- Restrict a configuration to a finite support, seen as a pattern. -/ +@[to_additive addPatternFromConfig] def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := { support := U, data := fun i => x i.1 } +end PatternFromToConfig + section OccursAtEqCylinder variable {A G : Type*} [Group G] [Inhabited A] [DecidableEq G] /-- “Occurrence = cylinder translated by `g`”. -/ +@[to_additive addOccursAt_eq_cylinder] lemma occursAt_eq_cylinder (p : Pattern A G) (g : G) : { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (patternToConfig p g) := by ext x constructor · intro H u hu obtain ⟨w, hw, rfl⟩ := Finset.mem_image.mp hu - dsimp [patternToConfig, patternToOriginConfig, shift] + dsimp [patternToConfig, patternToOriginConfig, mulShift] simp [dif_pos hw, H w hw] · intro H u hu have := H (u * g) (Finset.mem_image_of_mem _ hu) - dsimp [patternToConfig, patternToOriginConfig, shift] at this - simpa [add_neg_cancel_right, dif_pos hu] using this + dsimp [patternToConfig, patternToOriginConfig, mulShift] at this + simpa [mul_inv_cancel_right, mul_assoc, dif_pos hu] using this end OccursAtEqCylinder @@ -245,11 +316,13 @@ variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] [DecidableEq G] /-- Occurrence sets are open. -/ +@[to_additive addOccursAt_open] lemma occursAt_open (p : Pattern A G) (g : G) : IsOpen { x | p.occursIn x g } := by rw [occursAt_eq_cylinder]; exact cylinder_is_open _ _ /-- Avoiding a fixed set of patterns is a closed condition. -/ +@[to_additive addForbids_closed] lemma forbids_closed (F : Set (Pattern A G)) : IsClosed (forbids F) := by rw [forbids] @@ -271,27 +344,48 @@ variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] [DecidableEq G] /-- Occurrence sets are closed. -/ +@[to_additive addOccursAt_closed] lemma occursAt_closed (p : Pattern A G) (g : G) : IsClosed { x | p.occursIn x g } := by rw [occursAt_eq_cylinder]; exact cylinder_is_closed _ _ end OccSetsClosed +section DefSubshiftByForbidden + +variable {A : Type*} [Inhabited A] +variable {G : Type*} +variable [TopologicalSpace A] [DiscreteTopology A] +variable [Group G] [DecidableEq G] + /-- Subshift defined by forbidden patterns. -/ +@[to_additive addX_F] def X_F (F : Set (Pattern A G)) : Subshift A G := { carrier := forbids F, isClosed := forbids_closed F, shiftInvariant := forbids_shift_invariant F } /-- Subshift of finite type defined by a finite family of forbidden patterns. -/ +@[to_additive addSFT] def SFT (F : Finset (Pattern A G)) : Subshift A G := X_F (F : Set (Pattern A G)) +end DefSubshiftByForbidden + +section Language + +variable {A : Type*} [Fintype A] +variable {G : Type*} +variable [TopologicalSpace A] +variable [Group G] + /-- Patterns with fixed support `U`. -/ +@[to_additive AddFixedSupport] def FixedSupport (A : Type*) (G : Type*) [Group G] (U : Finset G) := { p : Pattern A G // p.support = U } /-- `FixedSupport A G U ≃ (U → A)`; gives finiteness immediately. -/ +@[to_additive addEquivFun] def equivFun {U : Finset G} : FixedSupport A G U ≃ (U → A) where toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ @@ -299,15 +393,18 @@ def equivFun {U : Finset G} : left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl right_inv := by intro f; rfl +@[to_additive SymbolicDynamics.addFintypeFixedSupport] noncomputable instance fintypeFixedSupport {U : Finset G} : Fintype (FixedSupport A G U) := by classical exact Fintype.ofEquiv (U → A) (equivFun (A := A) (G := G) (U := U)).symm /-- Language on a finite set `U ⊆ G`: patterns obtained by restricting some `x ∈ X`. -/ +@[to_additive addLanguageOn] def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, patternFromConfig x U = p } /-- Cardinality of the finite-support language. -/ +@[to_additive addLanguageCardOn] noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by classical -- Image of a map into the finite type `FixedSupport A G U` @@ -319,7 +416,10 @@ noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by exact hfin.toFinset.card /-- Number of patterns of a subshift on a finite shape `U`. -/ +@[to_additive addPatternCountOn] noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := languageCardOn (A := A) (G := G) Y.carrier U +end Language + end SymbolicDynamics From 7a4716a430f1547523e3854d7affbe60022d4294 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 11:33:12 +0200 Subject: [PATCH 17/93] chore(Dynamics/SymbolicDynamics): re-add stub to satisfy import --- .../Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean diff --git a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean new file mode 100644 index 00000000000000..5593a3505f976b --- /dev/null +++ b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean @@ -0,0 +1,5 @@ +/-! +# Entropy on finitely generated groups + +(split out to another PR) +-/ From 7a2f480e82e12d2d2a8c6575122ee3fb5229744b Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 12:09:21 +0200 Subject: [PATCH 18/93] removed entropy file --- Mathlib.lean | 1 - .../Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean | 5 ----- 2 files changed, 6 deletions(-) delete mode 100644 Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean diff --git a/Mathlib.lean b/Mathlib.lean index 21ce0c1671a408..46dcfcb2abd617 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3857,7 +3857,6 @@ import Mathlib.Dynamics.OmegaLimit import Mathlib.Dynamics.PeriodicPts.Defs import Mathlib.Dynamics.PeriodicPts.Lemmas import Mathlib.Dynamics.SymbolicDynamics.Basic -import Mathlib.Dynamics.SymbolicDynamics.EntropyFinitelyGenerated import Mathlib.Dynamics.TopologicalEntropy.CoverEntropy import Mathlib.Dynamics.TopologicalEntropy.DynamicalEntourage import Mathlib.Dynamics.TopologicalEntropy.NetEntropy diff --git a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean b/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean deleted file mode 100644 index 5593a3505f976b..00000000000000 --- a/Mathlib/Dynamics/SymbolicDynamics/EntropyFinitelyGenerated.lean +++ /dev/null @@ -1,5 +0,0 @@ -/-! -# Entropy on finitely generated groups - -(split out to another PR) --/ From 985d914deaa1306837991c1accd56e4981ffed09 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 13:30:39 +0200 Subject: [PATCH 19/93] chore(SymbolicDynamics): deglobalize new simp lemmas to avoid churn --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 98fdfdbb36706b..1de540c0950946 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -73,10 +73,10 @@ section ShiftAlgebra variable {A G : Type*} [Group G] -@[to_additive (attr := simp)] lemma mulShift_apply (g h : G) (x : G → A) : +@[to_additive] lemma mulShift_apply (g h : G) (x : G → A) : mulShift g x h = x (h * g) := rfl -@[to_additive (attr := simp)] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by +@[to_additive] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] @[to_additive] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : From ba085d428b22e637461ee69410922ba760cf336e Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 18:40:39 +0200 Subject: [PATCH 20/93] =?UTF-8?q?chore(SymbolicDynamics):=20fix=20lints=20?= =?UTF-8?q?=E2=80=94=20docstrings=20for=20additive=20decls;=20silence=20un?= =?UTF-8?q?used=20args=20in=20fullShift/addFullShift?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 35 ++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 1de540c0950946..5611b37b186e96 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -67,6 +67,8 @@ variable [Group G] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) +attribute [inherit_doc SymbolicDynamics.mulShift] SymbolicDynamics.addShift + end ShiftDefinition section ShiftAlgebra @@ -185,7 +187,7 @@ attribute [to_additive existing SymbolicDynamics.AddSubshift] /-- Example: the full shift on alphabet A. -/ @[to_additive SymbolicDynamics.addFullShift] -def fullShift (A G) [TopologicalSpace A] [Inhabited A] [Group G] : Subshift A G := +def fullShift (A G) [TopologicalSpace A] [Group G] : Subshift A G := { carrier := Set.univ, isClosed := isClosed_univ, shiftInvariant := by intro _ _ _; simp } @@ -230,17 +232,16 @@ variable [Group G] def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ +attribute [inherit_doc SymbolicDynamics.Pattern.occursIn] SymbolicDynamics.Pattern.addOccursIn + /-- Configurations avoiding every pattern in `F`. -/ @[to_additive addForbids] def forbids (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } -end Forbids +attribute [inherit_doc SymbolicDynamics.forbids] SymbolicDynamics.addForbids --- variable {A : Type*} [Fintype A] [Inhabited A] --- variable {G : Type*} --- variable [TopologicalSpace A] [DiscreteTopology A] --- variable [Group G] [DecidableEq G] +end Forbids section ShiftInvariance @@ -274,17 +275,24 @@ variable [Group G] [DecidableEq G] def patternToOriginConfig (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default +attribute [inherit_doc SymbolicDynamics.patternToOriginConfig] + SymbolicDynamics.addPatternToOriginConfig + /-- Translate a pattern to occur at `v`. -/ @[to_additive addPatternToConfig] def patternToConfig (p : Pattern A G) (v : G) : G → A := mulShift (v⁻¹) (patternToOriginConfig p) +attribute [inherit_doc SymbolicDynamics.patternToConfig] SymbolicDynamics.addPatternToConfig + /-- Restrict a configuration to a finite support, seen as a pattern. -/ @[to_additive addPatternFromConfig] def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := { support := U, data := fun i => x i.1 } +attribute [inherit_doc SymbolicDynamics.patternFromConfig] SymbolicDynamics.addPatternFromConfig + end PatternFromToConfig section OccursAtEqCylinder @@ -365,11 +373,15 @@ def X_F (F : Set (Pattern A G)) : Subshift A G := isClosed := forbids_closed F, shiftInvariant := forbids_shift_invariant F } +attribute [inherit_doc SymbolicDynamics.X_F] SymbolicDynamics.addX_F + /-- Subshift of finite type defined by a finite family of forbidden patterns. -/ @[to_additive addSFT] def SFT (F : Finset (Pattern A G)) : Subshift A G := X_F (F : Set (Pattern A G)) +attribute [inherit_doc SymbolicDynamics.SFT] SymbolicDynamics.addSFT + end DefSubshiftByForbidden section Language @@ -384,6 +396,8 @@ variable [Group G] def FixedSupport (A : Type*) (G : Type*) [Group G] (U : Finset G) := { p : Pattern A G // p.support = U } +attribute [inherit_doc SymbolicDynamics.FixedSupport] SymbolicDynamics.AddFixedSupport + /-- `FixedSupport A G U ≃ (U → A)`; gives finiteness immediately. -/ @[to_additive addEquivFun] def equivFun {U : Finset G} : @@ -393,6 +407,8 @@ def equivFun {U : Finset G} : left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl right_inv := by intro f; rfl +attribute [inherit_doc SymbolicDynamics.equivFun] SymbolicDynamics.addEquivFun + @[to_additive SymbolicDynamics.addFintypeFixedSupport] noncomputable instance fintypeFixedSupport {U : Finset G} : Fintype (FixedSupport A G U) := by @@ -403,6 +419,9 @@ instance fintypeFixedSupport {U : Finset G} : def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, patternFromConfig x U = p } +attribute [inherit_doc SymbolicDynamics.languageOn] SymbolicDynamics.addLanguageOn + + /-- Cardinality of the finite-support language. -/ @[to_additive addLanguageCardOn] noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by @@ -415,11 +434,15 @@ noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by |>.subset (by intro y hy; simp) exact hfin.toFinset.card +attribute [inherit_doc SymbolicDynamics.languageCardOn] SymbolicDynamics.addLanguageCardOn + /-- Number of patterns of a subshift on a finite shape `U`. -/ @[to_additive addPatternCountOn] noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := languageCardOn (A := A) (G := G) Y.carrier U +attribute [inherit_doc SymbolicDynamics.patternCountOn] SymbolicDynamics.addPatternCountOn + end Language end SymbolicDynamics From 022d82e2d0f04caff5bf8010634eeffbbc761fe0 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 23 Sep 2025 22:18:28 +0200 Subject: [PATCH 21/93] chore(SymbolicDynamics): deglobalize simp on to avoid churn --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 5611b37b186e96..e4cf59d3cb764f 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -113,7 +113,7 @@ lemma cylinder_eq_set_pi (U : Finset G) (x : G → A) : cylinder U x = Set.pi (↑U : Set G) (fun i => ({x i} : Set A)) := by ext y; simp [cylinder, Set.pi, Finset.mem_coe] -@[simp] lemma mem_cylinder {U : Finset G} {x y : G → A} : +lemma mem_cylinder {U : Finset G} {x y : G → A} : y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl end CylindersDefs From 1d1744b1e8767fdb95fd222304e9f1c090e02a8c Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 25 Sep 2025 17:48:10 +0200 Subject: [PATCH 22/93] linters docstrings --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index e4cf59d3cb764f..5ece76f8baf435 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -156,7 +156,7 @@ end CylindersClosed /-! ## Patterns and occurrences -/ section SubshiftDef -variable (A : Type*) [TopologicalSpace A] [Inhabited A] +variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [Group G] /-- A subshift is a closed, shift-invariant subset. -/ @@ -172,14 +172,18 @@ end SubshiftDef section AddSubshiftDef -variable (A : Type*) [TopologicalSpace A] [Inhabited A] +variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [AddGroup G] -/-- Additive version of the definition of subshift -/ +/-- Additive version of the definition of subshift. -/ structure AddSubshift : Type _ where + /-- The underlying set of configurations (additive group version). -/ carrier : Set (G → A) + /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier + /-- Shift invariance of `carrier` for the additive shift `addShift`. -/ shiftInvariant : ∀ g : G, ∀ x ∈ carrier, addShift g x ∈ carrier + end AddSubshiftDef attribute [to_additive existing SymbolicDynamics.AddSubshift] @@ -192,6 +196,8 @@ def fullShift (A G) [TopologicalSpace A] [Group G] : Subshift A G := isClosed := isClosed_univ, shiftInvariant := by intro _ _ _; simp } +attribute [inherit_doc SymbolicDynamics.fullShift] SymbolicDynamics.addFullShift + /-- A finite pattern: finite support in `G` and values on it. -/ structure Pattern (A : Type*) (G : Type*) [Group G] where /-- Finite support of the pattern. -/ @@ -201,7 +207,9 @@ structure Pattern (A : Type*) (G : Type*) [Group G] where /-- Additive version of `Pattern`. -/ structure AddPattern (A : Type*) (G : Type*) [AddGroup G] : Type _ where + /-- Finite support of the pattern (subset of `G`). -/ support : Finset G + /-- The symbol at each point of the support. -/ data : support → A attribute [to_additive existing SymbolicDynamics.AddPattern] @@ -219,6 +227,8 @@ def domino {A : Type*} { support := ({i, j} : Finset G) , data := fun ⟨z, hz⟩ => if z = i then ai else aj } +attribute [inherit_doc SymbolicDynamics.domino] SymbolicDynamics.addDomino + end Dominos section Forbids From 4f2502b83acf56a50f95636de5d88681b865258a Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Fri, 26 Sep 2025 10:12:19 +0200 Subject: [PATCH 23/93] docstrings + ambiant namespace --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 125 +++++++++++++------ 1 file changed, 89 insertions(+), 36 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 5ece76f8baf435..3752513bfbfceb 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -8,50 +8,95 @@ import Mathlib.Topology.Basic import Mathlib.Topology.Constructions import Mathlib.Data.Finset.Basic import Mathlib.Logic.Equiv.Defs - /-! # Symbolic dynamics on groups This file develops a minimal API for symbolic dynamics over an arbitrary group `G`. -Provided a finite set `A`, the ambient space is the space of functions from `G` to `A`, -hence it inherits the product topology from the Π-type. We define the right-translation action, -cylinders, finite patterns, their occurrences, forbidden sets, and subshifts (closed, -shift-invariant subsets). Basic topological statements (e.g. cylinders are clopen, +Given a finite alphabet `A`, the ambient configuration space is the set of functions +`G → A`, endowed with the product topology. We define the right-translation action, +cylinders, finite patterns, their occurrences, forbidden sets, and subshifts +(closed, shift-invariant subsets). Basic topological facts (e.g. cylinders are clopen, occurrence sets are clopen, forbidden sets are closed) are proved under discreteness assumptions on the alphabet. -The file is group-generic. Geometry specific to `ℤ^d` (boxes/cubes and the -box-based entropy) is kept in a separate specialization. +The development is group-generic. Geometry specific to `ℤ^d` (boxes/cubes and the +box-based entropy) is deferred to a separate specialization. ## Main definitions -* `shift g x` — right translation: in the multiplicative notation: `(shift g x) h = x (h * g)`; - additive notation (e.g. for `ℤ^d`): `(addShift v x) u = x (u + v)`. +* `mulShift g x` — right translation: in multiplicative notation `(mulShift g x) h = x (h * g)`; + additive notation `(addShift v x) u = x (u + v)`. * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. * `Pattern A G` — finite support together with values on that support. * `Pattern.occursIn p x g` — occurrence of `p` in `x` at translate `g`. * `forbids F` — configurations avoiding every pattern in `F`. * `Subshift A G` — closed, shift-invariant subsets of the full shift. +* `X_F F` — the subshift defined by forbidding a family of patterns. +* `SFT F` — a subshift of finite type defined by a finite set of forbidden patterns. +* `languageOn X U` — the set of patterns of shape `U` obtained by restricting some `x ∈ X`. ## Conventions We use a **right** action of `G` on configurations: -`(shift g x) h = x (h * g)`. In additive notation (e.g. for `ℤ^d`) this is -`(shift v x) u = x (u + v)`. +`(mulShift g x) h = x (h * g)`. +In additive notation (e.g. for `ℤ^d`): +`(addShift v x) u = x (u + v)`. + +## Design choice: ambient vs. inner (subshift-relative) viewpoint + +All core notions (shift, cylinder, occurrence, language, …) are defined **in the +ambient full shift** `(G → A)`. A subshift is then a closed, invariant subset, +bundled as `Subshift A G`. Working inside a subshift is done by restriction. + +**Motivation.** +If cylinders and shifts were defined only *inside* a subshift, local ergonomics +would improve but global operations would become awkward. For instance, to prove +that for finite shape `U`: + +`languageOn (X ∪ Y) U = languageOn X U ∪ languageOn Y U,` + +one must eventually move both sides to the ambient pattern type. Similar issues +arise for intersections, factors, and products. By contrast, with ambient +definitions these set-theoretic identities are tautological. +Thus the file develops the theory ambiently, and subshifts reuse it by restriction. + +**Working inside a subshift.** +For `Y : Subshift A G`, cylinders and occurrence sets *inside `Y`* are simply +preimages of the ambient ones under the inclusion `Y → (G → A)`. For example: + +`{ y : Y | ∀ i ∈ U, (y : G → A) i = (x : G → A) i } = (Subtype.val) ⁻¹’ (cylinder U (x : G → A)).` + +Shift invariance guarantees that the ambient shift restricts to `Y`. + +**Ergonomics.** +Thin wrappers (e.g. `Subshift.shift`, `Subshift.cylinder`, `Subshift.languageOn`) +may be added for convenience. They introduce no new theory and unfold to the +ambient definitions. + +## Namespacing policy + +All ambient definitions live under the namespace `SymbolicDynamics.Ambiant`. +If inner, subshift-relative wrappers are provided, they will be placed in the +subnamespace `SymbolicDynamics.Inner`. This separation avoids name clashes +between the two viewpoints, since both may naturally want to reuse names like +`cylinder`, `shift`, `occursAt`, or `languageOn`. ## Implementation notes * Openness/closedness results for cylinders and occurrence sets use - `[DiscreteTopology A]`. The closedness proofs that enumerate values additionally - require `[Fintype A]`, `[DecidableEq A]`, and `[DecidableEq G]` (for `Finset` manipulations - and `Function.update`). + `[DiscreteTopology A]`. Closedness proofs that enumerate values additionally + require `[Fintype A]`, `[DecidableEq A]`, and `[DecidableEq G]` (for `Finset` + manipulations and `Function.update`). -/ + noncomputable section open Set Topology namespace SymbolicDynamics +namespace Ambiant + /-! ## Full shift and shift action -/ section ShiftDefinition @@ -67,7 +112,7 @@ variable [Group G] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) -attribute [inherit_doc SymbolicDynamics.mulShift] SymbolicDynamics.addShift +attribute [inherit_doc SymbolicDynamics.Ambiant.mulShift] SymbolicDynamics.Ambiant.addShift end ShiftDefinition @@ -186,17 +231,17 @@ structure AddSubshift : Type _ where end AddSubshiftDef -attribute [to_additive existing SymbolicDynamics.AddSubshift] - SymbolicDynamics.Subshift +attribute [to_additive existing SymbolicDynamics.Ambiant.AddSubshift] + SymbolicDynamics.Ambiant.Subshift /-- Example: the full shift on alphabet A. -/ -@[to_additive SymbolicDynamics.addFullShift] +@[to_additive SymbolicDynamics.Ambiant.addFullShift] def fullShift (A G) [TopologicalSpace A] [Group G] : Subshift A G := { carrier := Set.univ, isClosed := isClosed_univ, shiftInvariant := by intro _ _ _; simp } -attribute [inherit_doc SymbolicDynamics.fullShift] SymbolicDynamics.addFullShift +attribute [inherit_doc SymbolicDynamics.Ambiant.fullShift] SymbolicDynamics.Ambiant.addFullShift /-- A finite pattern: finite support in `G` and values on it. -/ structure Pattern (A : Type*) (G : Type*) [Group G] where @@ -212,8 +257,8 @@ structure AddPattern (A : Type*) (G : Type*) [AddGroup G] : Type _ where /-- The symbol at each point of the support. -/ data : support → A -attribute [to_additive existing SymbolicDynamics.AddPattern] - SymbolicDynamics.Pattern +attribute [to_additive existing SymbolicDynamics.Ambiant.AddPattern] + SymbolicDynamics.Ambiant.Pattern section Dominos @@ -227,7 +272,7 @@ def domino {A : Type*} { support := ({i, j} : Finset G) , data := fun ⟨z, hz⟩ => if z = i then ai else aj } -attribute [inherit_doc SymbolicDynamics.domino] SymbolicDynamics.addDomino +attribute [inherit_doc SymbolicDynamics.Ambiant.domino] SymbolicDynamics.Ambiant.addDomino end Dominos @@ -242,14 +287,15 @@ variable [Group G] def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ -attribute [inherit_doc SymbolicDynamics.Pattern.occursIn] SymbolicDynamics.Pattern.addOccursIn +attribute [inherit_doc SymbolicDynamics.Ambiant.Pattern.occursIn] + SymbolicDynamics.Ambiant.Pattern.addOccursIn /-- Configurations avoiding every pattern in `F`. -/ @[to_additive addForbids] def forbids (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } -attribute [inherit_doc SymbolicDynamics.forbids] SymbolicDynamics.addForbids +attribute [inherit_doc SymbolicDynamics.Ambiant.forbids] SymbolicDynamics.Ambiant.addForbids end Forbids @@ -285,15 +331,16 @@ variable [Group G] [DecidableEq G] def patternToOriginConfig (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default -attribute [inherit_doc SymbolicDynamics.patternToOriginConfig] - SymbolicDynamics.addPatternToOriginConfig +attribute [inherit_doc SymbolicDynamics.Ambiant.patternToOriginConfig] + SymbolicDynamics.Ambiant.addPatternToOriginConfig /-- Translate a pattern to occur at `v`. -/ @[to_additive addPatternToConfig] def patternToConfig (p : Pattern A G) (v : G) : G → A := mulShift (v⁻¹) (patternToOriginConfig p) -attribute [inherit_doc SymbolicDynamics.patternToConfig] SymbolicDynamics.addPatternToConfig +attribute [inherit_doc SymbolicDynamics.Ambiant.patternToConfig] + SymbolicDynamics.Ambiant.addPatternToConfig /-- Restrict a configuration to a finite support, seen as a pattern. -/ @[to_additive addPatternFromConfig] @@ -301,7 +348,8 @@ def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := { support := U, data := fun i => x i.1 } -attribute [inherit_doc SymbolicDynamics.patternFromConfig] SymbolicDynamics.addPatternFromConfig +attribute [inherit_doc SymbolicDynamics.Ambiant.patternFromConfig] + SymbolicDynamics.Ambiant.addPatternFromConfig end PatternFromToConfig @@ -383,14 +431,14 @@ def X_F (F : Set (Pattern A G)) : Subshift A G := isClosed := forbids_closed F, shiftInvariant := forbids_shift_invariant F } -attribute [inherit_doc SymbolicDynamics.X_F] SymbolicDynamics.addX_F +attribute [inherit_doc SymbolicDynamics.Ambiant.X_F] SymbolicDynamics.Ambiant.addX_F /-- Subshift of finite type defined by a finite family of forbidden patterns. -/ @[to_additive addSFT] def SFT (F : Finset (Pattern A G)) : Subshift A G := X_F (F : Set (Pattern A G)) -attribute [inherit_doc SymbolicDynamics.SFT] SymbolicDynamics.addSFT +attribute [inherit_doc SymbolicDynamics.Ambiant.SFT] SymbolicDynamics.Ambiant.addSFT end DefSubshiftByForbidden @@ -406,7 +454,8 @@ variable [Group G] def FixedSupport (A : Type*) (G : Type*) [Group G] (U : Finset G) := { p : Pattern A G // p.support = U } -attribute [inherit_doc SymbolicDynamics.FixedSupport] SymbolicDynamics.AddFixedSupport +attribute [inherit_doc SymbolicDynamics.Ambiant.FixedSupport] + SymbolicDynamics.Ambiant.AddFixedSupport /-- `FixedSupport A G U ≃ (U → A)`; gives finiteness immediately. -/ @[to_additive addEquivFun] @@ -417,9 +466,9 @@ def equivFun {U : Finset G} : left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl right_inv := by intro f; rfl -attribute [inherit_doc SymbolicDynamics.equivFun] SymbolicDynamics.addEquivFun +attribute [inherit_doc SymbolicDynamics.Ambiant.equivFun] SymbolicDynamics.Ambiant.addEquivFun -@[to_additive SymbolicDynamics.addFintypeFixedSupport] noncomputable +@[to_additive SymbolicDynamics.Ambiant.addFintypeFixedSupport] noncomputable instance fintypeFixedSupport {U : Finset G} : Fintype (FixedSupport A G U) := by classical exact Fintype.ofEquiv (U → A) (equivFun (A := A) (G := G) (U := U)).symm @@ -429,7 +478,7 @@ instance fintypeFixedSupport {U : Finset G} : def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, patternFromConfig x U = p } -attribute [inherit_doc SymbolicDynamics.languageOn] SymbolicDynamics.addLanguageOn +attribute [inherit_doc SymbolicDynamics.Ambiant.languageOn] SymbolicDynamics.Ambiant.addLanguageOn /-- Cardinality of the finite-support language. -/ @@ -444,15 +493,19 @@ noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by |>.subset (by intro y hy; simp) exact hfin.toFinset.card -attribute [inherit_doc SymbolicDynamics.languageCardOn] SymbolicDynamics.addLanguageCardOn +attribute [inherit_doc SymbolicDynamics.Ambiant.languageCardOn] + SymbolicDynamics.Ambiant.addLanguageCardOn /-- Number of patterns of a subshift on a finite shape `U`. -/ @[to_additive addPatternCountOn] noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := languageCardOn (A := A) (G := G) Y.carrier U -attribute [inherit_doc SymbolicDynamics.patternCountOn] SymbolicDynamics.addPatternCountOn +attribute [inherit_doc SymbolicDynamics.Ambiant.patternCountOn] + SymbolicDynamics.Ambiant.addPatternCountOn end Language +end Ambiant + end SymbolicDynamics From 063698129271a7f1b7ad7bc0a8ef9dfd8bf113d3 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Mon, 29 Sep 2025 15:47:14 +0200 Subject: [PATCH 24/93] feat(SymbolicDynamics): support cancellative monoids, docstring refactor * Generalized all group assumptions to instead of . This allows working with cancellative monoids, not only groups. * Reworked to avoid inverses, using right-cancellation instead. Added lemma to characterize its behavior on translated supports. * Fixed proofs depending on inverses () to use cancellation arguments. * Expanded the file-level docstring: clarified assumptions (cancellative monoid instead of group) --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 180 +++++++++++++------ 1 file changed, 129 insertions(+), 51 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 3752513bfbfceb..ba4ce2d76ddd2f 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -9,23 +9,38 @@ import Mathlib.Topology.Constructions import Mathlib.Data.Finset.Basic import Mathlib.Logic.Equiv.Defs /-! -# Symbolic dynamics on groups - -This file develops a minimal API for symbolic dynamics over an arbitrary group `G`. -Given a finite alphabet `A`, the ambient configuration space is the set of functions -`G → A`, endowed with the product topology. We define the right-translation action, -cylinders, finite patterns, their occurrences, forbidden sets, and subshifts -(closed, shift-invariant subsets). Basic topological facts (e.g. cylinders are clopen, -occurrence sets are clopen, forbidden sets are closed) are proved under discreteness -assumptions on the alphabet. - -The development is group-generic. Geometry specific to `ℤ^d` (boxes/cubes and the -box-based entropy) is deferred to a separate specialization. +# Symbolic dynamics on cancellative monoids + +This file develops a minimal API for symbolic dynamics over an arbitrary +**right-cancellative monoid** `G` (`[Monoid G] [IsRightCancelMul G]`). + +Given a finite alphabet `A`, the ambient configuration space is the set of +functions `G → A`, endowed with the product topology. We define the +right-translation action, cylinders, finite patterns, their occurrences, +forbidden sets, and subshifts (closed, shift-invariant subsets). Basic +topological facts (e.g. cylinders are clopen, occurrence sets are clopen, +forbidden sets are closed) are proved under discreteness assumptions on +the alphabet. + +The development is generic for right-cancellative monoids. This covers both +groups (the standard setting of symbolic dynamics) and more general monoids +where cancellation holds but inverses may not exist. Geometry specific to +`ℤ^d` (boxes/cubes and the box-based entropy) is deferred to a separate +specialization. + +## Why cancellativity? + +Some constructions, such as translating a finite pattern to occur at a point `v`, +require solving equations of the form `w * v = h`. For this to have a unique +solution `w` given `h` and `v`, we assume **right-cancellation**: +if `a * v = b * v` then `a = b`. This allows us to define +`patternToConfig` without using inverses, so that the theory works not only +for groups but also for cancellative monoids. ## Main definitions -* `mulShift g x` — right translation: in multiplicative notation `(mulShift g x) h = x (h * g)`; - additive notation `(addShift v x) u = x (u + v)`. +* `mulShift g x` — right translation: in multiplicative notation + `(mulShift g x) h = x (h * g)`; additive notation `(addShift v x) u = x (u + v)`. * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. * `Pattern A G` — finite support together with values on that support. * `Pattern.occursIn p x g` — occurrence of `p` in `x` at translate `g`. @@ -103,7 +118,7 @@ section ShiftDefinition variable {A : Type*} variable {G : Type*} -variable [Group G] +variable [Monoid G] /-- Right-translation shift: * In multiplicative notation: `(mulShift g x) h = x (h * g)`. @@ -118,7 +133,7 @@ end ShiftDefinition section ShiftAlgebra -variable {A G : Type*} [Group G] +variable {A G : Type*} [Monoid G] @[to_additive] lemma mulShift_apply (g h : G) (x : G → A) : mulShift g x h = x (h * g) := rfl @@ -134,7 +149,7 @@ end ShiftAlgebra section ShiftTopology -- add only topology on A -variable {A G : Type*} [Group G] [TopologicalSpace A] +variable {A G : Type*} [Monoid G] [TopologicalSpace A] @[to_additive] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) (G := G) g) := by -- coordinate projections are continuous; composition preserves continuity @@ -142,8 +157,6 @@ variable {A G : Type*} [Group G] [TopologicalSpace A] end ShiftTopology - - /-! ## Cylinders -/ section CylindersDefs @@ -202,7 +215,7 @@ end CylindersClosed section SubshiftDef variable (A : Type*) [TopologicalSpace A] -variable (G : Type*) [Group G] +variable (G : Type*) [Monoid G] /-- A subshift is a closed, shift-invariant subset. -/ structure Subshift : Type _ where @@ -218,7 +231,7 @@ end SubshiftDef section AddSubshiftDef variable (A : Type*) [TopologicalSpace A] -variable (G : Type*) [AddGroup G] +variable (G : Type*) [AddMonoid G] /-- Additive version of the definition of subshift. -/ structure AddSubshift : Type _ where @@ -236,7 +249,7 @@ attribute [to_additive existing SymbolicDynamics.Ambiant.AddSubshift] /-- Example: the full shift on alphabet A. -/ @[to_additive SymbolicDynamics.Ambiant.addFullShift] -def fullShift (A G) [TopologicalSpace A] [Group G] : Subshift A G := +def fullShift (A G) [TopologicalSpace A] [Monoid G] : Subshift A G := { carrier := Set.univ, isClosed := isClosed_univ, shiftInvariant := by intro _ _ _; simp } @@ -244,14 +257,14 @@ def fullShift (A G) [TopologicalSpace A] [Group G] : Subshift A G := attribute [inherit_doc SymbolicDynamics.Ambiant.fullShift] SymbolicDynamics.Ambiant.addFullShift /-- A finite pattern: finite support in `G` and values on it. -/ -structure Pattern (A : Type*) (G : Type*) [Group G] where +structure Pattern (A : Type*) (G : Type*) [Monoid G] where /-- Finite support of the pattern. -/ support : Finset G /-- The value (symbol) at each point of the support. -/ data : support → A /-- Additive version of `Pattern`. -/ -structure AddPattern (A : Type*) (G : Type*) [AddGroup G] : Type _ where +structure AddPattern (A : Type*) (G : Type*) [AddMonoid G] : Type _ where /-- Finite support of the pattern (subset of `G`). -/ support : Finset G /-- The symbol at each point of the support. -/ @@ -262,7 +275,7 @@ attribute [to_additive existing SymbolicDynamics.Ambiant.AddPattern] section Dominos -variable (G : Type*) [Group G] [DecidableEq G] +variable (G : Type*) [Monoid G] [DecidableEq G] /-- The domino supported on `{i,j}` with values `ai`,`aj`. -/ @[to_additive addDomino] @@ -280,7 +293,7 @@ section Forbids variable {A : Type*} variable {G : Type*} -variable [Group G] +variable [Monoid G] /-- Occurrence of a pattern `p` in `x` at position `g`. -/ @[to_additive Pattern.addOccursIn] @@ -301,7 +314,7 @@ end Forbids section ShiftInvariance -variable {A G : Type*} [Group G] +variable {A G : Type*} [Monoid G] /-- Shifts move occurrences as expected. -/ @[to_additive addOccurs_addShift] @@ -324,7 +337,7 @@ section PatternFromToConfig variable {A : Type*} [Inhabited A] variable {G : Type*} -variable [Group G] [DecidableEq G] +variable [Monoid G] [IsRightCancelMul G] [DecidableEq G] /-- Extend a pattern by `default` away from its support (anchored at the origin). -/ @[to_additive addPatternToOriginConfig] @@ -334,13 +347,19 @@ def patternToOriginConfig (p : Pattern A G) : G → A := attribute [inherit_doc SymbolicDynamics.Ambiant.patternToOriginConfig] SymbolicDynamics.Ambiant.addPatternToOriginConfig -/-- Translate a pattern to occur at `v`. -/ @[to_additive addPatternToConfig] -def patternToConfig (p : Pattern A G) (v : G) : G → A := - mulShift (v⁻¹) (patternToOriginConfig p) - -attribute [inherit_doc SymbolicDynamics.Ambiant.patternToConfig] - SymbolicDynamics.Ambiant.addPatternToConfig +noncomputable def patternToConfig (p : Pattern A G) (v : G) : G → A := + fun h => + if hmem : h ∈ p.support.image (· * v) then + -- package existence of a preimage under (_ * v) + let ex : ∃ w, w ∈ p.support ∧ w * v = h := by + simpa [Finset.mem_image] using hmem + let w := Classical.choose ex + have hw : w ∈ p.support := (Classical.choose_spec ex).1 + have hwv : w * v = h := (Classical.choose_spec ex).2 + p.data ⟨w, hw⟩ + else + default /-- Restrict a configuration to a finite support, seen as a pattern. -/ @[to_additive addPatternFromConfig] @@ -355,22 +374,81 @@ end PatternFromToConfig section OccursAtEqCylinder -variable {A G : Type*} [Group G] [Inhabited A] [DecidableEq G] +variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [Inhabited A] [DecidableEq G] + +/-- On the translated support, `patternToConfig` agrees with `p` at the preimage. -/ +@[to_additive addPatternToConfig_apply_of_mem] +lemma patternToConfig_apply_of_mem + {A G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] [Inhabited A] + (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : + patternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by + classical + -- (w*v) is in the translated support + have hmem : (w * v) ∈ p.support.image (· * v) := + Finset.mem_image.mpr ⟨w, hw, rfl⟩ + -- existential used in the branch + have ex : ∃ w', w' ∈ p.support ∧ w' * v = w * v := by + simpa [Finset.mem_image] using hmem + -- open the `if` branch as returned by the definition + have h1 : + patternToConfig (A := A) (G := G) p v (w * v) + = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := by + simp [patternToConfig, hmem] + -- name the chosen witness and relate it to `w` by right-cancellation + let w' := Classical.choose ex + have hw' : w' ∈ p.support := (Classical.choose_spec ex).1 + have hwv' : w' * v = w * v := (Classical.choose_spec ex).2 + have h_eq : w' = w := by simpa using (mul_right_cancel hwv') + -- transport membership along h_eq + have hw_w : w ∈ p.support := by simpa [h_eq] using hw' + -- identify the subtype inside `p.data` (first replace the value w' by w) + have h2 : + (⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ : p.support) + = (⟨w, hw_w⟩ : p.support) := by + apply Subtype.ext + -- goal: Classical.choose ex = w + -- we have h_eq : w' = w and w' := Classical.choose ex + simpa [w'] using h_eq -- <-- use `using h_eq`, only unfold `[w']` + + -- then replace the proof component (same carrier w) + have h3 : + (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := by + apply Subtype.ext + rfl + + -- put the rewrites together + calc + patternToConfig (A := A) (G := G) p v (w * v) + = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := h1 + _ = p.data ⟨w, hw_w⟩ := by + -- push h2 through `p.data` + simpa using + (congrArg (fun z : {x // x ∈ p.support} => p.data z) h2) + _ = p.data ⟨w, hw⟩ := by + -- push h3 through `p.data` + simp [h3] /-- “Occurrence = cylinder translated by `g`”. -/ @[to_additive addOccursAt_eq_cylinder] -lemma occursAt_eq_cylinder (p : Pattern A G) (g : G) : +lemma occursAt_eq_cylinder + {A G : Type*} [Monoid G] [IsRightCancelMul G] [Inhabited A] [DecidableEq G] + (p : Pattern A G) (g : G) : { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (patternToConfig p g) := by - ext x - constructor - · intro H u hu - obtain ⟨w, hw, rfl⟩ := Finset.mem_image.mp hu - dsimp [patternToConfig, patternToOriginConfig, mulShift] - simp [dif_pos hw, H w hw] - · intro H u hu - have := H (u * g) (Finset.mem_image_of_mem _ hu) - dsimp [patternToConfig, patternToOriginConfig, mulShift] at this - simpa [mul_inv_cancel_right, mul_assoc, dif_pos hu] using this + classical + ext x; constructor + · -- ⇒: from an occurrence, get membership in the cylinder + intro H u hu + rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ + -- want: x (w*g) = patternToConfig p g (w*g) + have hx : x (w * g) = p.data ⟨w, hw⟩ := H w hw + simpa [patternToConfig_apply_of_mem (p:=p) (v:=g) (w:=w) hw] using hx + · -- ⇐: from the cylinder, recover an occurrence + intro H u hu + -- H gives equality with the translated pattern on the image + have hx : x (u * g) = patternToConfig p g (u * g) := + H (u * g) (Finset.mem_image_of_mem (· * g) hu) + -- rewrite the RHS by the “apply_of_mem” lemma + simpa [patternToConfig_apply_of_mem (p:=p) (v:=g) (w:=u) hu] using hx end OccursAtEqCylinder @@ -378,7 +456,7 @@ end OccursAtEqCylinder section OccSetsOpen -variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] +variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] [DecidableEq G] /-- Occurrence sets are open. -/ @@ -406,7 +484,7 @@ end OccSetsOpen section OccSetsClosed -variable {A G : Type*} [Group G] [TopologicalSpace A] [DiscreteTopology A] +variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] [DecidableEq G] /-- Occurrence sets are closed. -/ @@ -422,7 +500,7 @@ section DefSubshiftByForbidden variable {A : Type*} [Inhabited A] variable {G : Type*} variable [TopologicalSpace A] [DiscreteTopology A] -variable [Group G] [DecidableEq G] +variable [Monoid G] [IsRightCancelMul G] [DecidableEq G] /-- Subshift defined by forbidden patterns. -/ @[to_additive addX_F] @@ -447,11 +525,11 @@ section Language variable {A : Type*} [Fintype A] variable {G : Type*} variable [TopologicalSpace A] -variable [Group G] +variable [Monoid G] [IsRightCancelMul G] /-- Patterns with fixed support `U`. -/ @[to_additive AddFixedSupport] -def FixedSupport (A : Type*) (G : Type*) [Group G] (U : Finset G) := +def FixedSupport (A : Type*) (G : Type*) [Monoid G] [IsRightCancelMul G] (U : Finset G) := { p : Pattern A G // p.support = U } attribute [inherit_doc SymbolicDynamics.Ambiant.FixedSupport] From 9ddd4fb33440b0fba8e5c9893569165f1fc50615 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 30 Sep 2025 12:21:33 +0200 Subject: [PATCH 25/93] linters --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 18 ++++++++++++++++-- lake-manifest.json | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index ba4ce2d76ddd2f..1cb24c6cd1f493 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -347,6 +347,17 @@ def patternToOriginConfig (p : Pattern A G) : G → A := attribute [inherit_doc SymbolicDynamics.Ambiant.patternToOriginConfig] SymbolicDynamics.Ambiant.addPatternToOriginConfig +/-- Translate a finite pattern `p` so that it occurs at the translate `v`. + +On input `h : G`, we proceed as follows: +* if `h` lies in the right-translate of the support, i.e. `h ∈ p.support.image (· * v)`, + choose (noncomputably) `w ∈ p.support` with `w * v = h` and return `p.data ⟨w, _⟩`; +* otherwise return `default`. + +This definition does **not** assume cancellation; it only *chooses* a preimage. +Uniqueness (and the usual equations such as `patternToConfig p v (w * v) = p.data ⟨w, _⟩`) +require a right-cancellation hypothesis and are proved in separate lemmas. +-/ @[to_additive addPatternToConfig] noncomputable def patternToConfig (p : Pattern A G) (v : G) : G → A := fun h => @@ -361,6 +372,9 @@ noncomputable def patternToConfig (p : Pattern A G) (v : G) : G → A := else default +attribute [inherit_doc SymbolicDynamics.Ambiant.patternToConfig] + SymbolicDynamics.Ambiant.addPatternToConfig + /-- Restrict a configuration to a finite support, seen as a pattern. -/ @[to_additive addPatternFromConfig] def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := @@ -525,11 +539,11 @@ section Language variable {A : Type*} [Fintype A] variable {G : Type*} variable [TopologicalSpace A] -variable [Monoid G] [IsRightCancelMul G] +variable [Monoid G] /-- Patterns with fixed support `U`. -/ @[to_additive AddFixedSupport] -def FixedSupport (A : Type*) (G : Type*) [Monoid G] [IsRightCancelMul G] (U : Finset G) := +def FixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := { p : Pattern A G // p.support = U } attribute [inherit_doc SymbolicDynamics.Ambiant.FixedSupport] diff --git a/lake-manifest.json b/lake-manifest.json index dbbc1fd3e09804..bd000de3469b71 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "43f271c492f815dbbb9a4b753d6ccc9d19b5609a", + "rev": "9e2a0dd176ab4bb5bc5f10e1f5de26af3e094cf4", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", From 0759a0e3850d78b9819b04617c53f5edeee964a4 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 30 Sep 2025 21:38:12 +0200 Subject: [PATCH 26/93] linters --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 1cb24c6cd1f493..9183ba86e77e4b 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -141,7 +141,7 @@ variable {A G : Type*} [Monoid G] @[to_additive] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] -@[to_additive] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : +@[to_additive addShift_mul] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] @@ -151,7 +151,8 @@ section ShiftTopology -- add only topology on A variable {A G : Type*} [Monoid G] [TopologicalSpace A] -@[to_additive] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) (G := G) g) := by +@[to_additive] lemma continuous_mulShift (g : G) : + Continuous (mulShift (A := A) (G := G) g) := by -- coordinate projections are continuous; composition preserves continuity continuity @@ -393,7 +394,6 @@ variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [Inhabited A] [DecidableE /-- On the translated support, `patternToConfig` agrees with `p` at the preimage. -/ @[to_additive addPatternToConfig_apply_of_mem] lemma patternToConfig_apply_of_mem - {A G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] [Inhabited A] (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : patternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by classical @@ -445,7 +445,6 @@ lemma patternToConfig_apply_of_mem /-- “Occurrence = cylinder translated by `g`”. -/ @[to_additive addOccursAt_eq_cylinder] lemma occursAt_eq_cylinder - {A G : Type*} [Monoid G] [IsRightCancelMul G] [Inhabited A] [DecidableEq G] (p : Pattern A G) (g : G) : { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (patternToConfig p g) := by classical From 11fe743f69d0a75014df8b136116237d18709748 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Thu, 2 Oct 2025 10:42:49 +0200 Subject: [PATCH 27/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 9183ba86e77e4b..33f4b18edc1984 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -79,7 +79,7 @@ Thus the file develops the theory ambiently, and subshifts reuse it by restricti For `Y : Subshift A G`, cylinders and occurrence sets *inside `Y`* are simply preimages of the ambient ones under the inclusion `Y → (G → A)`. For example: -`{ y : Y | ∀ i ∈ U, (y : G → A) i = (x : G → A) i } = (Subtype.val) ⁻¹’ (cylinder U (x : G → A)).` +`{ y : Y | ∀ i ∈ U, (y : G → A) i = (x : G → A) i } = (Subtype.val) ⁻¹' (cylinder U (x : G → A)).` Shift invariance guarantees that the ambient shift restricts to `Y`. From 13691689bd9f95ced7f90cd4730e343ed54972c8 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 2 Oct 2025 15:23:27 +0200 Subject: [PATCH 28/93] refactor(SymbolicDynamics): streamline sections and assumptions Regroup consecutive sections that had the same variable line (, , ). Extra assumptions like are introduced only where first needed. This matches mathlib style and avoids unnecessary duplication. --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 150 +++++++------------ 1 file changed, 53 insertions(+), 97 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 33f4b18edc1984..55f5fb70f3d70a 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -90,9 +90,9 @@ ambient definitions. ## Namespacing policy -All ambient definitions live under the namespace `SymbolicDynamics.Ambiant`. +All ambient definitions live under the namespace `SymbolicDynamics.FullShift`. If inner, subshift-relative wrappers are provided, they will be placed in the -subnamespace `SymbolicDynamics.Inner`. This separation avoids name clashes +subnamespace `SymbolicDynamics.Subshift`. This separation avoids name clashes between the two viewpoints, since both may naturally want to reuse names like `cylinder`, `shift`, `occursAt`, or `languageOn`. @@ -110,15 +110,13 @@ open Set Topology namespace SymbolicDynamics -namespace Ambiant +namespace FullShift /-! ## Full shift and shift action -/ section ShiftDefinition -variable {A : Type*} -variable {G : Type*} -variable [Monoid G] +variable {A G : Type*} [Monoid G] /-- Right-translation shift: * In multiplicative notation: `(mulShift g x) h = x (h * g)`. @@ -127,13 +125,8 @@ variable [Monoid G] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) -attribute [inherit_doc SymbolicDynamics.Ambiant.mulShift] SymbolicDynamics.Ambiant.addShift - -end ShiftDefinition +attribute [inherit_doc SymbolicDynamics.FullShift.mulShift] SymbolicDynamics.FullShift.addShift -section ShiftAlgebra - -variable {A G : Type*} [Monoid G] @[to_additive] lemma mulShift_apply (g h : G) (x : G → A) : mulShift g x h = x (h * g) := rfl @@ -145,22 +138,19 @@ variable {A G : Type*} [Monoid G] mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] -end ShiftAlgebra - -section ShiftTopology -- add only topology on A -variable {A G : Type*} [Monoid G] [TopologicalSpace A] +variable [TopologicalSpace A] @[to_additive] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) (G := G) g) := by -- coordinate projections are continuous; composition preserves continuity continuity -end ShiftTopology +end ShiftDefinition /-! ## Cylinders -/ -section CylindersDefs +section Cylinders variable {A G : Type*} @@ -175,14 +165,10 @@ lemma cylinder_eq_set_pi (U : Finset G) (x : G → A) : lemma mem_cylinder {U : Finset G} {x y : G → A} : y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl -end CylindersDefs - -section CylindersOpen - -variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] +variable [TopologicalSpace A] [DiscreteTopology A] /-- Cylinders are open (and, dually, closed) when `A` is discrete. -/ -lemma cylinder_is_open (U : Finset G) (x : G → A) : +lemma isOpen_cylinder (U : Finset G) (x : G → A) : IsOpen (cylinder (A := A) (G := G) U x) := by classical have hopen : ∀ i ∈ (↑U : Set G), IsOpen ({x i} : Set A) := by @@ -193,13 +179,7 @@ lemma cylinder_is_open (U : Finset G) (x : G → A) : isOpen_set_pi (U.finite_toSet) hopen simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi -end CylindersOpen - -section CylindersClosed - -variable {A G : Type*} [TopologicalSpace A] [DiscreteTopology A] - -lemma cylinder_is_closed (U : Finset G) (x : G → A) : +lemma isClosed_cylinder (U : Finset G) (x : G → A) : IsClosed (cylinder (A := A) (G := G) U x) := by classical have hclosed : ∀ i ∈ (↑U : Set G), IsClosed ({x i} : Set A) := by @@ -210,7 +190,7 @@ lemma cylinder_is_closed (U : Finset G) (x : G → A) : isClosed_set_pi hclosed simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi -end CylindersClosed +end Cylinders /-! ## Patterns and occurrences -/ @@ -243,19 +223,21 @@ structure AddSubshift : Type _ where /-- Shift invariance of `carrier` for the additive shift `addShift`. -/ shiftInvariant : ∀ g : G, ∀ x ∈ carrier, addShift g x ∈ carrier + +attribute [to_additive existing SymbolicDynamics.FullShift.AddSubshift] + SymbolicDynamics.FullShift.Subshift + end AddSubshiftDef -attribute [to_additive existing SymbolicDynamics.Ambiant.AddSubshift] - SymbolicDynamics.Ambiant.Subshift /-- Example: the full shift on alphabet A. -/ -@[to_additive SymbolicDynamics.Ambiant.addFullShift] +@[to_additive SymbolicDynamics.FullShift.addFullShift] def fullShift (A G) [TopologicalSpace A] [Monoid G] : Subshift A G := -{ carrier := Set.univ, - isClosed := isClosed_univ, - shiftInvariant := by intro _ _ _; simp } + { carrier := Set.univ, + isClosed := isClosed_univ, + shiftInvariant := by intro _ _ _; simp } -attribute [inherit_doc SymbolicDynamics.Ambiant.fullShift] SymbolicDynamics.Ambiant.addFullShift +attribute [inherit_doc SymbolicDynamics.FullShift.fullShift] SymbolicDynamics.FullShift.addFullShift /-- A finite pattern: finite support in `G` and values on it. -/ structure Pattern (A : Type*) (G : Type*) [Monoid G] where @@ -269,10 +251,10 @@ structure AddPattern (A : Type*) (G : Type*) [AddMonoid G] : Type _ where /-- Finite support of the pattern (subset of `G`). -/ support : Finset G /-- The symbol at each point of the support. -/ - data : support → A + data : support → A -attribute [to_additive existing SymbolicDynamics.Ambiant.AddPattern] - SymbolicDynamics.Ambiant.Pattern +attribute [to_additive existing SymbolicDynamics.FullShift.AddPattern] + SymbolicDynamics.FullShift.Pattern section Dominos @@ -286,7 +268,7 @@ def domino {A : Type*} { support := ({i, j} : Finset G) , data := fun ⟨z, hz⟩ => if z = i then ai else aj } -attribute [inherit_doc SymbolicDynamics.Ambiant.domino] SymbolicDynamics.Ambiant.addDomino +attribute [inherit_doc SymbolicDynamics.FullShift.domino] SymbolicDynamics.FullShift.addDomino end Dominos @@ -301,21 +283,15 @@ variable [Monoid G] def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ -attribute [inherit_doc SymbolicDynamics.Ambiant.Pattern.occursIn] - SymbolicDynamics.Ambiant.Pattern.addOccursIn +attribute [inherit_doc SymbolicDynamics.FullShift.Pattern.occursIn] + SymbolicDynamics.FullShift.Pattern.addOccursIn /-- Configurations avoiding every pattern in `F`. -/ @[to_additive addForbids] def forbids (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } -attribute [inherit_doc SymbolicDynamics.Ambiant.forbids] SymbolicDynamics.Ambiant.addForbids - -end Forbids - -section ShiftInvariance - -variable {A G : Type*} [Monoid G] +attribute [inherit_doc SymbolicDynamics.FullShift.forbids] SymbolicDynamics.FullShift.addForbids /-- Shifts move occurrences as expected. -/ @[to_additive addOccurs_addShift] @@ -332,9 +308,9 @@ lemma forbids_shift_invariant (F : Set (Pattern A G)) : contrapose! hx simpa [occurs_shift] using hx -end ShiftInvariance +end Forbids -section PatternFromToConfig +section OccursAt variable {A : Type*} [Inhabited A] variable {G : Type*} @@ -345,8 +321,8 @@ variable [Monoid G] [IsRightCancelMul G] [DecidableEq G] def patternToOriginConfig (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default -attribute [inherit_doc SymbolicDynamics.Ambiant.patternToOriginConfig] - SymbolicDynamics.Ambiant.addPatternToOriginConfig +attribute [inherit_doc SymbolicDynamics.FullShift.patternToOriginConfig] + SymbolicDynamics.FullShift.addPatternToOriginConfig /-- Translate a finite pattern `p` so that it occurs at the translate `v`. @@ -373,8 +349,8 @@ noncomputable def patternToConfig (p : Pattern A G) (v : G) : G → A := else default -attribute [inherit_doc SymbolicDynamics.Ambiant.patternToConfig] - SymbolicDynamics.Ambiant.addPatternToConfig +attribute [inherit_doc SymbolicDynamics.FullShift.patternToConfig] + SymbolicDynamics.FullShift.addPatternToConfig /-- Restrict a configuration to a finite support, seen as a pattern. -/ @[to_additive addPatternFromConfig] @@ -382,14 +358,9 @@ def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := { support := U, data := fun i => x i.1 } -attribute [inherit_doc SymbolicDynamics.Ambiant.patternFromConfig] - SymbolicDynamics.Ambiant.addPatternFromConfig - -end PatternFromToConfig +attribute [inherit_doc SymbolicDynamics.FullShift.patternFromConfig] + SymbolicDynamics.FullShift.addPatternFromConfig -section OccursAtEqCylinder - -variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [Inhabited A] [DecidableEq G] /-- On the translated support, `patternToConfig` agrees with `p` at the preimage. -/ @[to_additive addPatternToConfig_apply_of_mem] @@ -463,11 +434,11 @@ lemma occursAt_eq_cylinder -- rewrite the RHS by the “apply_of_mem” lemma simpa [patternToConfig_apply_of_mem (p:=p) (v:=g) (w:=u) hu] using hx -end OccursAtEqCylinder +end OccursAt /-! ## Forbidden sets and subshifts -/ -section OccSetsOpen +section DefSubshiftByForbidden variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] [DecidableEq G] @@ -476,7 +447,7 @@ variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [Dis @[to_additive addOccursAt_open] lemma occursAt_open (p : Pattern A G) (g : G) : IsOpen { x | p.occursIn x g } := by - rw [occursAt_eq_cylinder]; exact cylinder_is_open _ _ + rw [occursAt_eq_cylinder]; exact isOpen_cylinder _ _ /-- Avoiding a fixed set of patterns is a closed condition. -/ @[to_additive addForbids_closed] @@ -493,27 +464,11 @@ lemma forbids_closed (F : Set (Pattern A G)) : intro v; have : {x | ¬p.occursIn x v} = {x | p.occursIn x v}ᶜ := by ext x; simp simpa [this, isClosed_compl_iff] using occursAt_open p v -end OccSetsOpen - -section OccSetsClosed - -variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [DiscreteTopology A] - [Inhabited A] [DecidableEq G] - /-- Occurrence sets are closed. -/ @[to_additive addOccursAt_closed] lemma occursAt_closed (p : Pattern A G) (g : G) : IsClosed { x | p.occursIn x g } := by - rw [occursAt_eq_cylinder]; exact cylinder_is_closed _ _ - -end OccSetsClosed - -section DefSubshiftByForbidden - -variable {A : Type*} [Inhabited A] -variable {G : Type*} -variable [TopologicalSpace A] [DiscreteTopology A] -variable [Monoid G] [IsRightCancelMul G] [DecidableEq G] + rw [occursAt_eq_cylinder]; exact isClosed_cylinder _ _ /-- Subshift defined by forbidden patterns. -/ @[to_additive addX_F] @@ -522,14 +477,14 @@ def X_F (F : Set (Pattern A G)) : Subshift A G := isClosed := forbids_closed F, shiftInvariant := forbids_shift_invariant F } -attribute [inherit_doc SymbolicDynamics.Ambiant.X_F] SymbolicDynamics.Ambiant.addX_F +attribute [inherit_doc SymbolicDynamics.FullShift.X_F] SymbolicDynamics.FullShift.addX_F /-- Subshift of finite type defined by a finite family of forbidden patterns. -/ @[to_additive addSFT] def SFT (F : Finset (Pattern A G)) : Subshift A G := X_F (F : Set (Pattern A G)) -attribute [inherit_doc SymbolicDynamics.Ambiant.SFT] SymbolicDynamics.Ambiant.addSFT +attribute [inherit_doc SymbolicDynamics.FullShift.SFT] SymbolicDynamics.FullShift.addSFT end DefSubshiftByForbidden @@ -545,8 +500,8 @@ variable [Monoid G] def FixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := { p : Pattern A G // p.support = U } -attribute [inherit_doc SymbolicDynamics.Ambiant.FixedSupport] - SymbolicDynamics.Ambiant.AddFixedSupport +attribute [inherit_doc SymbolicDynamics.FullShift.FixedSupport] + SymbolicDynamics.FullShift.AddFixedSupport /-- `FixedSupport A G U ≃ (U → A)`; gives finiteness immediately. -/ @[to_additive addEquivFun] @@ -557,9 +512,9 @@ def equivFun {U : Finset G} : left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl right_inv := by intro f; rfl -attribute [inherit_doc SymbolicDynamics.Ambiant.equivFun] SymbolicDynamics.Ambiant.addEquivFun +attribute [inherit_doc SymbolicDynamics.FullShift.equivFun] SymbolicDynamics.FullShift.addEquivFun -@[to_additive SymbolicDynamics.Ambiant.addFintypeFixedSupport] noncomputable +@[to_additive SymbolicDynamics.FullShift.addFintypeFixedSupport] noncomputable instance fintypeFixedSupport {U : Finset G} : Fintype (FixedSupport A G U) := by classical exact Fintype.ofEquiv (U → A) (equivFun (A := A) (G := G) (U := U)).symm @@ -569,7 +524,8 @@ instance fintypeFixedSupport {U : Finset G} : def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, patternFromConfig x U = p } -attribute [inherit_doc SymbolicDynamics.Ambiant.languageOn] SymbolicDynamics.Ambiant.addLanguageOn +attribute [inherit_doc SymbolicDynamics.FullShift.languageOn] + SymbolicDynamics.FullShift.addLanguageOn /-- Cardinality of the finite-support language. -/ @@ -584,19 +540,19 @@ noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by |>.subset (by intro y hy; simp) exact hfin.toFinset.card -attribute [inherit_doc SymbolicDynamics.Ambiant.languageCardOn] - SymbolicDynamics.Ambiant.addLanguageCardOn +attribute [inherit_doc SymbolicDynamics.FullShift.languageCardOn] + SymbolicDynamics.FullShift.addLanguageCardOn /-- Number of patterns of a subshift on a finite shape `U`. -/ @[to_additive addPatternCountOn] noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := languageCardOn (A := A) (G := G) Y.carrier U -attribute [inherit_doc SymbolicDynamics.Ambiant.patternCountOn] - SymbolicDynamics.Ambiant.addPatternCountOn +attribute [inherit_doc SymbolicDynamics.FullShift.patternCountOn] + SymbolicDynamics.FullShift.addPatternCountOn end Language -end Ambiant +end FullShift end SymbolicDynamics From f3db439ba320705b7d74c4231629f3de1be5dcc6 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 2 Oct 2025 18:47:03 +0200 Subject: [PATCH 29/93] doc(SymbolicDynamics/FullShift): improve and clarify docstrings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add introductory explanations for key notions: configurations, cylinders, patterns, occurrences, forbids, subshifts, languages. - Make explicit the assumptions needed in docstrings: * for uniqueness in translated patterns (, , etc.). - Fix minor typos (“ubshift” → “subshift”, “occurence” → “occurrence”). - Expand several docstrings to highlight intuition and role in symbolic dynamics (domino, forbids, X_F, SFT, languageOn, patternCountOn, etc.). - Add cross-references between constructions (e.g. vs ). --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 232 ++++++++++++++++--- 1 file changed, 195 insertions(+), 37 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 55f5fb70f3d70a..047a82d29c8bd3 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -118,15 +118,38 @@ section ShiftDefinition variable {A G : Type*} [Monoid G] -/-- Right-translation shift: -* In multiplicative notation: `(mulShift g x) h = x (h * g)`. -* In additive notation (e.g. for `ℤ^d`): `(addShift v x) u = x (u + v)` -/ -@[to_additive] +/-- The **right-translation shift** on configurations. + +We call *configuration* an element of `G → A`. + +Given a configuration `x : G → A` and an element `g : G` of the group, the shifted configuration +`mulShift g x` is defined by `(mulShift g x) h = x (h * g)`. + +Intuitively, this moves the whole configuration "in the direction of `g`": the value +at position `h` in the shifted configuration is the value that was at position +`h * g` in the original one. + +For example, if `G = ℤ` (with addition) and `A = {0,1}`, then +`addShift 1 x` is the sequence obtained from `x` by shifting every symbol one +step to the left. -/ +@[to_additive + /-- The **right-translation shift** on configurations, in additive notation. + +We call *configuration* an element of `G → A`. + +Given a configuration `x : G → A` and an element `g : G` of the additive group, +the shifted configuration `addShift g x` is defined by `(addShift g x) h = x (h + g)`. + +Intuitively, this moves the whole configuration "in the direction of `g`": the value +at position `h` in the shifted configuration is the value that was at position +`h + g` in the original one. + +For example, if `G = ℤ` and `A = {0,1}`, then +`addShift 1 x` is the sequence obtained from `x` by shifting every symbol one +step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) -attribute [inherit_doc SymbolicDynamics.FullShift.mulShift] SymbolicDynamics.FullShift.addShift - @[to_additive] lemma mulShift_apply (g h : G) (x : G → A) : mulShift g x h = x (h * g) := rfl @@ -134,6 +157,7 @@ attribute [inherit_doc SymbolicDynamics.FullShift.mulShift] SymbolicDynamics.Ful @[to_additive] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] +/-- Composition of right-translation shifts corresponds to multiplication in the group. -/ @[to_additive addShift_mul] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] @@ -141,6 +165,7 @@ attribute [inherit_doc SymbolicDynamics.FullShift.mulShift] SymbolicDynamics.Ful variable [TopologicalSpace A] +/-- The right-translation shift is continuous. -/ @[to_additive] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) (G := G) g) := by -- coordinate projections are continuous; composition preserves continuity @@ -154,10 +179,25 @@ section Cylinders variable {A G : Type*} -/-- Cylinder fixing `x` on the finite set `U`. -/ +/-- A *cylinder set* is the set of all configurations that agree with a given +reference configuration `x` on a fixed finite subset `U` of the index set `G`. + +The set `U` is called the *support* of the cylinder. + +Intuitively, cylinders specify the "letters" on finitely many coordinates, while +leaving all other coordinates free. For example, in the full shift `{0,1}^ℤ`, +the cylinder determined by `U = {0,1}` and `x 0 = 1, x 1 = 0` consists of all +bi-infinite sequences of `0`s and `1`s whose entries on positions `0` and `1` +respectively are `1` and `0`. + +When `A` has the discrete topology, cylinder sets form a basis of clopen sets +for the product topology on `G → A`. -/ def cylinder (U : Finset G) (x : G → A) : Set (G → A) := { y | ∀ i ∈ U, y i = x i } +/-- A cylinder set on `U` is the `Set.pi` over `U` of the singletons `{x i}`, +viewed as a subset of `G → A`. Equivalently, it is the preimage of that product +of singletons in `U → A` under the restriction map `(G → A) → (U → A)`. -/ lemma cylinder_eq_set_pi (U : Finset G) (x : G → A) : cylinder U x = Set.pi (↑U : Set G) (fun i => ({x i} : Set A)) := by ext y; simp [cylinder, Set.pi, Finset.mem_coe] @@ -167,7 +207,7 @@ lemma mem_cylinder {U : Finset G} {x y : G → A} : variable [TopologicalSpace A] [DiscreteTopology A] -/-- Cylinders are open (and, dually, closed) when `A` is discrete. -/ +/-- Cylinders are open when `A` is discrete. -/ lemma isOpen_cylinder (U : Finset G) (x : G → A) : IsOpen (cylinder (A := A) (G := G) U x) := by classical @@ -179,6 +219,7 @@ lemma isOpen_cylinder (U : Finset G) (x : G → A) : isOpen_set_pi (U.finite_toSet) hopen simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi +/-- Cylinders are closed when `A` is discrete. -/ lemma isClosed_cylinder (U : Finset G) (x : G → A) : IsClosed (cylinder (A := A) (G := G) U x) := by classical @@ -198,7 +239,12 @@ section SubshiftDef variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [Monoid G] -/-- A subshift is a closed, shift-invariant subset. -/ +/-- A subshift on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is +composed of: +* `carrier`: the underlying set of allowed configurations. +* `isClosed`: the set is topologically closed in `A^G`. +* `shiftInvariant`: the set is invariant under all right-translation shifts + `(mulShift g)`. -/ structure Subshift : Type _ where /-- The underlying set of configurations. -/ carrier : Set (G → A) @@ -230,7 +276,11 @@ attribute [to_additive existing SymbolicDynamics.FullShift.AddSubshift] end AddSubshiftDef -/-- Example: the full shift on alphabet A. -/ +/-- Example: the **full shift** on alphabet `A` over the (multiplicative) monoid `G`. + +It is the subshift whose underlying set is the set of all configurations +`G → A`. +-/ @[to_additive SymbolicDynamics.FullShift.addFullShift] def fullShift (A G) [TopologicalSpace A] [Monoid G] : Subshift A G := { carrier := Set.univ, @@ -239,7 +289,17 @@ def fullShift (A G) [TopologicalSpace A] [Monoid G] : Subshift A G := attribute [inherit_doc SymbolicDynamics.FullShift.fullShift] SymbolicDynamics.FullShift.addFullShift -/-- A finite pattern: finite support in `G` and values on it. -/ +/-- A **pattern** is a finite configuration in the full shift `A^G`. + +It consists of: +* a finite subset `support : Finset G` of coordinates, called the support of `p`; +* an assignment `data : support → A` of symbols to each point in the support. + +Intuitively, a pattern is a "partial configuration" (like a finite word), +specifying finitely many values of a configuration in `G → A`. Patterns are +the basic building blocks used to define subshifts via forbidden configurations. +Note that each pattern corresponds to a cylinder, which is the set of configurations +which agree with this pattern on its support. -/ structure Pattern (A : Type*) (G : Type*) [Monoid G] where /-- Finite support of the pattern. -/ support : Finset G @@ -260,7 +320,12 @@ section Dominos variable (G : Type*) [Monoid G] [DecidableEq G] -/-- The domino supported on `{i,j}` with values `ai`,`aj`. -/ +/-- A **domino** is a pattern supported on exactly two positions `{i, j}`, +specifying the value `ai` at `i` and the value `aj` at `j`. + +In symbolic dynamics, dominos (two-cell patterns) are the simplest nontrivial +building blocks: they describe local adjacency conditions between two sites +of a configuration. -/ @[to_additive addDomino] def domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by @@ -278,7 +343,15 @@ variable {A : Type*} variable {G : Type*} variable [Monoid G] -/-- Occurrence of a pattern `p` in `x` at position `g`. -/ +/-- `p.occursIn x g` means that the finite pattern `p` appears in the configuration `x` +at position `g`. + +Formally: for every position `h` in the support of `p`, the value of the configuration +at `h * g` coincides with the value specified by `p` at `h`. + +Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), +then on the support of `p` you exactly recover the pattern `p`. This is the basic +notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ @[to_additive Pattern.addOccursIn] def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ @@ -286,20 +359,36 @@ def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := attribute [inherit_doc SymbolicDynamics.FullShift.Pattern.occursIn] SymbolicDynamics.FullShift.Pattern.addOccursIn -/-- Configurations avoiding every pattern in `F`. -/ +/-- `forbids F` is the set of configurations that avoid every pattern in `F`. + +Formally: `x ∈ forbids F` if and only if for every pattern `p ∈ F` and every +group element `g : G`, the pattern `p` does not occur in `x` at position `g`. + +Intuitively, `forbids F` is the shift space defined by declaring the finite set +(or family) of patterns `F` to be *forbidden*. A configuration belongs to the subshift if and only +it avoids all the forbidden patterns. -/ @[to_additive addForbids] def forbids (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } attribute [inherit_doc SymbolicDynamics.FullShift.forbids] SymbolicDynamics.FullShift.addForbids -/-- Shifts move occurrences as expected. -/ +/-- Shifting a configuration commutes with occurrences of a pattern. + +Formally: a pattern `p` occurs in the shifted configuration `mulShift h x` at +position `g` if and only if it occurs in the original configuration `x` at +position `g * h`. -/ @[to_additive addOccurs_addShift] lemma occurs_shift (p : Pattern A G) (x : G → A) (g h : G) : p.occursIn (mulShift h x) g ↔ p.occursIn x (g * h) := by constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu -@[to_additive addForbids_addShift_invariant] +/-- Configurations that avoid a family `F` of patterns are stable under the shift. + +Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, +the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every position. -/ +@[to_additive addForbids_addShift_invariant + /-- Additive version: configurations avoiding `F` are stable under all additive shifts. -/] lemma forbids_shift_invariant (F : Set (Pattern A G)) : ∀ h : G, ∀ x ∈ forbids (A := A) (G := G) F, mulShift h x ∈ forbids F := by intro h x hx p hp g @@ -314,9 +403,19 @@ section OccursAt variable {A : Type*} [Inhabited A] variable {G : Type*} +-- We assume right-cancellation throughout this section for uniqueness of preimages under (_ * v). variable [Monoid G] [IsRightCancelMul G] [DecidableEq G] -/-- Extend a pattern by `default` away from its support (anchored at the origin). -/ +/-- Turn a finite pattern into a configuration, by extending it with +the default symbol outside its support. + +Formally: given a pattern `p` with finite support in `G`, we define a configuration +`patternToOriginConfig p : G → A` by setting +* `patternToOriginConfig p i = p.data ⟨i, h⟩` if `i ∈ p.support`, +* `patternToOriginConfig p i = default` otherwise. + +This produces a canonical "completion" of the pattern to a configuration, +filling all unspecified positions with `default`. -/ @[to_additive addPatternToOriginConfig] def patternToOriginConfig (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default @@ -324,14 +423,15 @@ def patternToOriginConfig (p : Pattern A G) : G → A := attribute [inherit_doc SymbolicDynamics.FullShift.patternToOriginConfig] SymbolicDynamics.FullShift.addPatternToOriginConfig -/-- Translate a finite pattern `p` so that it occurs at the translate `v`. +/-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into +a configuration. On input `h : G`, we proceed as follows: * if `h` lies in the right-translate of the support, i.e. `h ∈ p.support.image (· * v)`, choose (noncomputably) `w ∈ p.support` with `w * v = h` and return `p.data ⟨w, _⟩`; * otherwise return `default`. -This definition does **not** assume cancellation; it only *chooses* a preimage. +This definition does not assume right-cancellation; it only *chooses* a preimage. Uniqueness (and the usual equations such as `patternToConfig p v (w * v) = p.data ⟨w, _⟩`) require a right-cancellation hypothesis and are proved in separate lemmas. -/ @@ -352,7 +452,15 @@ noncomputable def patternToConfig (p : Pattern A G) (v : G) : G → A := attribute [inherit_doc SymbolicDynamics.FullShift.patternToConfig] SymbolicDynamics.FullShift.addPatternToConfig -/-- Restrict a configuration to a finite support, seen as a pattern. -/ +/-- Extract the finite pattern given by restricting a configuration `x : G → A` +to a finite subset `U : Finset G`. + +Formally: the support is `U`, and for each `i ∈ U` the pattern records the value +`x i`. In other words, `patternFromConfig x U` is the partial configuration of +`x` visible on the coordinates in `U`. + +This is the inverse construction to `patternToOriginConfig` (which extends a +finite pattern to a configuration by filling with `default`). -/ @[to_additive addPatternFromConfig] def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := { support := U, @@ -362,8 +470,15 @@ attribute [inherit_doc SymbolicDynamics.FullShift.patternFromConfig] SymbolicDynamics.FullShift.addPatternFromConfig -/-- On the translated support, `patternToConfig` agrees with `p` at the preimage. -/ -@[to_additive addPatternToConfig_apply_of_mem] +/-- On the translated support, `patternToConfig p v` agrees with `p` at the preimage. + +More precisely, if `w ∈ p.support`, then at the translated site `w * v`, +the configuration `patternToConfig p v` takes the value prescribed by `p` at `w`. + +This statement uses `[IsRightCancelMul G]` to identify the preimage of `w * v` +under right-multiplication by `v`.-/ +@[to_additive addPatternToConfig_apply_of_mem + /-- Additive version: on the translated support, `addPatternToConfig` agrees with the pattern. -/] lemma patternToConfig_apply_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : patternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by @@ -413,8 +528,18 @@ lemma patternToConfig_apply_of_mem -- push h3 through `p.data` simp [h3] -/-- “Occurrence = cylinder translated by `g`”. -/ -@[to_additive addOccursAt_eq_cylinder] +/-- We call *occurrence set* for pattern `p` and position `g` the set of configurations +in which a pattern `p` occurs at position `g`. + +This proves that it is exactly the cylinder corresponding to the +pattern obtained by translating `p` by `g`. + +Equivalently, `p.occursIn x g` iff on every translated site `w * g` (with `w ∈ p.support`) +the configuration `x` agrees with the translated pattern `patternToConfig p g`. + +(This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ +@[to_additive addOccursAt_eq_cylinder + /-- Additive version: occurrences at `g` coincide with the corresponding cylinder. -/] lemma occursAt_eq_cylinder (p : Pattern A G) (g : G) : { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (patternToConfig p g) := by @@ -425,14 +550,14 @@ lemma occursAt_eq_cylinder rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ -- want: x (w*g) = patternToConfig p g (w*g) have hx : x (w * g) = p.data ⟨w, hw⟩ := H w hw - simpa [patternToConfig_apply_of_mem (p:=p) (v:=g) (w:=w) hw] using hx + simpa [patternToConfig_apply_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image have hx : x (u * g) = patternToConfig p g (u * g) := H (u * g) (Finset.mem_image_of_mem (· * g) hu) -- rewrite the RHS by the “apply_of_mem” lemma - simpa [patternToConfig_apply_of_mem (p:=p) (v:=g) (w:=u) hu] using hx + simpa [patternToConfig_apply_of_mem (p := p) (v := g) (w := u) hu] using hx end OccursAt @@ -449,7 +574,11 @@ lemma occursAt_open (p : Pattern A G) (g : G) : IsOpen { x | p.occursIn x g } := by rw [occursAt_eq_cylinder]; exact isOpen_cylinder _ _ -/-- Avoiding a fixed set of patterns is a closed condition. -/ +/-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). + +Since each occurrence set `{ x | p.occursIn x v }` is open (when `A` is discrete), +its complement `{ x | ¬ p.occursIn x v }` is closed; `forbids F` is the intersection +of these closed sets over `p ∈ F` and `v ∈ G`. -/ @[to_additive addForbids_closed] lemma forbids_closed (F : Set (Pattern A G)) : IsClosed (forbids F) := by @@ -470,7 +599,16 @@ lemma occursAt_closed (p : Pattern A G) (g : G) : IsClosed { x | p.occursIn x g } := by rw [occursAt_eq_cylinder]; exact isClosed_cylinder _ _ -/-- Subshift defined by forbidden patterns. -/ +/-- The subshift defined by a family of forbidden patterns `F`. + +This is a standard way to construct subshifts: +`X_F F` consists of all configurations `x : G → A` in which no pattern +`p ∈ F` occurs at any position. + +Formally: +* the carrier is `forbids F` (configurations avoiding `F`), +* it is closed because each occurrence set is open, and +* it is shift-invariant since avoidance is preserved by shifts. -/ @[to_additive addX_F] def X_F (F : Set (Pattern A G)) : Subshift A G := { carrier := forbids F, @@ -479,7 +617,10 @@ def X_F (F : Set (Pattern A G)) : Subshift A G := attribute [inherit_doc SymbolicDynamics.FullShift.X_F] SymbolicDynamics.FullShift.addX_F -/-- Subshift of finite type defined by a finite family of forbidden patterns. -/ +/-- A subshift of finite type (SFT) is a subshift defined by forbidding +a *finite* family of patterns. + +Formally, `SFT F` is `X_F F` where `F` is a `Finset (Pattern A G)`. -/ @[to_additive addSFT] def SFT (F : Finset (Pattern A G)) : Subshift A G := X_F (F : Set (Pattern A G)) @@ -495,7 +636,7 @@ variable {G : Type*} variable [TopologicalSpace A] variable [Monoid G] -/-- Patterns with fixed support `U`. -/ +/-- The set of patterns with fixed support `U`. -/ @[to_additive AddFixedSupport] def FixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := { p : Pattern A G // p.support = U } @@ -503,8 +644,18 @@ def FixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := attribute [inherit_doc SymbolicDynamics.FullShift.FixedSupport] SymbolicDynamics.FullShift.AddFixedSupport -/-- `FixedSupport A G U ≃ (U → A)`; gives finiteness immediately. -/ -@[to_additive addEquivFun] +/-- An equivalence between patterns with fixed support and functions on that support. + +Concretely, `FixedSupport A G U` is the subtype of patterns whose support is +exactly `U`. Such a pattern is determined uniquely by its values on `U`, +i.e. by a function `U → A`. This equivalence makes that identification precise: + +* `toFun` sends a fixed-support pattern to the function recording its values, +* `invFun` rebuilds the pattern from a function on `U`. + +This shows immediately that `FixedSupport A G U` is finite whenever `U` is. -/ +@[to_additive addEquivFun + /-- Additive version: equivalence between fixed-support additive patterns and functions. -/] def equivFun {U : Finset G} : FixedSupport A G U ≃ (U → A) where toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ @@ -512,14 +663,17 @@ def equivFun {U : Finset G} : left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl right_inv := by intro f; rfl -attribute [inherit_doc SymbolicDynamics.FullShift.equivFun] SymbolicDynamics.FullShift.addEquivFun - +/-- `FixedSupport A G U` is a finite type: there are only finitely many patterns +with support exactly `U`. This follows from the equivalence with functions `U → A`. -/ @[to_additive SymbolicDynamics.FullShift.addFintypeFixedSupport] noncomputable instance fintypeFixedSupport {U : Finset G} : Fintype (FixedSupport A G U) := by classical exact Fintype.ofEquiv (U → A) (equivFun (A := A) (G := G) (U := U)).symm -/-- Language on a finite set `U ⊆ G`: patterns obtained by restricting some `x ∈ X`. -/ +/-- The language of a set of configurations `X` on a finite shape `U`. + +This is the set of all finite patterns obtained by restricting some configuration +`x ∈ X` to `U`. -/ @[to_additive addLanguageOn] def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, patternFromConfig x U = p } @@ -528,7 +682,10 @@ attribute [inherit_doc SymbolicDynamics.FullShift.languageOn] SymbolicDynamics.FullShift.addLanguageOn -/-- Cardinality of the finite-support language. -/ +/-- The cardinality of the language of `X` on a finite set `U`. + +That is, the number of distinct patterns supported on `U` which appear +in some configuration of `X`. Since `U` is finite, this is a finite number. -/ @[to_additive addLanguageCardOn] noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by classical @@ -543,7 +700,8 @@ noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by attribute [inherit_doc SymbolicDynamics.FullShift.languageCardOn] SymbolicDynamics.FullShift.addLanguageCardOn -/-- Number of patterns of a subshift on a finite shape `U`. -/ +/-- The number of patterns which appear in the configurations of the carrier +of a subshift `Y` on a finite set `U`. -/ @[to_additive addPatternCountOn] noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := languageCardOn (A := A) (G := G) Y.carrier U From 5d5b8ae319e334a91a78956e7f7a81ad51cc132f Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 2 Oct 2025 18:50:04 +0200 Subject: [PATCH 30/93] small docstrings warning and removing A and G from isOpen_cylinder + isClosed_cylinder statement --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 047a82d29c8bd3..0d1ab294cea854 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -209,7 +209,7 @@ variable [TopologicalSpace A] [DiscreteTopology A] /-- Cylinders are open when `A` is discrete. -/ lemma isOpen_cylinder (U : Finset G) (x : G → A) : - IsOpen (cylinder (A := A) (G := G) U x) := by + IsOpen (cylinder U x) := by classical have hopen : ∀ i ∈ (↑U : Set G), IsOpen ({x i} : Set A) := by intro i _; simp @@ -221,7 +221,7 @@ lemma isOpen_cylinder (U : Finset G) (x : G → A) : /-- Cylinders are closed when `A` is discrete. -/ lemma isClosed_cylinder (U : Finset G) (x : G → A) : - IsClosed (cylinder (A := A) (G := G) U x) := by + IsClosed (cylinder U x) := by classical have hclosed : ∀ i ∈ (↑U : Set G), IsClosed ({x i} : Set A) := by intro i _; simp @@ -476,7 +476,7 @@ More precisely, if `w ∈ p.support`, then at the translated site `w * v`, the configuration `patternToConfig p v` takes the value prescribed by `p` at `w`. This statement uses `[IsRightCancelMul G]` to identify the preimage of `w * v` -under right-multiplication by `v`.-/ +under right-multiplication by `v`. -/ @[to_additive addPatternToConfig_apply_of_mem /-- Additive version: on the translated support, `addPatternToConfig` agrees with the pattern. -/] lemma patternToConfig_apply_of_mem From 9f2761ef938724f7848979ca4870aa1e9bb57fb0 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:29:31 +0200 Subject: [PATCH 31/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 0d1ab294cea854..4cea16f6847586 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -159,7 +159,7 @@ def mulShift (g : G) (x : G → A) : G → A := /-- Composition of right-translation shifts corresponds to multiplication in the group. -/ @[to_additive addShift_mul] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : - mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by + mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] From 4ec487b140d8d4d0487099f409105d91022a534a Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:29:57 +0200 Subject: [PATCH 32/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 4cea16f6847586..735fcfd843d271 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -3,11 +3,8 @@ Copyright (c) 2025 S. Gangloff. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: S. Gangloff -/ - -import Mathlib.Topology.Basic import Mathlib.Topology.Constructions -import Mathlib.Data.Finset.Basic -import Mathlib.Logic.Equiv.Defs + /-! # Symbolic dynamics on cancellative monoids From c37e49b08bae926d7b4ae960fec4dfaf491b781d Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:30:21 +0200 Subject: [PATCH 33/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 735fcfd843d271..01a0cba9d57cd4 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -207,7 +207,6 @@ variable [TopologicalSpace A] [DiscreteTopology A] /-- Cylinders are open when `A` is discrete. -/ lemma isOpen_cylinder (U : Finset G) (x : G → A) : IsOpen (cylinder U x) := by - classical have hopen : ∀ i ∈ (↑U : Set G), IsOpen ({x i} : Set A) := by intro i _; simp have hpi : From f4fe917b33b66542c5077aee138b6b5fa9b2832c Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:38:39 +0200 Subject: [PATCH 34/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 01a0cba9d57cd4..00e5d8586234ad 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -163,10 +163,11 @@ def mulShift (g : G) (x : G → A) : G → A := variable [TopologicalSpace A] /-- The right-translation shift is continuous. -/ -@[to_additive] lemma continuous_mulShift (g : G) : - Continuous (mulShift (A := A) (G := G) g) := by +@[to_additive (attr := fun_prop)] lemma continuous_mulShift (g : G) : + Continuous (mulShift (A := A) g) := by -- coordinate projections are continuous; composition preserves continuity - continuity + unfold mulShift + fun_prop end ShiftDefinition From 8dfdf683bbc2dfd1fb3d133ea7652b6d3a94d2b1 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Wed, 8 Oct 2025 10:48:12 +0200 Subject: [PATCH 35/93] =?UTF-8?q?feat(symbolic=5Fdynamics):=20-=20Rename?= =?UTF-8?q?=20additive=20image=20of=20=20to=20=20with=20=20=20and=20update?= =?UTF-8?q?=20docstrings=20accordingly;=20similar=20modifications=20for=20?= =?UTF-8?q?other=20structures=20and=20statements=20-=20Conform=20to=20math?= =?UTF-8?q?lib=20naming=20conventions:=20lowercase=20structure=20names;=20?= =?UTF-8?q?=20=20rename=20=20=E2=86=92=20=20(and=20multiplicative=20varian?= =?UTF-8?q?t=20=20if=20present).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 323 +++++++++---------- 1 file changed, 161 insertions(+), 162 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 00e5d8586234ad..3cc9592ee31220 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -1,7 +1,7 @@ /- -Copyright (c) 2025 S. Gangloff. All rights reserved. +Copyright (c) 2025 Silvère Gangloff. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: S. Gangloff +Authors: Silvère Gangloff -/ import Mathlib.Topology.Constructions @@ -31,34 +31,36 @@ Some constructions, such as translating a finite pattern to occur at a point `v` require solving equations of the form `w * v = h`. For this to have a unique solution `w` given `h` and `v`, we assume **right-cancellation**: if `a * v = b * v` then `a = b`. This allows us to define -`patternToConfig` without using inverses, so that the theory works not only -for groups but also for cancellative monoids. +`patternToConfig` (which extends a pattern into a configuration +using the default value of `A`) without using inverses, +so that the theory works not only for groups but also for cancellative monoids. ## Main definitions -* `mulShift g x` — right translation: in multiplicative notation - `(mulShift g x) h = x (h * g)`; additive notation `(addShift v x) u = x (u + v)`. +* `mulShift g x` — right translation: in additive notation `(shift v x) u = x (u + v)`; + multiplicative notation `(mulShift g x) h = x (h * g)`. * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. -* `Pattern A G` — finite support together with values on that support. -* `Pattern.occursIn p x g` — occurrence of `p` in `x` at translate `g`. +* `pattern A G` — finite support together with values on that support. +* `pattern.occursIn p x g` — occurrence of `p` in `x` at translate `g`. * `forbids F` — configurations avoiding every pattern in `F`. -* `Subshift A G` — closed, shift-invariant subsets of the full shift. -* `X_F F` — the subshift defined by forbidding a family of patterns. -* `SFT F` — a subshift of finite type defined by a finite set of forbidden patterns. +* `subshift A G` — closed, shift-invariant subsets of the full shift. +* `subshft_from_forbidden F` — the subshift defined by forbidding a family of patterns. +* `subshift_of_finite_type F` — a subshift of finite type defined by a finite set of +forbidden patterns. * `languageOn X U` — the set of patterns of shape `U` obtained by restricting some `x ∈ X`. ## Conventions We use a **right** action of `G` on configurations: +`(shift v x) u = x (u + v)`. +In multiplicative notation: `(mulShift g x) h = x (h * g)`. -In additive notation (e.g. for `ℤ^d`): -`(addShift v x) u = x (u + v)`. ## Design choice: ambient vs. inner (subshift-relative) viewpoint All core notions (shift, cylinder, occurrence, language, …) are defined **in the ambient full shift** `(G → A)`. A subshift is then a closed, invariant subset, -bundled as `Subshift A G`. Working inside a subshift is done by restriction. +bundled as `subshift A G`. Working inside a subshift is done by restriction. **Motivation.** If cylinders and shifts were defined only *inside* a subshift, local ergonomics @@ -73,7 +75,7 @@ definitions these set-theoretic identities are tautological. Thus the file develops the theory ambiently, and subshifts reuse it by restriction. **Working inside a subshift.** -For `Y : Subshift A G`, cylinders and occurrence sets *inside `Y`* are simply +For `Y : subshift A G`, cylinders and occurrence sets *inside `Y`* are simply preimages of the ambient ones under the inclusion `Y → (G → A)`. For example: `{ y : Y | ∀ i ∈ U, (y : G → A) i = (x : G → A) i } = (Subtype.val) ⁻¹' (cylinder U (x : G → A)).` @@ -120,34 +122,33 @@ variable {A G : Type*} [Monoid G] We call *configuration* an element of `G → A`. Given a configuration `x : G → A` and an element `g : G` of the group, the shifted configuration -`mulShift g x` is defined by `(mulShift g x) h = x (h * g)`. +`shift g x` is defined by `(shift g x) h = x (h + g)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value at position `h` in the shifted configuration is the value that was at position -`h * g` in the original one. +`h + g` in the original one. For example, if `G = ℤ` (with addition) and `A = {0,1}`, then -`addShift 1 x` is the sequence obtained from `x` by shifting every symbol one +`shift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ -@[to_additive - /-- The **right-translation shift** on configurations, in additive notation. +@[to_additive shift +/-- The **right-translation shift** on configurations, in additive notation. We call *configuration* an element of `G → A`. -Given a configuration `x : G → A` and an element `g : G` of the additive group, -the shifted configuration `addShift g x` is defined by `(addShift g x) h = x (h + g)`. +Given a configuration `x : G → A` and an element `g : G` of the multiplicative group, +the shifted configuration `mulShift g x` is defined by `(mulShift g x) h = x (h * g)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value at position `h` in the shifted configuration is the value that was at position `h + g` in the original one. For example, if `G = ℤ` and `A = {0,1}`, then -`addShift 1 x` is the sequence obtained from `x` by shifting every symbol one +`mulShift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) - @[to_additive] lemma mulShift_apply (g h : G) (x : G → A) : mulShift g x h = x (h * g) := rfl @@ -155,11 +156,10 @@ def mulShift (g : G) (x : G → A) : G → A := ext h; simp [mulShift] /-- Composition of right-translation shifts corresponds to multiplication in the group. -/ -@[to_additive addShift_mul] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : +@[to_additive shift_mul] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] - variable [TopologicalSpace A] /-- The right-translation shift is continuous. -/ @@ -219,7 +219,6 @@ lemma isOpen_cylinder (U : Finset G) (x : G → A) : /-- Cylinders are closed when `A` is discrete. -/ lemma isClosed_cylinder (U : Finset G) (x : G → A) : IsClosed (cylinder U x) := by - classical have hclosed : ∀ i ∈ (↑U : Set G), IsClosed ({x i} : Set A) := by intro i _; simp have hpi : @@ -232,45 +231,45 @@ end Cylinders /-! ## Patterns and occurrences -/ + section SubshiftDef variable (A : Type*) [TopologicalSpace A] -variable (G : Type*) [Monoid G] +variable (G : Type*) [AddMonoid G] -/-- A subshift on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is +/-- A *subshift* on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is composed of: * `carrier`: the underlying set of allowed configurations. * `isClosed`: the set is topologically closed in `A^G`. * `shiftInvariant`: the set is invariant under all right-translation shifts - `(mulShift g)`. -/ -structure Subshift : Type _ where - /-- The underlying set of configurations. -/ + `(shift g)`. -/ +structure subshift : Type _ where + /-- The underlying set of configurations (additive group version). -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier - /-- Shift invariance of `carrier`. -/ - shiftInvariant : ∀ g : G, ∀ x ∈ carrier, mulShift g x ∈ carrier + /-- Shift invariance of `carrier` for the additive shift `shift`. -/ + shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift g x ∈ carrier end SubshiftDef - -section AddSubshiftDef +section MulSubshiftDef variable (A : Type*) [TopologicalSpace A] -variable (G : Type*) [AddMonoid G] +variable (G : Type*) [Monoid G] -/-- Additive version of the definition of subshift. -/ -structure AddSubshift : Type _ where - /-- The underlying set of configurations (additive group version). -/ +/-- Multiplicative version of the definition of subshift. -/ +structure mulSubshift : Type _ where + /-- The underlying set of configurations. -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier - /-- Shift invariance of `carrier` for the additive shift `addShift`. -/ - shiftInvariant : ∀ g : G, ∀ x ∈ carrier, addShift g x ∈ carrier + /-- Shift invariance of `carrier`. -/ + shiftInvariant : ∀ g : G, ∀ x ∈ carrier, mulShift g x ∈ carrier +end MulSubshiftDef -attribute [to_additive existing SymbolicDynamics.FullShift.AddSubshift] - SymbolicDynamics.FullShift.Subshift -end AddSubshiftDef +attribute [to_additive existing SymbolicDynamics.FullShift.subshift] + SymbolicDynamics.FullShift.mulSubshift /-- Example: the **full shift** on alphabet `A` over the (multiplicative) monoid `G`. @@ -278,15 +277,15 @@ end AddSubshiftDef It is the subshift whose underlying set is the set of all configurations `G → A`. -/ -@[to_additive SymbolicDynamics.FullShift.addFullShift] -def fullShift (A G) [TopologicalSpace A] [Monoid G] : Subshift A G := +@[to_additive SymbolicDynamics.FullShift.fullShift] +def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : mulSubshift A G := { carrier := Set.univ, isClosed := isClosed_univ, shiftInvariant := by intro _ _ _; simp } -attribute [inherit_doc SymbolicDynamics.FullShift.fullShift] SymbolicDynamics.FullShift.addFullShift +attribute [inherit_doc SymbolicDynamics.FullShift.mulFullShift] SymbolicDynamics.FullShift.fullShift -/-- A **pattern** is a finite configuration in the full shift `A^G`. +/-- A *pattern* is a finite configuration in the full shift `A^G`. It consists of: * a finite subset `support : Finset G` of coordinates, called the support of `p`; @@ -297,40 +296,40 @@ specifying finitely many values of a configuration in `G → A`. Patterns are the basic building blocks used to define subshifts via forbidden configurations. Note that each pattern corresponds to a cylinder, which is the set of configurations which agree with this pattern on its support. -/ -structure Pattern (A : Type*) (G : Type*) [Monoid G] where +structure mulPattern (A : Type*) (G : Type*) [Monoid G] where /-- Finite support of the pattern. -/ support : Finset G /-- The value (symbol) at each point of the support. -/ data : support → A /-- Additive version of `Pattern`. -/ -structure AddPattern (A : Type*) (G : Type*) [AddMonoid G] : Type _ where +structure pattern (A : Type*) (G : Type*) [AddMonoid G] : Type _ where /-- Finite support of the pattern (subset of `G`). -/ support : Finset G /-- The symbol at each point of the support. -/ data : support → A -attribute [to_additive existing SymbolicDynamics.FullShift.AddPattern] - SymbolicDynamics.FullShift.Pattern +attribute [to_additive existing SymbolicDynamics.FullShift.pattern] + SymbolicDynamics.FullShift.mulPattern section Dominos variable (G : Type*) [Monoid G] [DecidableEq G] -/-- A **domino** is a pattern supported on exactly two positions `{i, j}`, -specifying the value `ai` at `i` and the value `aj` at `j`. +/-- A *domino* is a pattern supported on exactly two positions (sometimes +also called cells) `{i, j}`, specifying the value `ai` at `i` and the value `aj` at `j`. In symbolic dynamics, dominos (two-cell patterns) are the simplest nontrivial building blocks: they describe local adjacency conditions between two sites of a configuration. -/ -@[to_additive addDomino] -def domino {A : Type*} - (i j : G) (ai aj : A) : Pattern A G := by +@[to_additive domino] +def mulDomino {A : Type*} + (i j : G) (ai aj : A) : mulPattern A G := by refine { support := ({i, j} : Finset G) , data := fun ⟨z, hz⟩ => if z = i then ai else aj } -attribute [inherit_doc SymbolicDynamics.FullShift.domino] SymbolicDynamics.FullShift.addDomino +attribute [inherit_doc SymbolicDynamics.FullShift.mulDomino] SymbolicDynamics.FullShift.domino end Dominos @@ -344,17 +343,17 @@ variable [Monoid G] at position `g`. Formally: for every position `h` in the support of `p`, the value of the configuration -at `h * g` coincides with the value specified by `p` at `h`. +at `h + g` coincides with the value specified by `p` at `h`. -Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), +Intuitively, if you shift the configuration `x` by `g` (using `shift g`), then on the support of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ -@[to_additive Pattern.addOccursIn] -def Pattern.occursIn (p : Pattern A G) (x : G → A) (g : G) : Prop := +@[to_additive] +def mulPattern.occursIn (p : mulPattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ -attribute [inherit_doc SymbolicDynamics.FullShift.Pattern.occursIn] - SymbolicDynamics.FullShift.Pattern.addOccursIn +attribute [inherit_doc SymbolicDynamics.FullShift.mulPattern.occursIn] + SymbolicDynamics.FullShift.pattern.occursIn /-- `forbids F` is the set of configurations that avoid every pattern in `F`. @@ -364,35 +363,35 @@ group element `g : G`, the pattern `p` does not occur in `x` at position `g`. Intuitively, `forbids F` is the shift space defined by declaring the finite set (or family) of patterns `F` to be *forbidden*. A configuration belongs to the subshift if and only it avoids all the forbidden patterns. -/ -@[to_additive addForbids] -def forbids (F : Set (Pattern A G)) : Set (G → A) := +@[to_additive forbids] +def mulForbids (F : Set (mulPattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } -attribute [inherit_doc SymbolicDynamics.FullShift.forbids] SymbolicDynamics.FullShift.addForbids +attribute [inherit_doc SymbolicDynamics.FullShift.mulForbids] SymbolicDynamics.FullShift.forbids /-- Shifting a configuration commutes with occurrences of a pattern. -Formally: a pattern `p` occurs in the shifted configuration `mulShift h x` at +Formally: a pattern `p` occurs in the shifted configuration `shift h x` at position `g` if and only if it occurs in the original configuration `x` at -position `g * h`. -/ -@[to_additive addOccurs_addShift] -lemma occurs_shift (p : Pattern A G) (x : G → A) (g h : G) : +position `g + h`. -/ +@[to_additive occurs_shift] +lemma mulOccurs_mulShift (p : mulPattern A G) (x : G → A) (g h : G) : p.occursIn (mulShift h x) g ↔ p.occursIn x (g * h) := by constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu /-- Configurations that avoid a family `F` of patterns are stable under the shift. Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, -the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every position. -/ -@[to_additive addForbids_addShift_invariant +the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/ +@[to_additive forbids_shift_invariant /-- Additive version: configurations avoiding `F` are stable under all additive shifts. -/] -lemma forbids_shift_invariant (F : Set (Pattern A G)) : - ∀ h : G, ∀ x ∈ forbids (A := A) (G := G) F, mulShift h x ∈ forbids F := by +lemma mulForbids_shift_invariant (F : Set (mulPattern A G)) : + ∀ h : G, ∀ x ∈ mulForbids (A := A) (G := G) F, mulShift h x ∈ mulForbids F := by intro h x hx p hp g specialize hx p hp (g * h) -- contraposition contrapose! hx - simpa [occurs_shift] using hx + simpa [mulOccurs_mulShift] using hx end Forbids @@ -413,12 +412,12 @@ Formally: given a pattern `p` with finite support in `G`, we define a configurat This produces a canonical "completion" of the pattern to a configuration, filling all unspecified positions with `default`. -/ -@[to_additive addPatternToOriginConfig] -def patternToOriginConfig (p : Pattern A G) : G → A := +@[to_additive patternToOriginConfig] +def mulPatternToOriginConfig (p : mulPattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default -attribute [inherit_doc SymbolicDynamics.FullShift.patternToOriginConfig] - SymbolicDynamics.FullShift.addPatternToOriginConfig +attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternToOriginConfig] + SymbolicDynamics.FullShift.patternToOriginConfig /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. @@ -432,8 +431,8 @@ This definition does not assume right-cancellation; it only *chooses* a preimage Uniqueness (and the usual equations such as `patternToConfig p v (w * v) = p.data ⟨w, _⟩`) require a right-cancellation hypothesis and are proved in separate lemmas. -/ -@[to_additive addPatternToConfig] -noncomputable def patternToConfig (p : Pattern A G) (v : G) : G → A := +@[to_additive patternToConfig] +noncomputable def mulPatternToConfig (p : mulPattern A G) (v : G) : G → A := fun h => if hmem : h ∈ p.support.image (· * v) then -- package existence of a preimage under (_ * v) @@ -446,8 +445,8 @@ noncomputable def patternToConfig (p : Pattern A G) (v : G) : G → A := else default -attribute [inherit_doc SymbolicDynamics.FullShift.patternToConfig] - SymbolicDynamics.FullShift.addPatternToConfig +attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternToConfig] + SymbolicDynamics.FullShift.patternToConfig /-- Extract the finite pattern given by restricting a configuration `x : G → A` to a finite subset `U : Finset G`. @@ -458,13 +457,13 @@ Formally: the support is `U`, and for each `i ∈ U` the pattern records the val This is the inverse construction to `patternToOriginConfig` (which extends a finite pattern to a configuration by filling with `default`). -/ -@[to_additive addPatternFromConfig] -def patternFromConfig (x : G → A) (U : Finset G) : Pattern A G := +@[to_additive patternFromConfig] +def mulPatternFromConfig (x : G → A) (U : Finset G) : mulPattern A G := { support := U, data := fun i => x i.1 } -attribute [inherit_doc SymbolicDynamics.FullShift.patternFromConfig] - SymbolicDynamics.FullShift.addPatternFromConfig +attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternFromConfig] + SymbolicDynamics.FullShift.patternFromConfig /-- On the translated support, `patternToConfig p v` agrees with `p` at the preimage. @@ -474,12 +473,11 @@ the configuration `patternToConfig p v` takes the value prescribed by `p` at `w` This statement uses `[IsRightCancelMul G]` to identify the preimage of `w * v` under right-multiplication by `v`. -/ -@[to_additive addPatternToConfig_apply_of_mem +@[to_additive patternToConfig_apply_of_mem /-- Additive version: on the translated support, `addPatternToConfig` agrees with the pattern. -/] -lemma patternToConfig_apply_of_mem - (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : - patternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by - classical +lemma mulPatternToConfig_apply_of_mem + (p : mulPattern A G) (v w : G) (hw : w ∈ p.support) : + mulPatternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by -- (w*v) is in the translated support have hmem : (w * v) ∈ p.support.image (· * v) := Finset.mem_image.mpr ⟨w, hw, rfl⟩ @@ -488,9 +486,9 @@ lemma patternToConfig_apply_of_mem simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition have h1 : - patternToConfig (A := A) (G := G) p v (w * v) + mulPatternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := by - simp [patternToConfig, hmem] + simp [mulPatternToConfig, hmem] -- name the chosen witness and relate it to `w` by right-cancellation let w' := Classical.choose ex have hw' : w' ∈ p.support := (Classical.choose_spec ex).1 @@ -515,7 +513,7 @@ lemma patternToConfig_apply_of_mem -- put the rewrites together calc - patternToConfig (A := A) (G := G) p v (w * v) + mulPatternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := h1 _ = p.data ⟨w, hw_w⟩ := by -- push h2 through `p.data` @@ -535,26 +533,25 @@ Equivalently, `p.occursIn x g` iff on every translated site `w * g` (with `w ∈ the configuration `x` agrees with the translated pattern `patternToConfig p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ -@[to_additive addOccursAt_eq_cylinder +@[to_additive occursAt_eq_cylinder /-- Additive version: occurrences at `g` coincide with the corresponding cylinder. -/] -lemma occursAt_eq_cylinder - (p : Pattern A G) (g : G) : - { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (patternToConfig p g) := by - classical +lemma mulOccursAt_eq_cylinder + (p : mulPattern A G) (g : G) : + { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (mulPatternToConfig p g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ -- want: x (w*g) = patternToConfig p g (w*g) have hx : x (w * g) = p.data ⟨w, hw⟩ := H w hw - simpa [patternToConfig_apply_of_mem (p := p) (v := g) (w := w) hw] using hx + simpa [mulPatternToConfig_apply_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image - have hx : x (u * g) = patternToConfig p g (u * g) := + have hx : x (u * g) = mulPatternToConfig p g (u * g) := H (u * g) (Finset.mem_image_of_mem (· * g) hu) -- rewrite the RHS by the “apply_of_mem” lemma - simpa [patternToConfig_apply_of_mem (p := p) (v := g) (w := u) hu] using hx + simpa [mulPatternToConfig_apply_of_mem (p := p) (v := g) (w := u) hu] using hx end OccursAt @@ -566,63 +563,66 @@ variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [Dis [Inhabited A] [DecidableEq G] /-- Occurrence sets are open. -/ -@[to_additive addOccursAt_open] -lemma occursAt_open (p : Pattern A G) (g : G) : +@[to_additive occursAt_open] +lemma mulOccursAt_open (p : mulPattern A G) (g : G) : IsOpen { x | p.occursIn x g } := by - rw [occursAt_eq_cylinder]; exact isOpen_cylinder _ _ + rw [mulOccursAt_eq_cylinder]; exact isOpen_cylinder _ _ /-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). Since each occurrence set `{ x | p.occursIn x v }` is open (when `A` is discrete), its complement `{ x | ¬ p.occursIn x v }` is closed; `forbids F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/ -@[to_additive addForbids_closed] -lemma forbids_closed (F : Set (Pattern A G)) : - IsClosed (forbids F) := by - rw [forbids] +@[to_additive forbids_closed] +lemma mulForbids_closed (F : Set (mulPattern A G)) : + IsClosed (mulForbids F) := by + rw [mulForbids] have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.occursIn x v} - = ⋂ (p : Pattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.occursIn x v} := by + = ⋂ (p : mulPattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.occursIn x v} := by ext x; simp rw [this] refine isClosed_iInter ?_; intro p; refine isClosed_iInter ?_; intro _; refine isClosed_iInter ?_; intro v; have : {x | ¬p.occursIn x v} = {x | p.occursIn x v}ᶜ := by ext x; simp - simpa [this, isClosed_compl_iff] using occursAt_open p v + simpa [this, isClosed_compl_iff] using mulOccursAt_open p v /-- Occurrence sets are closed. -/ -@[to_additive addOccursAt_closed] -lemma occursAt_closed (p : Pattern A G) (g : G) : +@[to_additive occursAt_closed] +lemma mulOccursAt_closed (p : mulPattern A G) (g : G) : IsClosed { x | p.occursIn x g } := by - rw [occursAt_eq_cylinder]; exact isClosed_cylinder _ _ + rw [mulOccursAt_eq_cylinder]; exact isClosed_cylinder _ _ /-- The subshift defined by a family of forbidden patterns `F`. This is a standard way to construct subshifts: -`X_F F` consists of all configurations `x : G → A` in which no pattern +`subshift_from_forbidden F` consists of all configurations `x : G → A` in which no pattern `p ∈ F` occurs at any position. Formally: * the carrier is `forbids F` (configurations avoiding `F`), * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ -@[to_additive addX_F] -def X_F (F : Set (Pattern A G)) : Subshift A G := -{ carrier := forbids F, - isClosed := forbids_closed F, - shiftInvariant := forbids_shift_invariant F } +@[to_additive subshift_from_forbidden] +def mulSubshift_from_forbidden (F : Set (mulPattern A G)) : mulSubshift A G := +{ carrier := mulForbids F, + isClosed := mulForbids_closed F, + shiftInvariant := mulForbids_shift_invariant F } -attribute [inherit_doc SymbolicDynamics.FullShift.X_F] SymbolicDynamics.FullShift.addX_F +attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_from_forbidden] + SymbolicDynamics.FullShift.subshift_from_forbidden /-- A subshift of finite type (SFT) is a subshift defined by forbidding a *finite* family of patterns. -Formally, `SFT F` is `X_F F` where `F` is a `Finset (Pattern A G)`. -/ -@[to_additive addSFT] -def SFT (F : Finset (Pattern A G)) : Subshift A G := - X_F (F : Set (Pattern A G)) +Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a +`Finset (pattern A G)`. -/ +@[to_additive subshift_of_finite_type] +def mulSubshift_of_finite_type (F : Finset (mulPattern A G)) : mulSubshift A G := + mulSubshift_from_forbidden (F : Set (mulPattern A G)) -attribute [inherit_doc SymbolicDynamics.FullShift.SFT] SymbolicDynamics.FullShift.addSFT +attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_of_finite_type] + SymbolicDynamics.FullShift.subshift_of_finite_type end DefSubshiftByForbidden @@ -634,77 +634,76 @@ variable [TopologicalSpace A] variable [Monoid G] /-- The set of patterns with fixed support `U`. -/ -@[to_additive AddFixedSupport] -def FixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := - { p : Pattern A G // p.support = U } +@[to_additive fixedSupport] +def mulFixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := + { p : mulPattern A G // p.support = U } -attribute [inherit_doc SymbolicDynamics.FullShift.FixedSupport] - SymbolicDynamics.FullShift.AddFixedSupport +attribute [inherit_doc SymbolicDynamics.FullShift.mulFixedSupport] + SymbolicDynamics.FullShift.fixedSupport /-- An equivalence between patterns with fixed support and functions on that support. -Concretely, `FixedSupport A G U` is the subtype of patterns whose support is +Concretely, `fixedSupport A G U` is the subtype of patterns whose support is exactly `U`. Such a pattern is determined uniquely by its values on `U`, i.e. by a function `U → A`. This equivalence makes that identification precise: * `toFun` sends a fixed-support pattern to the function recording its values, * `invFun` rebuilds the pattern from a function on `U`. -This shows immediately that `FixedSupport A G U` is finite whenever `U` is. -/ -@[to_additive addEquivFun +This shows immediately that `fixedSupport A G U` is finite whenever `U` is. -/ +@[to_additive equivFun /-- Additive version: equivalence between fixed-support additive patterns and functions. -/] -def equivFun {U : Finset G} : - FixedSupport A G U ≃ (U → A) where +def mulEquivFun {U : Finset G} : + mulFixedSupport A G U ≃ (U → A) where toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl right_inv := by intro f; rfl -/-- `FixedSupport A G U` is a finite type: there are only finitely many patterns +/-- `fixedSupport A G U` is a finite type: there are only finitely many patterns with support exactly `U`. This follows from the equivalence with functions `U → A`. -/ -@[to_additive SymbolicDynamics.FullShift.addFintypeFixedSupport] noncomputable -instance fintypeFixedSupport {U : Finset G} : - Fintype (FixedSupport A G U) := by - classical exact Fintype.ofEquiv (U → A) (equivFun (A := A) (G := G) (U := U)).symm +@[to_additive SymbolicDynamics.FullShift.fintypeFixedSupport] noncomputable +instance mulFintypeFixedSupport {U : Finset G} : + Fintype (mulFixedSupport A G U) := by + classical exact Fintype.ofEquiv (U → A) (mulEquivFun (A := A) (G := G) (U := U)).symm /-- The language of a set of configurations `X` on a finite shape `U`. This is the set of all finite patterns obtained by restricting some configuration `x ∈ X` to `U`. -/ -@[to_additive addLanguageOn] -def languageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := - { p | ∃ x ∈ X, patternFromConfig x U = p } +@[to_additive languageOn] +def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (mulPattern A G) := + { p | ∃ x ∈ X, mulPatternFromConfig x U = p } -attribute [inherit_doc SymbolicDynamics.FullShift.languageOn] - SymbolicDynamics.FullShift.addLanguageOn +attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageOn] + SymbolicDynamics.FullShift.languageOn /-- The cardinality of the language of `X` on a finite set `U`. That is, the number of distinct patterns supported on `U` which appear in some configuration of `X`. Since `U` is finite, this is a finite number. -/ -@[to_additive addLanguageCardOn] -noncomputable def languageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by - classical +@[to_additive languageCardOn] +noncomputable def mulLanguageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by -- Image of a map into the finite type `FixedSupport A G U` - let f : {x : G → A // x ∈ X} → FixedSupport A G U := - fun x => ⟨patternFromConfig x.1 U, rfl⟩ + let f : {x : G → A // x ∈ X} → mulFixedSupport A G U := + fun x => ⟨mulPatternFromConfig x.1 U, rfl⟩ have hfin : (Set.range f).Finite := (Set.finite_univ : - (Set.univ : Set (FixedSupport A G U)).Finite) + (Set.univ : Set (mulFixedSupport A G U)).Finite) |>.subset (by intro y hy; simp) exact hfin.toFinset.card -attribute [inherit_doc SymbolicDynamics.FullShift.languageCardOn] - SymbolicDynamics.FullShift.addLanguageCardOn +attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageCardOn] + SymbolicDynamics.FullShift.languageCardOn /-- The number of patterns which appear in the configurations of the carrier of a subshift `Y` on a finite set `U`. -/ -@[to_additive addPatternCountOn] -noncomputable def patternCountOn (Y : Subshift A G) (U : Finset G) : ℕ := - languageCardOn (A := A) (G := G) Y.carrier U +@[to_additive patternCountOn] +noncomputable def mulPatternCountOn (Y : mulSubshift A G) (U : Finset G) : ℕ := + mulLanguageCardOn (A := A) (G := G) Y.carrier U -attribute [inherit_doc SymbolicDynamics.FullShift.patternCountOn] - SymbolicDynamics.FullShift.addPatternCountOn +attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternCountOn] + SymbolicDynamics.FullShift.patternCountOn end Language From 1783c221147ac18bdf2627157e3c9c8eee73ec46 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Wed, 8 Oct 2025 10:55:07 +0200 Subject: [PATCH 36/93] style(symbolic_dynamics): switch structure literals to ; minor cleanups --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 3cc9592ee31220..bb976f93f1b7db 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -278,10 +278,12 @@ It is the subshift whose underlying set is the set of all configurations `G → A`. -/ @[to_additive SymbolicDynamics.FullShift.fullShift] -def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : mulSubshift A G := - { carrier := Set.univ, - isClosed := isClosed_univ, - shiftInvariant := by intro _ _ _; simp } +def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : mulSubshift A G where + carrier := Set.univ + isClosed := isClosed_univ + shiftInvariant := by + intro _ _ _ + simp attribute [inherit_doc SymbolicDynamics.FullShift.mulFullShift] SymbolicDynamics.FullShift.fullShift @@ -323,11 +325,9 @@ In symbolic dynamics, dominos (two-cell patterns) are the simplest nontrivial building blocks: they describe local adjacency conditions between two sites of a configuration. -/ @[to_additive domino] -def mulDomino {A : Type*} - (i j : G) (ai aj : A) : mulPattern A G := by - refine - { support := ({i, j} : Finset G) - , data := fun ⟨z, hz⟩ => if z = i then ai else aj } +def mulDomino {A : Type*} (i j : G) (ai aj : A) : mulPattern A G where + support := ({i, j} : Finset G) + data := fun ⟨z, _hz⟩ => if z = i then ai else aj attribute [inherit_doc SymbolicDynamics.FullShift.mulDomino] SymbolicDynamics.FullShift.domino @@ -458,9 +458,9 @@ Formally: the support is `U`, and for each `i ∈ U` the pattern records the val This is the inverse construction to `patternToOriginConfig` (which extends a finite pattern to a configuration by filling with `default`). -/ @[to_additive patternFromConfig] -def mulPatternFromConfig (x : G → A) (U : Finset G) : mulPattern A G := - { support := U, - data := fun i => x i.1 } +def mulPatternFromConfig (x : G → A) (U : Finset G) : mulPattern A G where + support := U + data := fun i => x i.1 attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternFromConfig] SymbolicDynamics.FullShift.patternFromConfig @@ -474,7 +474,7 @@ the configuration `patternToConfig p v` takes the value prescribed by `p` at `w` This statement uses `[IsRightCancelMul G]` to identify the preimage of `w * v` under right-multiplication by `v`. -/ @[to_additive patternToConfig_apply_of_mem - /-- Additive version: on the translated support, `addPatternToConfig` agrees with the pattern. -/] + /-- Additive version: on the translated support, `patternToConfig` agrees with the pattern. -/] lemma mulPatternToConfig_apply_of_mem (p : mulPattern A G) (v w : G) (hw : w ∈ p.support) : mulPatternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by @@ -604,10 +604,10 @@ Formally: * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ @[to_additive subshift_from_forbidden] -def mulSubshift_from_forbidden (F : Set (mulPattern A G)) : mulSubshift A G := -{ carrier := mulForbids F, - isClosed := mulForbids_closed F, - shiftInvariant := mulForbids_shift_invariant F } +def mulSubshift_from_forbidden (F : Set (mulPattern A G)) : mulSubshift A G where + carrier := mulForbids F + isClosed := mulForbids_closed F + shiftInvariant := mulForbids_shift_invariant F attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_from_forbidden] SymbolicDynamics.FullShift.subshift_from_forbidden From 03f2257710ea403d8d1114b54e331b08e9b61f59 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Wed, 8 Oct 2025 11:11:32 +0200 Subject: [PATCH 37/93] docs(symbolic_dynamics): replace inherited docstrings with additive-specific ones --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 116 +++++++++++++------ 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index bb976f93f1b7db..9056adf4219835 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -122,14 +122,14 @@ variable {A G : Type*} [Monoid G] We call *configuration* an element of `G → A`. Given a configuration `x : G → A` and an element `g : G` of the group, the shifted configuration -`shift g x` is defined by `(shift g x) h = x (h + g)`. +`mulShift g x` is defined by `(mulShift g x) h = x (h * g)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value at position `h` in the shifted configuration is the value that was at position -`h + g` in the original one. +`h * g` in the original one. For example, if `G = ℤ` (with addition) and `A = {0,1}`, then -`shift 1 x` is the sequence obtained from `x` by shifting every symbol one +`mulShift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ @[to_additive shift /-- The **right-translation shift** on configurations, in additive notation. @@ -137,14 +137,14 @@ step to the left. -/ We call *configuration* an element of `G → A`. Given a configuration `x : G → A` and an element `g : G` of the multiplicative group, -the shifted configuration `mulShift g x` is defined by `(mulShift g x) h = x (h * g)`. +the shifted configuration `shift g x` is defined by `(shift g x) h = x (h + g)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value at position `h` in the shifted configuration is the value that was at position `h + g` in the original one. For example, if `G = ℤ` and `A = {0,1}`, then -`mulShift 1 x` is the sequence obtained from `x` by shifting every symbol one +`shift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) @@ -272,12 +272,17 @@ attribute [to_additive existing SymbolicDynamics.FullShift.subshift] SymbolicDynamics.FullShift.mulSubshift -/-- Example: the **full shift** on alphabet `A` over the (multiplicative) monoid `G`. +/-- Example: the **full shift** on alphabet `A` over the multiplicative monoid `G`. It is the subshift whose underlying set is the set of all configurations `G → A`. -/ -@[to_additive SymbolicDynamics.FullShift.fullShift] +@[to_additive SymbolicDynamics.FullShift.fullShift +/-- Example: the **full shift** on alphabet `A` over the additive monoid `G`. + +It is the subshift whose underlying set is the set of all configurations +`G → A`. +-/] def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : mulSubshift A G where carrier := Set.univ isClosed := isClosed_univ @@ -285,8 +290,6 @@ def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : mulSubshift A G where intro _ _ _ simp -attribute [inherit_doc SymbolicDynamics.FullShift.mulFullShift] SymbolicDynamics.FullShift.fullShift - /-- A *pattern* is a finite configuration in the full shift `A^G`. It consists of: @@ -342,19 +345,25 @@ variable [Monoid G] /-- `p.occursIn x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. +Formally: for every position `h` in the support of `p`, the value of the configuration +at `h * g` coincides with the value specified by `p` at `h`. + +Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), +then on the support of `p` you exactly recover the pattern `p`. This is the basic +notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ +@[to_additive +/-- `p.occursIn x g` means that the finite pattern `p` appears in the configuration `x` +at position `g`. + Formally: for every position `h` in the support of `p`, the value of the configuration at `h + g` coincides with the value specified by `p` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `shift g`), then on the support of `p` you exactly recover the pattern `p`. This is the basic -notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ -@[to_additive] +notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/] def mulPattern.occursIn (p : mulPattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ -attribute [inherit_doc SymbolicDynamics.FullShift.mulPattern.occursIn] - SymbolicDynamics.FullShift.pattern.occursIn - /-- `forbids F` is the set of configurations that avoid every pattern in `F`. Formally: `x ∈ forbids F` if and only if for every pattern `p ∈ F` and every @@ -371,10 +380,15 @@ attribute [inherit_doc SymbolicDynamics.FullShift.mulForbids] SymbolicDynamics.F /-- Shifting a configuration commutes with occurrences of a pattern. -Formally: a pattern `p` occurs in the shifted configuration `shift h x` at +Formally: a pattern `p` occurs in the shifted configuration `mulShift h x` at position `g` if and only if it occurs in the original configuration `x` at position `g + h`. -/ -@[to_additive occurs_shift] +@[to_additive occurs_shift +/-- Shifting a configuration commutes with occurrences of a pattern. + +Formally: a pattern `p` occurs in the shifted configuration `shift h x` at +position `g` if and only if it occurs in the original configuration `x` at +position `g + h`. -/] lemma mulOccurs_mulShift (p : mulPattern A G) (x : G → A) (g h : G) : p.occursIn (mulShift h x) g ↔ p.occursIn x (g * h) := by constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu @@ -382,9 +396,12 @@ lemma mulOccurs_mulShift (p : mulPattern A G) (x : G → A) (g h : G) : /-- Configurations that avoid a family `F` of patterns are stable under the shift. Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, -the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/ +the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every position. -/ @[to_additive forbids_shift_invariant - /-- Additive version: configurations avoiding `F` are stable under all additive shifts. -/] + /-- Configurations that avoid a family `F` of patterns are stable under the shift. + +Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, +the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] lemma mulForbids_shift_invariant (F : Set (mulPattern A G)) : ∀ h : G, ∀ x ∈ mulForbids (A := A) (G := G) F, mulShift h x ∈ mulForbids F := by intro h x hx p hp g @@ -399,7 +416,7 @@ section OccursAt variable {A : Type*} [Inhabited A] variable {G : Type*} --- We assume right-cancellation throughout this section for uniqueness of preimages under (_ * v). +-- We assume right-cancellation throughout this section for uniqueness of preimages under (_ + v). variable [Monoid G] [IsRightCancelMul G] [DecidableEq G] /-- Turn a finite pattern into a configuration, by extending it with @@ -428,10 +445,22 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume right-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `patternToConfig p v (w * v) = p.data ⟨w, _⟩`) +Uniqueness (and the usual equations such as `mulPatternToConfig p v (w * v) = p.data ⟨w, _⟩`) require a right-cancellation hypothesis and are proved in separate lemmas. -/ -@[to_additive patternToConfig] +@[to_additive patternToConfig +/-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into +a configuration. + +On input `h : G`, we proceed as follows: +* if `h` lies in the right-translate of the support, i.e. `h ∈ p.support.image (· + v)`, + choose (noncomputably) `w ∈ p.support` with `w + v = h` and return `p.data ⟨w, _⟩`; +* otherwise return `default`. + +This definition does not assume right-cancellation; it only *chooses* a preimage. +Uniqueness (and the usual equations such as `patternToConfig p v (w + v) = p.data ⟨w, _⟩`) +require a right-cancellation hypothesis and are proved in separate lemmas. +-/] noncomputable def mulPatternToConfig (p : mulPattern A G) (v : G) : G → A := fun h => if hmem : h ∈ p.support.image (· * v) then @@ -445,9 +474,16 @@ noncomputable def mulPatternToConfig (p : mulPattern A G) (v : G) : G → A := else default -attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternToConfig] - SymbolicDynamics.FullShift.patternToConfig +/-- Extract the finite pattern given by restricting a configuration `x : G → A` +to a finite subset `U : Finset G`. + +Formally: the support is `U`, and for each `i ∈ U` the pattern records the value +`x i`. In other words, `mulPatternFromConfig x U` is the partial configuration of +`x` visible on the coordinates in `U`. +This is the inverse construction to `mulPatternToOriginConfig` (which extends a +finite pattern to a configuration by filling with `default`). -/ +@[to_additive patternFromConfig /-- Extract the finite pattern given by restricting a configuration `x : G → A` to a finite subset `U : Finset G`. @@ -456,25 +492,26 @@ Formally: the support is `U`, and for each `i ∈ U` the pattern records the val `x` visible on the coordinates in `U`. This is the inverse construction to `patternToOriginConfig` (which extends a -finite pattern to a configuration by filling with `default`). -/ -@[to_additive patternFromConfig] +finite pattern to a configuration by filling with `default`). -/] def mulPatternFromConfig (x : G → A) (U : Finset G) : mulPattern A G where support := U data := fun i => x i.1 -attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternFromConfig] - SymbolicDynamics.FullShift.patternFromConfig - - -/-- On the translated support, `patternToConfig p v` agrees with `p` at the preimage. +/-- On the translated support, `mulPatternToConfig p v` agrees with `p` at the preimage. More precisely, if `w ∈ p.support`, then at the translated site `w * v`, -the configuration `patternToConfig p v` takes the value prescribed by `p` at `w`. +the configuration `mulPatternToConfig p v` takes the value prescribed by `p` at `w`. This statement uses `[IsRightCancelMul G]` to identify the preimage of `w * v` under right-multiplication by `v`. -/ @[to_additive patternToConfig_apply_of_mem - /-- Additive version: on the translated support, `patternToConfig` agrees with the pattern. -/] + /-- On the translated support, `patternToConfig p v` agrees with `p` at the preimage. + +More precisely, if `w ∈ p.support`, then at the translated site `w + v`, +the configuration `patternToConfig p v` takes the value prescribed by `p` at `w`. + +This statement uses `[IsRightCancelMul G]` to identify the preimage of `w + v` +under right-multiplication by `v`. -/] lemma mulPatternToConfig_apply_of_mem (p : mulPattern A G) (v w : G) (hw : w ∈ p.support) : mulPatternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by @@ -529,12 +566,21 @@ in which a pattern `p` occurs at position `g`. This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. -Equivalently, `p.occursIn x g` iff on every translated site `w * g` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `patternToConfig p g`. +Equivalently, `p.OccursIn x g` iff on every translated site `w * g` (with `w ∈ p.support`) +the configuration `x` agrees with the translated pattern `mulpatternToConfig p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ @[to_additive occursAt_eq_cylinder - /-- Additive version: occurrences at `g` coincide with the corresponding cylinder. -/] + /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations +in which a pattern `p` occurs at position `g`. + +This proves that it is exactly the cylinder corresponding to the +pattern obtained by translating `p` by `g`. + +Equivalently, `p.occursIn x g` iff on every translated site `w + g` (with `w ∈ p.support`) +the configuration `x` agrees with the translated pattern `patternToConfig p g`. + +(This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/] lemma mulOccursAt_eq_cylinder (p : mulPattern A G) (g : G) : { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (mulPatternToConfig p g) := by From 57cd7a291bc6b735cd15227eb79ae881a2fc1e35 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Wed, 8 Oct 2025 11:20:27 +0200 Subject: [PATCH 38/93] style(sd): prefer / --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 9056adf4219835..ac32db1f98f489 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -208,24 +208,12 @@ variable [TopologicalSpace A] [DiscreteTopology A] /-- Cylinders are open when `A` is discrete. -/ lemma isOpen_cylinder (U : Finset G) (x : G → A) : IsOpen (cylinder U x) := by - have hopen : ∀ i ∈ (↑U : Set G), IsOpen ({x i} : Set A) := by - intro i _; simp - have hpi : - IsOpen (Set.pi (s := (↑U : Set G)) - (t := fun i => ({x i} : Set A))) := - isOpen_set_pi (U.finite_toSet) hopen - simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi + simpa [cylinder_eq_set_pi U x] using isOpen_set_pi (U.finite_toSet) (by simp) /-- Cylinders are closed when `A` is discrete. -/ lemma isClosed_cylinder (U : Finset G) (x : G → A) : IsClosed (cylinder U x) := by - have hclosed : ∀ i ∈ (↑U : Set G), IsClosed ({x i} : Set A) := by - intro i _; simp - have hpi : - IsClosed (Set.pi (s := (↑U : Set G)) - (t := fun i => ({x i} : Set A))) := - isClosed_set_pi hclosed - simpa [cylinder_eq_set_pi (A := A) (G := G) U x] using hpi + simpa [cylinder_eq_set_pi U x] using isClosed_set_pi (by simp) end Cylinders @@ -612,7 +600,7 @@ variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [Dis @[to_additive occursAt_open] lemma mulOccursAt_open (p : mulPattern A G) (g : G) : IsOpen { x | p.occursIn x g } := by - rw [mulOccursAt_eq_cylinder]; exact isOpen_cylinder _ _ + simpa [mulOccursAt_eq_cylinder] using isOpen_cylinder _ _ /-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). @@ -637,7 +625,7 @@ lemma mulForbids_closed (F : Set (mulPattern A G)) : @[to_additive occursAt_closed] lemma mulOccursAt_closed (p : mulPattern A G) (g : G) : IsClosed { x | p.occursIn x g } := by - rw [mulOccursAt_eq_cylinder]; exact isClosed_cylinder _ _ + simpa [mulOccursAt_eq_cylinder] using isClosed_cylinder _ _ /-- The subshift defined by a family of forbidden patterns `F`. From 0ace1230c40a79dc92db9d7b79c7761dc368981e Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Wed, 15 Oct 2025 12:59:06 +0200 Subject: [PATCH 39/93] =?UTF-8?q?feat:=20ensure=20to=5Fadditive=20maps=20m?= =?UTF-8?q?ulShift=20=E2=86=92=20shift=20and=20MulSubshift=20=E2=86=92=20S?= =?UTF-8?q?ubshift?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 11 +++++------ Mathlib/Tactic/ToAdditive/GuessName.lean | 5 +++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index ac32db1f98f489..ccc0d4e8c8a7eb 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -131,8 +131,7 @@ at position `h` in the shifted configuration is the value that was at position For example, if `G = ℤ` (with addition) and `A = {0,1}`, then `mulShift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ -@[to_additive shift -/-- The **right-translation shift** on configurations, in additive notation. +@[to_additive /-- The **right-translation shift** on configurations, in additive notation. We call *configuration* an element of `G → A`. @@ -156,7 +155,7 @@ def mulShift (g : G) (x : G → A) : G → A := ext h; simp [mulShift] /-- Composition of right-translation shifts corresponds to multiplication in the group. -/ -@[to_additive shift_mul] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : +lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] @@ -256,7 +255,7 @@ structure mulSubshift : Type _ where end MulSubshiftDef -attribute [to_additive existing SymbolicDynamics.FullShift.subshift] +attribute [to_additive existing] SymbolicDynamics.FullShift.mulSubshift @@ -637,7 +636,7 @@ Formally: * the carrier is `forbids F` (configurations avoiding `F`), * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ -@[to_additive subshift_from_forbidden] +@[to_additive] def mulSubshift_from_forbidden (F : Set (mulPattern A G)) : mulSubshift A G where carrier := mulForbids F isClosed := mulForbids_closed F @@ -651,7 +650,7 @@ a *finite* family of patterns. Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a `Finset (pattern A G)`. -/ -@[to_additive subshift_of_finite_type] +@[to_additive] def mulSubshift_of_finite_type (F : Finset (mulPattern A G)) : mulSubshift A G := mulSubshift_from_forbidden (F : Set (mulPattern A G)) diff --git a/Mathlib/Tactic/ToAdditive/GuessName.lean b/Mathlib/Tactic/ToAdditive/GuessName.lean index a95e9323524183..97f7d12f74d341 100644 --- a/Mathlib/Tactic/ToAdditive/GuessName.lean +++ b/Mathlib/Tactic/ToAdditive/GuessName.lean @@ -236,9 +236,14 @@ def fixAbbreviation : List String → List String | "sub" :: "Neg" :: "Zero" :: "Add" :: "Monoid" :: s => "subNegZeroMonoid" :: fixAbbreviation s | "modular" :: "Character" :: s => "addModularCharacter" :: fixAbbreviation s | "Modular" :: "Character" :: s => "AddModularCharacter" :: fixAbbreviation s + | "Add" :: "Shift" :: s => "Shift" :: fixAbbreviation s + | "add" :: "Shift" :: s => "shift" :: fixAbbreviation s + | "Add" :: "Subshift" :: s => "Subshift" :: fixAbbreviation s + | "add" :: "Subshift" :: s => "subshift" :: fixAbbreviation s | x :: s => x :: fixAbbreviation s | [] => [] + /-- Autogenerate additive name. This runs in several steps: From 668f60e8bf675e982a62ec28988e0c6b37f95748 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:08:43 +0100 Subject: [PATCH 40/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index ccc0d4e8c8a7eb..cb704d62b47d6b 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -59,7 +59,7 @@ In multiplicative notation: ## Design choice: ambient vs. inner (subshift-relative) viewpoint All core notions (shift, cylinder, occurrence, language, …) are defined **in the -ambient full shift** `(G → A)`. A subshift is then a closed, invariant subset, +ambient full shift** `G → A`. A subshift is then a closed, invariant subset, bundled as `subshift A G`. Working inside a subshift is done by restriction. **Motivation.** From c526ac3bbdc8d17353af3e9876e1032531b78ee2 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:12:39 +0100 Subject: [PATCH 41/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index cb704d62b47d6b..76c7852b674581 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -128,8 +128,8 @@ Intuitively, this moves the whole configuration "in the direction of `g`": the v at position `h` in the shifted configuration is the value that was at position `h * g` in the original one. -For example, if `G = ℤ` (with addition) and `A = {0,1}`, then -`mulShift 1 x` is the sequence obtained from `x` by shifting every symbol one +For example, if `G = ℤ` (with addition) and `A = {0, 1}`, then +`shift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ @[to_additive /-- The **right-translation shift** on configurations, in additive notation. From da90c301ff81a850c1cce65eca176dec840dcb09 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:16:43 +0100 Subject: [PATCH 42/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 76c7852b674581..70b43ada8b28f5 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -142,7 +142,7 @@ Intuitively, this moves the whole configuration "in the direction of `g`": the v at position `h` in the shifted configuration is the value that was at position `h + g` in the original one. -For example, if `G = ℤ` and `A = {0,1}`, then +For example, if `G = ℤ` and `A = {0, 1}`, then `shift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := From a39a93f0e6cf4ffcd3c75732ecd8f4e6fce83cd6 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:17:57 +0100 Subject: [PATCH 43/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 70b43ada8b28f5..9126104332476e 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -135,7 +135,7 @@ step to the left. -/ We call *configuration* an element of `G → A`. -Given a configuration `x : G → A` and an element `g : G` of the multiplicative group, +Given a configuration `x : G → A` and an element `g : G` of the additive group, the shifted configuration `shift g x` is defined by `(shift g x) h = x (h + g)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value From c2fd6fedc69752acff9df416f1bf8880bebd2baf Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 30 Oct 2025 16:31:29 +0100 Subject: [PATCH 44/93] feat(SymbolicDynamics/Basic): refactor additve and multiplicative versions --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 108 ++++++++----------- 1 file changed, 47 insertions(+), 61 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 9126104332476e..1bc0427c6137a4 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -41,7 +41,7 @@ so that the theory works not only for groups but also for cancellative monoids. multiplicative notation `(mulShift g x) h = x (h * g)`. * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. * `pattern A G` — finite support together with values on that support. -* `pattern.occursIn p x g` — occurrence of `p` in `x` at translate `g`. +* `pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. * `forbids F` — configurations avoiding every pattern in `F`. * `subshift A G` — closed, shift-invariant subsets of the full shift. * `subshft_from_forbidden F` — the subshift defined by forbidding a family of patterns. @@ -182,8 +182,8 @@ reference configuration `x` on a fixed finite subset `U` of the index set `G`. The set `U` is called the *support* of the cylinder. Intuitively, cylinders specify the "letters" on finitely many coordinates, while -leaving all other coordinates free. For example, in the full shift `{0,1}^ℤ`, -the cylinder determined by `U = {0,1}` and `x 0 = 1, x 1 = 0` consists of all +leaving all other coordinates free. For example, in the full shift `{0, 1}^ℤ`, +the cylinder determined by `U = {0, 1}` and `x 0 = 1, x 1 = 0` consists of all bi-infinite sequences of `0`s and `1`s whose entries on positions `0` and `1` respectively are `1` and `0`. @@ -229,7 +229,7 @@ composed of: * `isClosed`: the set is topologically closed in `A^G`. * `shiftInvariant`: the set is invariant under all right-translation shifts `(shift g)`. -/ -structure subshift : Type _ where +structure Subshift where /-- The underlying set of configurations (additive group version). -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ @@ -244,7 +244,8 @@ variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [Monoid G] /-- Multiplicative version of the definition of subshift. -/ -structure mulSubshift : Type _ where +@[to_additive] +structure MulSubshift where /-- The underlying set of configurations. -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ @@ -255,10 +256,6 @@ structure mulSubshift : Type _ where end MulSubshiftDef -attribute [to_additive existing] - SymbolicDynamics.FullShift.mulSubshift - - /-- Example: the **full shift** on alphabet `A` over the multiplicative monoid `G`. It is the subshift whose underlying set is the set of all configurations @@ -270,7 +267,7 @@ It is the subshift whose underlying set is the set of all configurations It is the subshift whose underlying set is the set of all configurations `G → A`. -/] -def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : mulSubshift A G where +def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : MulSubshift A G where carrier := Set.univ isClosed := isClosed_univ shiftInvariant := by @@ -288,25 +285,15 @@ specifying finitely many values of a configuration in `G → A`. Patterns are the basic building blocks used to define subshifts via forbidden configurations. Note that each pattern corresponds to a cylinder, which is the set of configurations which agree with this pattern on its support. -/ -structure mulPattern (A : Type*) (G : Type*) [Monoid G] where +structure Pattern (A : Type*) (G : Type*) where /-- Finite support of the pattern. -/ support : Finset G /-- The value (symbol) at each point of the support. -/ data : support → A -/-- Additive version of `Pattern`. -/ -structure pattern (A : Type*) (G : Type*) [AddMonoid G] : Type _ where - /-- Finite support of the pattern (subset of `G`). -/ - support : Finset G - /-- The symbol at each point of the support. -/ - data : support → A - -attribute [to_additive existing SymbolicDynamics.FullShift.pattern] - SymbolicDynamics.FullShift.mulPattern - section Dominos -variable (G : Type*) [Monoid G] [DecidableEq G] +variable (G : Type*) [Monoid G] /-- A *domino* is a pattern supported on exactly two positions (sometimes also called cells) `{i, j}`, specifying the value `ai` at `i` and the value `aj` at `j`. @@ -314,12 +301,11 @@ also called cells) `{i, j}`, specifying the value `ai` at `i` and the value `aj` In symbolic dynamics, dominos (two-cell patterns) are the simplest nontrivial building blocks: they describe local adjacency conditions between two sites of a configuration. -/ -@[to_additive domino] -def mulDomino {A : Type*} (i j : G) (ai aj : A) : mulPattern A G where - support := ({i, j} : Finset G) - data := fun ⟨z, _hz⟩ => if z = i then ai else aj - -attribute [inherit_doc SymbolicDynamics.FullShift.mulDomino] SymbolicDynamics.FullShift.domino +def Domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by + classical + refine + { support := ({i, j} : Finset G) + data := fun ⟨z, _hz⟩ => if z = i then ai else aj } end Dominos @@ -329,7 +315,7 @@ variable {A : Type*} variable {G : Type*} variable [Monoid G] -/-- `p.occursIn x g` means that the finite pattern `p` appears in the configuration `x` +/-- `p.mulOccursInAt x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. Formally: for every position `h` in the support of `p`, the value of the configuration @@ -339,7 +325,7 @@ Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), then on the support of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ @[to_additive -/-- `p.occursIn x g` means that the finite pattern `p` appears in the configuration `x` +/-- `p.addOccursInAt x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. Formally: for every position `h` in the support of `p`, the value of the configuration @@ -348,7 +334,7 @@ at `h + g` coincides with the value specified by `p` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `shift g`), then on the support of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/] -def mulPattern.occursIn (p : mulPattern A G) (x : G → A) (g : G) : Prop := +def Pattern.mulOccursInAt (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ /-- `forbids F` is the set of configurations that avoid every pattern in `F`. @@ -360,8 +346,8 @@ Intuitively, `forbids F` is the shift space defined by declaring the finite set (or family) of patterns `F` to be *forbidden*. A configuration belongs to the subshift if and only it avoids all the forbidden patterns. -/ @[to_additive forbids] -def mulForbids (F : Set (mulPattern A G)) : Set (G → A) := - { x | ∀ p ∈ F, ∀ g : G, ¬ p.occursIn x g } +def mulForbids (F : Set (Pattern A G)) : Set (G → A) := + { x | ∀ p ∈ F, ∀ g : G, ¬ p.mulOccursInAt x g } attribute [inherit_doc SymbolicDynamics.FullShift.mulForbids] SymbolicDynamics.FullShift.forbids @@ -376,8 +362,8 @@ position `g + h`. -/ Formally: a pattern `p` occurs in the shifted configuration `shift h x` at position `g` if and only if it occurs in the original configuration `x` at position `g + h`. -/] -lemma mulOccurs_mulShift (p : mulPattern A G) (x : G → A) (g h : G) : - p.occursIn (mulShift h x) g ↔ p.occursIn x (g * h) := by +lemma mulOccurs_mulShift (p : Pattern A G) (x : G → A) (g h : G) : + p.mulOccursInAt (mulShift h x) g ↔ p.mulOccursInAt x (g * h) := by constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu /-- Configurations that avoid a family `F` of patterns are stable under the shift. @@ -389,7 +375,7 @@ the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every po Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] -lemma mulForbids_shift_invariant (F : Set (mulPattern A G)) : +lemma mulForbids_shift_invariant (F : Set (Pattern A G)) : ∀ h : G, ∀ x ∈ mulForbids (A := A) (G := G) F, mulShift h x ∈ mulForbids F := by intro h x hx p hp g specialize hx p hp (g * h) @@ -417,7 +403,7 @@ Formally: given a pattern `p` with finite support in `G`, we define a configurat This produces a canonical "completion" of the pattern to a configuration, filling all unspecified positions with `default`. -/ @[to_additive patternToOriginConfig] -def mulPatternToOriginConfig (p : mulPattern A G) : G → A := +def mulPatternToOriginConfig (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternToOriginConfig] @@ -448,7 +434,7 @@ This definition does not assume right-cancellation; it only *chooses* a preimage Uniqueness (and the usual equations such as `patternToConfig p v (w + v) = p.data ⟨w, _⟩`) require a right-cancellation hypothesis and are proved in separate lemmas. -/] -noncomputable def mulPatternToConfig (p : mulPattern A G) (v : G) : G → A := +noncomputable def mulPatternToConfig (p : Pattern A G) (v : G) : G → A := fun h => if hmem : h ∈ p.support.image (· * v) then -- package existence of a preimage under (_ * v) @@ -480,7 +466,7 @@ Formally: the support is `U`, and for each `i ∈ U` the pattern records the val This is the inverse construction to `patternToOriginConfig` (which extends a finite pattern to a configuration by filling with `default`). -/] -def mulPatternFromConfig (x : G → A) (U : Finset G) : mulPattern A G where +def mulPatternFromConfig (x : G → A) (U : Finset G) : Pattern A G where support := U data := fun i => x i.1 @@ -500,7 +486,7 @@ the configuration `patternToConfig p v` takes the value prescribed by `p` at `w` This statement uses `[IsRightCancelMul G]` to identify the preimage of `w + v` under right-multiplication by `v`. -/] lemma mulPatternToConfig_apply_of_mem - (p : mulPattern A G) (v w : G) (hw : w ∈ p.support) : + (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : mulPatternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by -- (w*v) is in the translated support have hmem : (w * v) ∈ p.support.image (· * v) := @@ -553,7 +539,7 @@ in which a pattern `p` occurs at position `g`. This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. -Equivalently, `p.OccursIn x g` iff on every translated site `w * g` (with `w ∈ p.support`) +Equivalently, `p.OccursInAt x g` iff on every translated site `w * g` (with `w ∈ p.support`) the configuration `x` agrees with the translated pattern `mulpatternToConfig p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ @@ -564,13 +550,13 @@ in which a pattern `p` occurs at position `g`. This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. -Equivalently, `p.occursIn x g` iff on every translated site `w + g` (with `w ∈ p.support`) +Equivalently, `p.occursInAt x g` iff on every translated site `w + g` (with `w ∈ p.support`) the configuration `x` agrees with the translated pattern `patternToConfig p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/] lemma mulOccursAt_eq_cylinder - (p : mulPattern A G) (g : G) : - { x | p.occursIn x g } = cylinder (p.support.image (· * g)) (mulPatternToConfig p g) := by + (p : Pattern A G) (g : G) : + { x | p.mulOccursInAt x g } = cylinder (p.support.image (· * g)) (mulPatternToConfig p g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu @@ -596,9 +582,9 @@ variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [Dis [Inhabited A] [DecidableEq G] /-- Occurrence sets are open. -/ -@[to_additive occursAt_open] -lemma mulOccursAt_open (p : mulPattern A G) (g : G) : - IsOpen { x | p.occursIn x g } := by +@[to_additive isOpen_occursInAt] +lemma isOpen_mulOccursInAt (p : Pattern A G) (g : G) : + IsOpen { x | p.mulOccursInAt x g } := by simpa [mulOccursAt_eq_cylinder] using isOpen_cylinder _ _ /-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). @@ -607,23 +593,23 @@ Since each occurrence set `{ x | p.occursIn x v }` is open (when `A` is discrete its complement `{ x | ¬ p.occursIn x v }` is closed; `forbids F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/ @[to_additive forbids_closed] -lemma mulForbids_closed (F : Set (mulPattern A G)) : +lemma mulForbids_closed (F : Set (Pattern A G)) : IsClosed (mulForbids F) := by rw [mulForbids] - have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.occursIn x v} - = ⋂ (p : mulPattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.occursIn x v} := by + have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.mulOccursInAt x v} + = ⋂ (p : Pattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.mulOccursInAt x v} := by ext x; simp rw [this] refine isClosed_iInter ?_; intro p; refine isClosed_iInter ?_; intro _; refine isClosed_iInter ?_; - intro v; have : {x | ¬p.occursIn x v} = {x | p.occursIn x v}ᶜ := by ext x; simp - simpa [this, isClosed_compl_iff] using mulOccursAt_open p v + intro v; have : {x | ¬p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by ext x; simp + simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt p v /-- Occurrence sets are closed. -/ -@[to_additive occursAt_closed] -lemma mulOccursAt_closed (p : mulPattern A G) (g : G) : - IsClosed { x | p.occursIn x g } := by +@[to_additive iClosed_occursInAt_add] +lemma iClosed_occursInAt (p : Pattern A G) (g : G) : + IsClosed { x | p.mulOccursInAt x g } := by simpa [mulOccursAt_eq_cylinder] using isClosed_cylinder _ _ /-- The subshift defined by a family of forbidden patterns `F`. @@ -637,7 +623,7 @@ Formally: * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ @[to_additive] -def mulSubshift_from_forbidden (F : Set (mulPattern A G)) : mulSubshift A G where +def mulSubshift_from_forbidden (F : Set (Pattern A G)) : MulSubshift A G where carrier := mulForbids F isClosed := mulForbids_closed F shiftInvariant := mulForbids_shift_invariant F @@ -651,8 +637,8 @@ a *finite* family of patterns. Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a `Finset (pattern A G)`. -/ @[to_additive] -def mulSubshift_of_finite_type (F : Finset (mulPattern A G)) : mulSubshift A G := - mulSubshift_from_forbidden (F : Set (mulPattern A G)) +def mulSubshift_of_finite_type (F : Finset (Pattern A G)) : MulSubshift A G := + mulSubshift_from_forbidden (F : Set (Pattern A G)) attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_of_finite_type] SymbolicDynamics.FullShift.subshift_of_finite_type @@ -669,7 +655,7 @@ variable [Monoid G] /-- The set of patterns with fixed support `U`. -/ @[to_additive fixedSupport] def mulFixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := - { p : mulPattern A G // p.support = U } + { p : Pattern A G // p.support = U } attribute [inherit_doc SymbolicDynamics.FullShift.mulFixedSupport] SymbolicDynamics.FullShift.fixedSupport @@ -705,7 +691,7 @@ instance mulFintypeFixedSupport {U : Finset G} : This is the set of all finite patterns obtained by restricting some configuration `x ∈ X` to `U`. -/ @[to_additive languageOn] -def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (mulPattern A G) := +def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, mulPatternFromConfig x U = p } attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageOn] @@ -732,7 +718,7 @@ attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageCardOn] /-- The number of patterns which appear in the configurations of the carrier of a subshift `Y` on a finite set `U`. -/ @[to_additive patternCountOn] -noncomputable def mulPatternCountOn (Y : mulSubshift A G) (U : Finset G) : ℕ := +noncomputable def mulPatternCountOn (Y : MulSubshift A G) (U : Finset G) : ℕ := mulLanguageCardOn (A := A) (G := G) Y.carrier U attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternCountOn] From d1c266c6f798cc5922a8d8e9ce57d1f205d32eee Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 30 Oct 2025 18:13:42 +0100 Subject: [PATCH 45/93] fix arguments unused --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 1bc0427c6137a4..5bb1f8e765e313 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -654,7 +654,7 @@ variable [Monoid G] /-- The set of patterns with fixed support `U`. -/ @[to_additive fixedSupport] -def mulFixedSupport (A : Type*) (G : Type*) [Monoid G] (U : Finset G) := +def mulFixedSupport (A : Type*) (G : Type*) (U : Finset G) := { p : Pattern A G // p.support = U } attribute [inherit_doc SymbolicDynamics.FullShift.mulFixedSupport] From 31a8f19b26e3a99686d6f922b20fdcb6496049b9 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 30 Oct 2025 20:41:50 +0100 Subject: [PATCH 46/93] linters --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 5bb1f8e765e313..d6a09c345f2d14 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -729,3 +729,5 @@ end Language end FullShift end SymbolicDynamics + +#lint only From 2215de3c9c8bdedfac5a9c8f39f0e9033f913032 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 30 Oct 2025 21:29:02 +0100 Subject: [PATCH 47/93] Sync toolchain+lockfile with upstream --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index bd000de3469b71..dbbc1fd3e09804 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "9e2a0dd176ab4bb5bc5f10e1f5de26af3e094cf4", + "rev": "43f271c492f815dbbb9a4b753d6ccc9d19b5609a", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", From 7e077f5204ae15b73a8ac85192e6be62383380b0 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Thu, 30 Oct 2025 21:33:21 +0100 Subject: [PATCH 48/93] typo --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index d6a09c345f2d14..f29eacdbb720bf 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -607,8 +607,8 @@ lemma mulForbids_closed (F : Set (Pattern A G)) : simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt p v /-- Occurrence sets are closed. -/ -@[to_additive iClosed_occursInAt_add] -lemma iClosed_occursInAt (p : Pattern A G) (g : G) : +@[to_additive isClosed_occursInAt_add] +lemma isClosed_occursInAt (p : Pattern A G) (g : G) : IsClosed { x | p.mulOccursInAt x g } := by simpa [mulOccursAt_eq_cylinder] using isClosed_cylinder _ _ @@ -729,5 +729,3 @@ end Language end FullShift end SymbolicDynamics - -#lint only From bb3f41c91da3083f0a285b44f1c90a59cf64b715 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Fri, 31 Oct 2025 12:41:26 +0100 Subject: [PATCH 49/93] linters --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index f29eacdbb720bf..2e5062c4e2074c 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -197,7 +197,7 @@ viewed as a subset of `G → A`. Equivalently, it is the preimage of that produc of singletons in `U → A` under the restriction map `(G → A) → (U → A)`. -/ lemma cylinder_eq_set_pi (U : Finset G) (x : G → A) : cylinder U x = Set.pi (↑U : Set G) (fun i => ({x i} : Set A)) := by - ext y; simp [cylinder, Set.pi, Finset.mem_coe] + ext y; simp [cylinder, Set.pi] lemma mem_cylinder {U : Finset G} {x y : G → A} : y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl From bc51bcfe676bba97de779711e160b6f2243eb58a Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Sun, 2 Nov 2025 11:30:39 +0100 Subject: [PATCH 50/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 2e5062c4e2074c..bca4314b3c6494 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -301,7 +301,7 @@ also called cells) `{i, j}`, specifying the value `ai` at `i` and the value `aj` In symbolic dynamics, dominos (two-cell patterns) are the simplest nontrivial building blocks: they describe local adjacency conditions between two sites of a configuration. -/ -def Domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by +def domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by classical refine { support := ({i, j} : Finset G) From 197ab537f9f7b91d929427cdcb1b880a3aac7085 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Sun, 2 Nov 2025 11:34:53 +0100 Subject: [PATCH 51/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index bca4314b3c6494..870cf72b2c457b 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -303,7 +303,7 @@ building blocks: they describe local adjacency conditions between two sites of a configuration. -/ def domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by classical - refine + exact { support := ({i, j} : Finset G) data := fun ⟨z, _hz⟩ => if z = i then ai else aj } From 1f1cc504039ec5791db3b10727f9f347fccf121c Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Sun, 2 Nov 2025 11:36:12 +0100 Subject: [PATCH 52/93] Update Mathlib/Tactic/ToAdditive/GuessName.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Tactic/ToAdditive/GuessName.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Mathlib/Tactic/ToAdditive/GuessName.lean b/Mathlib/Tactic/ToAdditive/GuessName.lean index 97f7d12f74d341..f6f1e4052c48eb 100644 --- a/Mathlib/Tactic/ToAdditive/GuessName.lean +++ b/Mathlib/Tactic/ToAdditive/GuessName.lean @@ -243,7 +243,6 @@ def fixAbbreviation : List String → List String | x :: s => x :: fixAbbreviation s | [] => [] - /-- Autogenerate additive name. This runs in several steps: From 07d70ed4b587c7888922d159ae6d9f00e92d3fe7 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Sun, 2 Nov 2025 12:18:04 +0100 Subject: [PATCH 53/93] style: apply review comments (dot notation, MapsTo, variable formatting) --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 93 +++++++++++--------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 870cf72b2c457b..7f999e393aaf6e 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -311,9 +311,7 @@ end Dominos section Forbids -variable {A : Type*} -variable {G : Type*} -variable [Monoid G] +variable {A G : Type*} [Monoid G] /-- `p.mulOccursInAt x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. @@ -324,8 +322,8 @@ at `h * g` coincides with the value specified by `p` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), then on the support of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ -@[to_additive -/-- `p.addOccursInAt x g` means that the finite pattern `p` appears in the configuration `x` +@[to_additive Pattern.occursInAt +/-- `p.occursInAt x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. Formally: for every position `h` in the support of `p`, the value of the configuration @@ -337,6 +335,15 @@ notion of "pattern occurrence" used to define subshifts via forbidden patterns. def Pattern.mulOccursInAt (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ +/-- `mulForbids F` is the set of configurations that avoid every pattern in `F`. + +Formally: `x ∈ mulForbids F` if and only if for every pattern `p ∈ F` and every +group element `g : G`, the pattern `p` does not occur in `x` at position `g`. + +Intuitively, `mulForbids F` is the shift space defined by declaring the finite set +(or family) of patterns `F` to be *forbidden*. A configuration belongs to the subshift if and only +it avoids all the forbidden patterns. -/ +@[to_additive forbids /-- `forbids F` is the set of configurations that avoid every pattern in `F`. Formally: `x ∈ forbids F` if and only if for every pattern `p ∈ F` and every @@ -344,18 +351,15 @@ group element `g : G`, the pattern `p` does not occur in `x` at position `g`. Intuitively, `forbids F` is the shift space defined by declaring the finite set (or family) of patterns `F` to be *forbidden*. A configuration belongs to the subshift if and only -it avoids all the forbidden patterns. -/ -@[to_additive forbids] +it avoids all the forbidden patterns. -/] def mulForbids (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.mulOccursInAt x g } -attribute [inherit_doc SymbolicDynamics.FullShift.mulForbids] SymbolicDynamics.FullShift.forbids - /-- Shifting a configuration commutes with occurrences of a pattern. Formally: a pattern `p` occurs in the shifted configuration `mulShift h x` at position `g` if and only if it occurs in the original configuration `x` at -position `g + h`. -/ +position `g * h`. -/ @[to_additive occurs_shift /-- Shifting a configuration commutes with occurrences of a pattern. @@ -375,11 +379,13 @@ the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every po Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] -lemma mulForbids_shift_invariant (F : Set (Pattern A G)) : - ∀ h : G, ∀ x ∈ mulForbids (A := A) (G := G) F, mulShift h x ∈ mulForbids F := by - intro h x hx p hp g +lemma mulForbids_shift_invariant + (F : Set (Pattern A G)) (h : G) : + Set.MapsTo (fun x => mulShift h x) + (mulForbids (A := A) (G := G) F) (mulForbids F) := by + -- unfold `MapsTo` + intro x hx p hp g specialize hx p hp (g * h) - -- contraposition contrapose! hx simpa [mulOccurs_mulShift] using hx @@ -388,26 +394,33 @@ end Forbids section OccursAt variable {A : Type*} [Inhabited A] -variable {G : Type*} --- We assume right-cancellation throughout this section for uniqueness of preimages under (_ + v). -variable [Monoid G] [IsRightCancelMul G] [DecidableEq G] +variable {G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] +-- We assume right-cancellation throughout this section for uniqueness of preimages under (_ * v) +-- or (_ + v). /-- Turn a finite pattern into a configuration, by extending it with the default symbol outside its support. Formally: given a pattern `p` with finite support in `G`, we define a configuration -`patternToOriginConfig p : G → A` by setting -* `patternToOriginConfig p i = p.data ⟨i, h⟩` if `i ∈ p.support`, -* `patternToOriginConfig p i = default` otherwise. +`Pattern.mulExtend p : G → A` by setting +* `Pattern.mulExtend p i = p.data ⟨i, h⟩` if `i ∈ p.support`, +* `Pattern.mulExtend p i = default` otherwise. This produces a canonical "completion" of the pattern to a configuration, filling all unspecified positions with `default`. -/ -@[to_additive patternToOriginConfig] -def mulPatternToOriginConfig (p : Pattern A G) : G → A := - fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default +@[to_additive Pattern.extendAtOrigin +/-- Turn a finite pattern into a configuration, by extending it with +the default symbol outside its support. + +Formally: given a pattern `p` with finite support in `G`, we define a configuration +`Pattern.extend p : G → A` by setting +* `Pattern.extend p i = p.data ⟨i, h⟩` if `i ∈ p.support`, +* `Pattern.extend p i = default` otherwise. -attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternToOriginConfig] - SymbolicDynamics.FullShift.patternToOriginConfig +This produces a canonical "completion" of the pattern to a configuration, +filling all unspecified positions with `default`. -/] +def Pattern.mulExtendAtOrigin (p : Pattern A G) : G → A := + fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. @@ -418,10 +431,10 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume right-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `mulPatternToConfig p v (w * v) = p.data ⟨w, _⟩`) +Uniqueness (and the usual equations such as `Pattern.mulExtend p v (w * v) = p.data ⟨w, _⟩`) require a right-cancellation hypothesis and are proved in separate lemmas. -/ -@[to_additive patternToConfig +@[to_additive Pattern.extend /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. @@ -431,10 +444,10 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume right-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `patternToConfig p v (w + v) = p.data ⟨w, _⟩`) +Uniqueness (and the usual equations such as `Pattern.extend p v (w + v) = p.data ⟨w, _⟩`) require a right-cancellation hypothesis and are proved in separate lemmas. -/] -noncomputable def mulPatternToConfig (p : Pattern A G) (v : G) : G → A := +noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := fun h => if hmem : h ∈ p.support.image (· * v) then -- package existence of a preimage under (_ * v) @@ -487,7 +500,7 @@ This statement uses `[IsRightCancelMul G]` to identify the preimage of `w + v` under right-multiplication by `v`. -/] lemma mulPatternToConfig_apply_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : - mulPatternToConfig (A := A) (G := G) p v (w * v) = p.data ⟨w, hw⟩ := by + p.mulExtend v (w * v) = p.data ⟨w, hw⟩ := by -- (w*v) is in the translated support have hmem : (w * v) ∈ p.support.image (· * v) := Finset.mem_image.mpr ⟨w, hw, rfl⟩ @@ -496,9 +509,9 @@ lemma mulPatternToConfig_apply_of_mem simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition have h1 : - mulPatternToConfig (A := A) (G := G) p v (w * v) + p.mulExtend v (w * v) = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := by - simp [mulPatternToConfig, hmem] + simp [Pattern.mulExtend, hmem] -- name the chosen witness and relate it to `w` by right-cancellation let w' := Classical.choose ex have hw' : w' ∈ p.support := (Classical.choose_spec ex).1 @@ -523,7 +536,7 @@ lemma mulPatternToConfig_apply_of_mem -- put the rewrites together calc - mulPatternToConfig (A := A) (G := G) p v (w * v) + p.mulExtend v (w * v) = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := h1 _ = p.data ⟨w, hw_w⟩ := by -- push h2 through `p.data` @@ -556,7 +569,7 @@ the configuration `x` agrees with the translated pattern `patternToConfig p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/] lemma mulOccursAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.mulOccursInAt x g } = cylinder (p.support.image (· * g)) (mulPatternToConfig p g) := by + { x | p.mulOccursInAt x g } = cylinder (p.support.image (· * g)) (p.mulExtend g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu @@ -567,7 +580,7 @@ lemma mulOccursAt_eq_cylinder · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image - have hx : x (u * g) = mulPatternToConfig p g (u * g) := + have hx : x (u * g) = p.mulExtend g (u * g) := H (u * g) (Finset.mem_image_of_mem (· * g) hu) -- rewrite the RHS by the “apply_of_mem” lemma simpa [mulPatternToConfig_apply_of_mem (p := p) (v := g) (w := u) hu] using hx @@ -578,8 +591,8 @@ end OccursAt section DefSubshiftByForbidden -variable {A G : Type*} [Monoid G] [IsRightCancelMul G] [TopologicalSpace A] [DiscreteTopology A] - [Inhabited A] [DecidableEq G] +variable {A : Type*} [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] +variable {G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] /-- Occurrence sets are open. -/ @[to_additive isOpen_occursInAt] @@ -647,10 +660,8 @@ end DefSubshiftByForbidden section Language -variable {A : Type*} [Fintype A] -variable {G : Type*} -variable [TopologicalSpace A] -variable [Monoid G] +variable {A : Type*} [Fintype A] [TopologicalSpace A] +variable {G : Type*} [Monoid G] /-- The set of patterns with fixed support `U`. -/ @[to_additive fixedSupport] From 881811d597f541e529bc6583eb976e11cd7b215b Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Sun, 2 Nov 2025 12:25:42 +0100 Subject: [PATCH 54/93] =?UTF-8?q?refactor:=20rename=20mulPatternFromConfig?= =?UTF-8?q?=20=E2=86=92=20Pattern.mulFromConfig=20for=20consistency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 35 +++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 7f999e393aaf6e..c9b230b6182d51 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -460,45 +460,46 @@ noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := else default +namespace Pattern /-- Extract the finite pattern given by restricting a configuration `x : G → A` to a finite subset `U : Finset G`. Formally: the support is `U`, and for each `i ∈ U` the pattern records the value -`x i`. In other words, `mulPatternFromConfig x U` is the partial configuration of +`x i`. In other words, `Pattern.mulFromConfig x U` is the partial configuration of `x` visible on the coordinates in `U`. -This is the inverse construction to `mulPatternToOriginConfig` (which extends a +This is the inverse construction to `Pattern.mulFromConfig` (which extends a finite pattern to a configuration by filling with `default`). -/ -@[to_additive patternFromConfig +@[to_additive fromConfig /-- Extract the finite pattern given by restricting a configuration `x : G → A` to a finite subset `U : Finset G`. Formally: the support is `U`, and for each `i ∈ U` the pattern records the value -`x i`. In other words, `patternFromConfig x U` is the partial configuration of +`x i`. In other words, `Pattern.fromConfig x U` is the partial configuration of `x` visible on the coordinates in `U`. -This is the inverse construction to `patternToOriginConfig` (which extends a +This is the inverse construction to `Pattern.fromConfig` (which extends a finite pattern to a configuration by filling with `default`). -/] -def mulPatternFromConfig (x : G → A) (U : Finset G) : Pattern A G where +def mulFromConfig (x : G → A) (U : Finset G) : Pattern A G where support := U data := fun i => x i.1 -/-- On the translated support, `mulPatternToConfig p v` agrees with `p` at the preimage. +/-- On the translated support, `Pattern.mulExtend p v` agrees with `p` at the preimage. More precisely, if `w ∈ p.support`, then at the translated site `w * v`, -the configuration `mulPatternToConfig p v` takes the value prescribed by `p` at `w`. +the configuration `Pattern.extend p v` takes the value prescribed by `p` at `w`. This statement uses `[IsRightCancelMul G]` to identify the preimage of `w * v` under right-multiplication by `v`. -/ -@[to_additive patternToConfig_apply_of_mem - /-- On the translated support, `patternToConfig p v` agrees with `p` at the preimage. +@[to_additive toConfig_apply_of_mem + /-- On the translated support, `Pattern.extend p v` agrees with `p` at the preimage. More precisely, if `w ∈ p.support`, then at the translated site `w + v`, -the configuration `patternToConfig p v` takes the value prescribed by `p` at `w`. +the configuration `Pattern.extend p v` takes the value prescribed by `p` at `w`. This statement uses `[IsRightCancelMul G]` to identify the preimage of `w + v` under right-multiplication by `v`. -/] -lemma mulPatternToConfig_apply_of_mem +lemma mulToConfig_apply_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : p.mulExtend v (w * v) = p.data ⟨w, hw⟩ := by -- (w*v) is in the translated support @@ -546,6 +547,8 @@ lemma mulPatternToConfig_apply_of_mem -- push h3 through `p.data` simp [h3] +end Pattern + /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations in which a pattern `p` occurs at position `g`. @@ -576,14 +579,14 @@ lemma mulOccursAt_eq_cylinder rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ -- want: x (w*g) = patternToConfig p g (w*g) have hx : x (w * g) = p.data ⟨w, hw⟩ := H w hw - simpa [mulPatternToConfig_apply_of_mem (p := p) (v := g) (w := w) hw] using hx + simpa [Pattern.mulToConfig_apply_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image have hx : x (u * g) = p.mulExtend g (u * g) := H (u * g) (Finset.mem_image_of_mem (· * g) hu) -- rewrite the RHS by the “apply_of_mem” lemma - simpa [mulPatternToConfig_apply_of_mem (p := p) (v := g) (w := u) hu] using hx + simpa [Pattern.mulToConfig_apply_of_mem (p := p) (v := g) (w := u) hu] using hx end OccursAt @@ -703,7 +706,7 @@ This is the set of all finite patterns obtained by restricting some configuratio `x ∈ X` to `U`. -/ @[to_additive languageOn] def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := - { p | ∃ x ∈ X, mulPatternFromConfig x U = p } + { p | ∃ x ∈ X, Pattern.mulFromConfig x U = p } attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageOn] SymbolicDynamics.FullShift.languageOn @@ -717,7 +720,7 @@ in some configuration of `X`. Since `U` is finite, this is a finite number. -/ noncomputable def mulLanguageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by -- Image of a map into the finite type `FixedSupport A G U` let f : {x : G → A // x ∈ X} → mulFixedSupport A G U := - fun x => ⟨mulPatternFromConfig x.1 U, rfl⟩ + fun x => ⟨Pattern.mulFromConfig x.1 U, rfl⟩ have hfin : (Set.range f).Finite := (Set.finite_univ : (Set.univ : Set (mulFixedSupport A G U)).Finite) |>.subset (by intro y hy; simp) From ac5eb78b5764573f0ed5858d0eb785d71fd0595e Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 4 Nov 2025 15:48:55 +0100 Subject: [PATCH 55/93] symbolic dynamics: clean up to_additive, namespacing, and docs --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 332 +++++++++---------- 1 file changed, 162 insertions(+), 170 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index c9b230b6182d51..301a4415aa5472 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -8,8 +8,13 @@ import Mathlib.Topology.Constructions /-! # Symbolic dynamics on cancellative monoids -This file develops a minimal API for symbolic dynamics over an arbitrary -**right-cancellative monoid** `G` (`[Monoid G] [IsRightCancelMul G]`). +This file develops a minimal API for symbolic dynamics over a +**right-cancellative monoid** `G`—formally, a structure carrying `[Monoid G]` +and `[IsRightCancelMul G]` (which becomes `[AddMonoid G]` and +`[IsRightCancelAdd G]` in the additive form). Throughout the documentation we use the +**additive** notations, which are the most common in symbolic dynamics, although +all the notions introduced are defined in the multiplicative notations and adapted +to the additive notation. Given a finite alphabet `A`, the ambient configuration space is the set of functions `G → A`, endowed with the product topology. We define the @@ -28,41 +33,35 @@ specialization. ## Why cancellativity? Some constructions, such as translating a finite pattern to occur at a point `v`, -require solving equations of the form `w * v = h`. For this to have a unique +require solving equations of the form `w + v = h`. For this to have a unique solution `w` given `h` and `v`, we assume **right-cancellation**: -if `a * v = b * v` then `a = b`. This allows us to define -`patternToConfig` (which extends a pattern into a configuration +if `a + v = b + v` then `a = b`. This allows us to define +`Pattern.extend` (which extends a pattern into a configuration using the default value of `A`) without using inverses, so that the theory works not only for groups but also for cancellative monoids. ## Main definitions -* `mulShift g x` — right translation: in additive notation `(shift v x) u = x (u + v)`; - multiplicative notation `(mulShift g x) h = x (h * g)`. +* `shift g x` — right translation: in additive notation `(shift v x) u = x (u + v)` (using the +**right** action of `G` on configurations). * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. -* `pattern A G` — finite support together with values on that support. -* `pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. -* `forbids F` — configurations avoiding every pattern in `F`. -* `subshift A G` — closed, shift-invariant subsets of the full shift. -* `subshft_from_forbidden F` — the subshift defined by forbidding a family of patterns. +* `Pattern A G` — finite support together with values on that support. +* `Pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. +* `forbidden F` — configurations avoiding every pattern in `F`. +* `Subshift A G` — closed, shift-invariant subsets of the full shift. +* `subshift_from_forbidden F` — the subshift defined by forbidding a family of patterns. * `subshift_of_finite_type F` — a subshift of finite type defined by a finite set of forbidden patterns. * `languageOn X U` — the set of patterns of shape `U` obtained by restricting some `x ∈ X`. -## Conventions - -We use a **right** action of `G` on configurations: -`(shift v x) u = x (u + v)`. -In multiplicative notation: -`(mulShift g x) h = x (h * g)`. - ## Design choice: ambient vs. inner (subshift-relative) viewpoint All core notions (shift, cylinder, occurrence, language, …) are defined **in the ambient full shift** `G → A`. A subshift is then a closed, invariant subset, -bundled as `subshift A G`. Working inside a subshift is done by restriction. +bundled as `Subshift A G`. Working inside a subshift is done by restriction. **Motivation.** + If cylinders and shifts were defined only *inside* a subshift, local ergonomics would improve but global operations would become awkward. For instance, to prove that for finite shape `U`: @@ -75,7 +74,8 @@ definitions these set-theoretic identities are tautological. Thus the file develops the theory ambiently, and subshifts reuse it by restriction. **Working inside a subshift.** -For `Y : subshift A G`, cylinders and occurrence sets *inside `Y`* are simply + +For `Y : Subshift A G`, cylinders and occurrence sets *inside `Y`* are simply preimages of the ambient ones under the inclusion `Y → (G → A)`. For example: `{ y : Y | ∀ i ∈ U, (y : G → A) i = (x : G → A) i } = (Subtype.val) ⁻¹' (cylinder U (x : G → A)).` @@ -83,6 +83,7 @@ preimages of the ambient ones under the inclusion `Y → (G → A)`. For example Shift invariance guarantees that the ambient shift restricts to `Y`. **Ergonomics.** + Thin wrappers (e.g. `Subshift.shift`, `Subshift.cylinder`, `Subshift.languageOn`) may be added for convenience. They introduce no new theory and unfold to the ambient definitions. @@ -121,7 +122,7 @@ variable {A G : Type*} [Monoid G] We call *configuration* an element of `G → A`. -Given a configuration `x : G → A` and an element `g : G` of the group, the shifted configuration +Given a configuration `x : G → A` and an element `g : G` of the monoid, the shifted configuration `mulShift g x` is defined by `(mulShift g x) h = x (h * g)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value @@ -135,7 +136,7 @@ step to the left. -/ We call *configuration* an element of `G → A`. -Given a configuration `x : G → A` and an element `g : G` of the additive group, +Given a configuration `x : G → A` and an element `g : G` of the additive monoid, the shifted configuration `shift g x` is defined by `(shift g x) h = x (h + g)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value @@ -148,13 +149,13 @@ step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) -@[to_additive] lemma mulShift_apply (g h : G) (x : G → A) : +@[to_additive] lemma mulShift_apply (g : G) (x : G → A) (h : G) : mulShift g x h = x (h * g) := rfl @[to_additive] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] -/-- Composition of right-translation shifts corresponds to multiplication in the group. -/ +/-- Composition of right-translation shifts corresponds to multiplication in the monoid `G`. -/ lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] @@ -230,7 +231,7 @@ composed of: * `shiftInvariant`: the set is invariant under all right-translation shifts `(shift g)`. -/ structure Subshift where - /-- The underlying set of configurations (additive group version). -/ + /-- The underlying set of configurations (additive monoid version). -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier @@ -243,8 +244,13 @@ section MulSubshiftDef variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [Monoid G] -/-- Multiplicative version of the definition of subshift. -/ -@[to_additive] +/-- A *subshift* on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is +composed of: +* `carrier`: the underlying set of allowed configurations. +* `isClosed`: the set is topologically closed in `A^G`. +* `shiftInvariant`: the set is invariant under all right-translation shifts + `(shift g)`. -/ +@[to_additive existing] structure MulSubshift where /-- The underlying set of configurations. -/ carrier : Set (G → A) @@ -291,9 +297,10 @@ structure Pattern (A : Type*) (G : Type*) where /-- The value (symbol) at each point of the support. -/ data : support → A +namespace Pattern section Dominos -variable (G : Type*) [Monoid G] +variable (G : Type*) /-- A *domino* is a pattern supported on exactly two positions (sometimes also called cells) `{i, j}`, specifying the value `ai` at `i` and the value `aj` at `j`. @@ -308,8 +315,9 @@ def domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by data := fun ⟨z, _hz⟩ => if z = i then ai else aj } end Dominos +end Pattern -section Forbids +section Forbidden variable {A G : Type*} [Monoid G] @@ -335,61 +343,27 @@ notion of "pattern occurrence" used to define subshifts via forbidden patterns. def Pattern.mulOccursInAt (p : Pattern A G) (x : G → A) (g : G) : Prop := ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ -/-- `mulForbids F` is the set of configurations that avoid every pattern in `F`. +/-- `mulForbidden F` is the set of configurations that avoid every pattern in `F`. -Formally: `x ∈ mulForbids F` if and only if for every pattern `p ∈ F` and every -group element `g : G`, the pattern `p` does not occur in `x` at position `g`. +Formally: `x ∈ mulForbidden F` if and only if for every pattern `p ∈ F` and every +monoid element `g : G`, the pattern `p` does not occur in `x` at position `g`. -Intuitively, `mulForbids F` is the shift space defined by declaring the finite set +Intuitively, `mulForbidden F` is the shift space defined by declaring the finite set (or family) of patterns `F` to be *forbidden*. A configuration belongs to the subshift if and only it avoids all the forbidden patterns. -/ -@[to_additive forbids -/-- `forbids F` is the set of configurations that avoid every pattern in `F`. +@[to_additive forbidden +/-- `forbidden F` is the set of configurations that avoid every pattern in `F`. -Formally: `x ∈ forbids F` if and only if for every pattern `p ∈ F` and every -group element `g : G`, the pattern `p` does not occur in `x` at position `g`. +Formally: `x ∈ forbidden F` if and only if for every pattern `p ∈ F` and every +monoid element `g : G`, the pattern `p` does not occur in `x` at position `g`. -Intuitively, `forbids F` is the shift space defined by declaring the finite set +Intuitively, `forbidden F` is the shift space defined by declaring the finite set (or family) of patterns `F` to be *forbidden*. A configuration belongs to the subshift if and only it avoids all the forbidden patterns. -/] -def mulForbids (F : Set (Pattern A G)) : Set (G → A) := +def mulForbidden (F : Set (Pattern A G)) : Set (G → A) := { x | ∀ p ∈ F, ∀ g : G, ¬ p.mulOccursInAt x g } -/-- Shifting a configuration commutes with occurrences of a pattern. - -Formally: a pattern `p` occurs in the shifted configuration `mulShift h x` at -position `g` if and only if it occurs in the original configuration `x` at -position `g * h`. -/ -@[to_additive occurs_shift -/-- Shifting a configuration commutes with occurrences of a pattern. - -Formally: a pattern `p` occurs in the shifted configuration `shift h x` at -position `g` if and only if it occurs in the original configuration `x` at -position `g + h`. -/] -lemma mulOccurs_mulShift (p : Pattern A G) (x : G → A) (g h : G) : - p.mulOccursInAt (mulShift h x) g ↔ p.mulOccursInAt x (g * h) := by - constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu - -/-- Configurations that avoid a family `F` of patterns are stable under the shift. - -Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, -the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every position. -/ -@[to_additive forbids_shift_invariant - /-- Configurations that avoid a family `F` of patterns are stable under the shift. - -Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, -the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] -lemma mulForbids_shift_invariant - (F : Set (Pattern A G)) (h : G) : - Set.MapsTo (fun x => mulShift h x) - (mulForbids (A := A) (G := G) F) (mulForbids F) := by - -- unfold `MapsTo` - intro x hx p hp g - specialize hx p hp (g * h) - contrapose! hx - simpa [mulOccurs_mulShift] using hx - -end Forbids +end Forbidden section OccursAt @@ -402,24 +376,13 @@ variable {G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] the default symbol outside its support. Formally: given a pattern `p` with finite support in `G`, we define a configuration -`Pattern.mulExtend p : G → A` by setting -* `Pattern.mulExtend p i = p.data ⟨i, h⟩` if `i ∈ p.support`, -* `Pattern.mulExtend p i = default` otherwise. +`Pattern.extendAtOrigin p : G → A` by setting +* `Pattern.extendAtOrigin p i = p.data ⟨i, h⟩` if `i ∈ p.support`, +* `Pattern.extendAtOrigin p i = default` otherwise. This produces a canonical "completion" of the pattern to a configuration, filling all unspecified positions with `default`. -/ -@[to_additive Pattern.extendAtOrigin -/-- Turn a finite pattern into a configuration, by extending it with -the default symbol outside its support. - -Formally: given a pattern `p` with finite support in `G`, we define a configuration -`Pattern.extend p : G → A` by setting -* `Pattern.extend p i = p.data ⟨i, h⟩` if `i ∈ p.support`, -* `Pattern.extend p i = default` otherwise. - -This produces a canonical "completion" of the pattern to a configuration, -filling all unspecified positions with `default`. -/] -def Pattern.mulExtendAtOrigin (p : Pattern A G) : G → A := +def Pattern.extendAtOrigin (p : Pattern A G) : G → A := fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into @@ -464,42 +427,32 @@ namespace Pattern /-- Extract the finite pattern given by restricting a configuration `x : G → A` to a finite subset `U : Finset G`. -Formally: the support is `U`, and for each `i ∈ U` the pattern records the value -`x i`. In other words, `Pattern.mulFromConfig x U` is the partial configuration of -`x` visible on the coordinates in `U`. - -This is the inverse construction to `Pattern.mulFromConfig` (which extends a -finite pattern to a configuration by filling with `default`). -/ -@[to_additive fromConfig -/-- Extract the finite pattern given by restricting a configuration `x : G → A` -to a finite subset `U : Finset G`. - Formally: the support is `U`, and for each `i ∈ U` the pattern records the value `x i`. In other words, `Pattern.fromConfig x U` is the partial configuration of `x` visible on the coordinates in `U`. -This is the inverse construction to `Pattern.fromConfig` (which extends a -finite pattern to a configuration by filling with `default`). -/] -def mulFromConfig (x : G → A) (U : Finset G) : Pattern A G where +This is the inverse construction to `Pattern.extendAtOrigin` (which extends a +finite pattern to a configuration by filling with `default`). -/ +def fromConfig (x : G → A) (U : Finset G) : Pattern A G where support := U data := fun i => x i.1 -/-- On the translated support, `Pattern.mulExtend p v` agrees with `p` at the preimage. +/-- On the translated support, `p.mulExtend v` agrees with `p` at the preimage. More precisely, if `w ∈ p.support`, then at the translated site `w * v`, -the configuration `Pattern.extend p v` takes the value prescribed by `p` at `w`. +the configuration `p.mulExtend v` takes the value prescribed by `p` at `w`. -This statement uses `[IsRightCancelMul G]` to identify the preimage of `w * v` +This uses `[IsRightCancelMul G]` to identify the unique preimage of `w * v` under right-multiplication by `v`. -/ -@[to_additive toConfig_apply_of_mem - /-- On the translated support, `Pattern.extend p v` agrees with `p` at the preimage. +@[to_additive extend_apply_add_right_of_mem + /-- On the translated support, `p.extend v` agrees with `p` at the preimage. -More precisely, if `w ∈ p.support`, then at the translated site `w + v`, -the configuration `Pattern.extend p v` takes the value prescribed by `p` at `w`. + More precisely, if `w ∈ p.support`, then at the translated site `w + v`, + the configuration `p.extend v` takes the value prescribed by `p` at `w`. -This statement uses `[IsRightCancelMul G]` to identify the preimage of `w + v` -under right-multiplication by `v`. -/] -lemma mulToConfig_apply_of_mem + This uses `[IsRightCancelAdd G]` to identify the unique preimage of `w + v` + under right-translation by `v`. -/] +lemma mulExtend_apply_mul_right_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : p.mulExtend v (w * v) = p.data ⟨w, hw⟩ := by -- (w*v) is in the translated support @@ -528,13 +481,10 @@ lemma mulToConfig_apply_of_mem -- goal: Classical.choose ex = w -- we have h_eq : w' = w and w' := Classical.choose ex simpa [w'] using h_eq -- <-- use `using h_eq`, only unfold `[w']` - -- then replace the proof component (same carrier w) - have h3 : - (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := by + have h3 : (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := by apply Subtype.ext rfl - -- put the rewrites together calc p.mulExtend v (w * v) @@ -547,6 +497,69 @@ lemma mulToConfig_apply_of_mem -- push h3 through `p.data` simp [h3] + +/-- Shifting a configuration commutes with occurrences of a pattern. + +Formally: a pattern `p` occurs in the shifted configuration `mulShift h x` at +position `g` if and only if it occurs in the original configuration `x` at +position `g * h`. -/ +@[to_additive occursInAt_shift +/-- Shifting a configuration commutes with occurrences of a pattern. + +Formally: a pattern `p` occurs in the shifted configuration `shift h x` at +position `g` if and only if it occurs in the original configuration `x` at +position `g + h`. -/] +lemma mulOccursInAt_mulShift {A G : Type*} [Monoid G] (p : Pattern A G) (x : G → A) (g h : G) : + p.mulOccursInAt (mulShift h x) g ↔ p.mulOccursInAt x (g * h) := by + constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu + +/-- Configurations that avoid a family `F` of patterns are stable under the shift. + +Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, +the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every position. -/ +@[to_additive forbidden_shift_invariant + /-- Configurations that avoid a family `F` of patterns are stable under the shift. + +Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, +the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] +lemma mulForbidden_shift_invariant {A G : Type*} [Monoid G] + (F : Set (Pattern A G)) (h : G) : + Set.MapsTo (fun x => mulShift h x) + (mulForbidden (A := A) (G := G) F) (mulForbidden F) := by + -- unfold `MapsTo` + intro x hx p hp g + specialize hx p hp (g * h) + contrapose! hx + simpa [mulOccursInAt_mulShift] using hx + + +/-- The set of patterns with fixed support `U`. -/ +@[to_additive fixedSupport] +def mulFixedSupport (A : Type*) (G : Type*) (U : Finset G) := + { p : Pattern A G // p.support = U } + +attribute [inherit_doc SymbolicDynamics.FullShift.Pattern.mulFixedSupport] + SymbolicDynamics.FullShift.Pattern.fixedSupport + +/-- An equivalence between patterns with fixed support and functions on that support. + +Concretely, `fixedSupport A G U` is the subtype of patterns whose support is +exactly `U`. Such a pattern is determined uniquely by its values on `U`, +i.e. by a function `U → A`. This equivalence makes that identification precise: + +* `toFun` sends a fixed-support pattern to the function recording its values, +* `invFun` rebuilds the pattern from a function on `U`. + +This shows immediately that `fixedSupport A G U` is finite whenever `U` is. -/ +@[to_additive equivFun + /-- Additive version: equivalence between fixed-support additive patterns and functions. -/] +def mulEquivFun {U : Finset G} : + mulFixedSupport A G U ≃ (U → A) where + toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ + invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ + left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl + right_inv := by intro f; rfl + end Pattern /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations @@ -555,11 +568,11 @@ in which a pattern `p` occurs at position `g`. This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. -Equivalently, `p.OccursInAt x g` iff on every translated site `w * g` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `mulpatternToConfig p g`. +Equivalently, `p.occursInAt x g` iff on every translated site `w * g` (with `w ∈ p.support`) +the configuration `x` agrees with the translated pattern `Pattern.mulExtend p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ -@[to_additive occursAt_eq_cylinder +@[to_additive occursInAt_eq_cylinder /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations in which a pattern `p` occurs at position `g`. @@ -567,26 +580,26 @@ This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. Equivalently, `p.occursInAt x g` iff on every translated site `w + g` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `patternToConfig p g`. +the configuration `x` agrees with the translated pattern `Pattern.extend p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/] -lemma mulOccursAt_eq_cylinder +lemma mulOccursInAt_eq_cylinder (p : Pattern A G) (g : G) : { x | p.mulOccursInAt x g } = cylinder (p.support.image (· * g)) (p.mulExtend g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ - -- want: x (w*g) = patternToConfig p g (w*g) + -- want: x (w*g) = Pattern.mulExtend p g (w*g) have hx : x (w * g) = p.data ⟨w, hw⟩ := H w hw - simpa [Pattern.mulToConfig_apply_of_mem (p := p) (v := g) (w := w) hw] using hx + simpa [Pattern.mulExtend_apply_mul_right_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image have hx : x (u * g) = p.mulExtend g (u * g) := H (u * g) (Finset.mem_image_of_mem (· * g) hu) -- rewrite the RHS by the “apply_of_mem” lemma - simpa [Pattern.mulToConfig_apply_of_mem (p := p) (v := g) (w := u) hu] using hx + simpa [Pattern.mulExtend_apply_mul_right_of_mem (p := p) (v := g) (w := u) hu] using hx end OccursAt @@ -601,17 +614,17 @@ variable {G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] @[to_additive isOpen_occursInAt] lemma isOpen_mulOccursInAt (p : Pattern A G) (g : G) : IsOpen { x | p.mulOccursInAt x g } := by - simpa [mulOccursAt_eq_cylinder] using isOpen_cylinder _ _ + simpa [mulOccursInAt_eq_cylinder] using isOpen_cylinder _ _ /-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). Since each occurrence set `{ x | p.occursIn x v }` is open (when `A` is discrete), -its complement `{ x | ¬ p.occursIn x v }` is closed; `forbids F` is the intersection +its complement `{ x | ¬ p.occursIn x v }` is closed; `forbidden F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/ -@[to_additive forbids_closed] -lemma mulForbids_closed (F : Set (Pattern A G)) : - IsClosed (mulForbids F) := by - rw [mulForbids] +@[to_additive forbidden_closed] +lemma mulForbidden_closed (F : Set (Pattern A G)) : + IsClosed (mulForbidden F) := by + rw [mulForbidden] have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.mulOccursInAt x v} = ⋂ (p : Pattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.mulOccursInAt x v} := by ext x; simp @@ -623,10 +636,10 @@ lemma mulForbids_closed (F : Set (Pattern A G)) : simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt p v /-- Occurrence sets are closed. -/ -@[to_additive isClosed_occursInAt_add] -lemma isClosed_occursInAt (p : Pattern A G) (g : G) : +@[to_additive isClosed_occursInAt] +lemma isClosed_mulOccursInAt (p : Pattern A G) (g : G) : IsClosed { x | p.mulOccursInAt x g } := by - simpa [mulOccursAt_eq_cylinder] using isClosed_cylinder _ _ + simpa [mulOccursInAt_eq_cylinder] using isClosed_cylinder _ _ /-- The subshift defined by a family of forbidden patterns `F`. @@ -635,14 +648,14 @@ This is a standard way to construct subshifts: `p ∈ F` occurs at any position. Formally: -* the carrier is `forbids F` (configurations avoiding `F`), +* the carrier is `forbidden F` (configurations avoiding `F`), * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ @[to_additive] def mulSubshift_from_forbidden (F : Set (Pattern A G)) : MulSubshift A G where - carrier := mulForbids F - isClosed := mulForbids_closed F - shiftInvariant := mulForbids_shift_invariant F + carrier := mulForbidden F + isClosed := mulForbidden_closed F + shiftInvariant := Pattern.mulForbidden_shift_invariant F attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_from_forbidden] SymbolicDynamics.FullShift.subshift_from_forbidden @@ -666,39 +679,13 @@ section Language variable {A : Type*} [Fintype A] [TopologicalSpace A] variable {G : Type*} [Monoid G] -/-- The set of patterns with fixed support `U`. -/ -@[to_additive fixedSupport] -def mulFixedSupport (A : Type*) (G : Type*) (U : Finset G) := - { p : Pattern A G // p.support = U } - -attribute [inherit_doc SymbolicDynamics.FullShift.mulFixedSupport] - SymbolicDynamics.FullShift.fixedSupport - -/-- An equivalence between patterns with fixed support and functions on that support. - -Concretely, `fixedSupport A G U` is the subtype of patterns whose support is -exactly `U`. Such a pattern is determined uniquely by its values on `U`, -i.e. by a function `U → A`. This equivalence makes that identification precise: - -* `toFun` sends a fixed-support pattern to the function recording its values, -* `invFun` rebuilds the pattern from a function on `U`. - -This shows immediately that `fixedSupport A G U` is finite whenever `U` is. -/ -@[to_additive equivFun - /-- Additive version: equivalence between fixed-support additive patterns and functions. -/] -def mulEquivFun {U : Finset G} : - mulFixedSupport A G U ≃ (U → A) where - toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ - invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ - left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl - right_inv := by intro f; rfl /-- `fixedSupport A G U` is a finite type: there are only finitely many patterns with support exactly `U`. This follows from the equivalence with functions `U → A`. -/ @[to_additive SymbolicDynamics.FullShift.fintypeFixedSupport] noncomputable instance mulFintypeFixedSupport {U : Finset G} : - Fintype (mulFixedSupport A G U) := by - classical exact Fintype.ofEquiv (U → A) (mulEquivFun (A := A) (G := G) (U := U)).symm + Fintype (Pattern.mulFixedSupport A G U) := by + classical exact Fintype.ofEquiv (U → A) (Pattern.mulEquivFun (A := A) (G := G) (U := U)).symm /-- The language of a set of configurations `X` on a finite shape `U`. @@ -706,11 +693,16 @@ This is the set of all finite patterns obtained by restricting some configuratio `x ∈ X` to `U`. -/ @[to_additive languageOn] def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := - { p | ∃ x ∈ X, Pattern.mulFromConfig x U = p } + { p | ∃ x ∈ X, Pattern.fromConfig x U = p } attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageOn] SymbolicDynamics.FullShift.languageOn +/-- The language of a subshift `Y` on a finite shape `U`. -/ +@[to_additive] +def MulSubshift.languageOn {A G} [Fintype A] [TopologicalSpace A] [Monoid G] + (Y : MulSubshift A G) (U : Finset G) : Set (Pattern A G) := + SymbolicDynamics.FullShift.mulLanguageOn (A:=A) (G:=G) Y.carrier U /-- The cardinality of the language of `X` on a finite set `U`. @@ -719,10 +711,10 @@ in some configuration of `X`. Since `U` is finite, this is a finite number. -/ @[to_additive languageCardOn] noncomputable def mulLanguageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by -- Image of a map into the finite type `FixedSupport A G U` - let f : {x : G → A // x ∈ X} → mulFixedSupport A G U := - fun x => ⟨Pattern.mulFromConfig x.1 U, rfl⟩ + let f : {x : G → A // x ∈ X} → Pattern.mulFixedSupport A G U := + fun x => ⟨Pattern.fromConfig x.1 U, rfl⟩ have hfin : (Set.range f).Finite := (Set.finite_univ : - (Set.univ : Set (mulFixedSupport A G U)).Finite) + (Set.univ : Set (Pattern.mulFixedSupport A G U)).Finite) |>.subset (by intro y hy; simp) exact hfin.toFinset.card From 62a958232c9395e2ab8062ffb9214f2d6cd66859 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 4 Nov 2025 16:02:12 +0100 Subject: [PATCH 56/93] additional docstring fixes --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 301a4415aa5472..d18bc143fcc2f8 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -249,8 +249,14 @@ composed of: * `carrier`: the underlying set of allowed configurations. * `isClosed`: the set is topologically closed in `A^G`. * `shiftInvariant`: the set is invariant under all right-translation shifts - `(shift g)`. -/ -@[to_additive existing] + `(mulShift g)`. -/ +@[to_additive existing +/-- A *subshift* on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is +composed of: +* `carrier`: the underlying set of allowed configurations. +* `isClosed`: the set is topologically closed in `A^G`. +* `shiftInvariant`: the set is invariant under all right-translation shifts + `(shift g)`. -/] structure MulSubshift where /-- The underlying set of configurations. -/ carrier : Set (G → A) @@ -483,8 +489,7 @@ lemma mulExtend_apply_mul_right_of_mem simpa [w'] using h_eq -- <-- use `using h_eq`, only unfold `[w']` -- then replace the proof component (same carrier w) have h3 : (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := by - apply Subtype.ext - rfl + apply Subtype.ext; rfl -- put the rewrites together calc p.mulExtend v (w * v) @@ -568,7 +573,7 @@ in which a pattern `p` occurs at position `g`. This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. -Equivalently, `p.occursInAt x g` iff on every translated site `w * g` (with `w ∈ p.support`) +Equivalently, `p.mulOccursInAt x g` iff on every translated site `w * g` (with `w ∈ p.support`) the configuration `x` agrees with the translated pattern `Pattern.mulExtend p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ @@ -618,10 +623,15 @@ lemma isOpen_mulOccursInAt (p : Pattern A G) (g : G) : /-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). -Since each occurrence set `{ x | p.occursIn x v }` is open (when `A` is discrete), -its complement `{ x | ¬ p.occursIn x v }` is closed; `forbidden F` is the intersection +Since each occurrence set `{ x | p.mulOccursInAt x v }` is open (when `A` is discrete), +its complement `{ x | ¬ p.mulOccursInAt x v }` is closed; `forbidden F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/ -@[to_additive forbidden_closed] +@[to_additive forbidden_closed +/-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). + +Since each occurrence set `{ x | p.occursInAt x v }` is open (when `A` is discrete), +its complement `{ x | ¬ p.occursInAt x v }` is closed; `forbidden F` is the intersection +of these closed sets over `p ∈ F` and `v ∈ G`. -/] lemma mulForbidden_closed (F : Set (Pattern A G)) : IsClosed (mulForbidden F) := by rw [mulForbidden] @@ -664,7 +674,7 @@ attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_from_forbidden] a *finite* family of patterns. Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a -`Finset (pattern A G)`. -/ +`Finset (Pattern A G)`. -/ @[to_additive] def mulSubshift_of_finite_type (F : Finset (Pattern A G)) : MulSubshift A G := mulSubshift_from_forbidden (F : Set (Pattern A G)) From 5fb1b4e116e9c7308006234cff0ca64ce4925513 Mon Sep 17 00:00:00 2001 From: Silvere Gangloff Date: Tue, 4 Nov 2025 17:21:29 +0100 Subject: [PATCH 57/93] linters --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index d18bc143fcc2f8..a2402f57bc4f65 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -709,8 +709,8 @@ attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageOn] SymbolicDynamics.FullShift.languageOn /-- The language of a subshift `Y` on a finite shape `U`. -/ -@[to_additive] -def MulSubshift.languageOn {A G} [Fintype A] [TopologicalSpace A] [Monoid G] +@[to_additive /-- The language of a subshift `Y` on a finite shape `U`. -/] +def MulSubshift.languageOn {A G} [TopologicalSpace A] [Monoid G] (Y : MulSubshift A G) (U : Finset G) : Set (Pattern A G) := SymbolicDynamics.FullShift.mulLanguageOn (A:=A) (G:=G) Y.carrier U From d5442d4bf4d9a6b15866dbf89d62385b01bb623c Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 20 Nov 2025 09:25:52 +0100 Subject: [PATCH 58/93] Update import_all files --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index 740188104f3884..a4a6221f36eec4 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3927,6 +3927,7 @@ public import Mathlib.Dynamics.Newton public import Mathlib.Dynamics.OmegaLimit public import Mathlib.Dynamics.PeriodicPts.Defs public import Mathlib.Dynamics.PeriodicPts.Lemmas +public import Mathlib.Dynamics.SymbolicDynamics.Basic public import Mathlib.Dynamics.TopologicalEntropy.CoverEntropy public import Mathlib.Dynamics.TopologicalEntropy.DynamicalEntourage public import Mathlib.Dynamics.TopologicalEntropy.NetEntropy From c3d485dcf6372c50b692f7d910246a6fdbcac52d Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 20 Nov 2025 10:14:53 +0100 Subject: [PATCH 59/93] Renaming additive versions following removal of GuessName.lean --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index a2402f57bc4f65..f663fc8fb91ddd 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -132,7 +132,7 @@ at position `h` in the shifted configuration is the value that was at position For example, if `G = ℤ` (with addition) and `A = {0, 1}`, then `shift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ -@[to_additive /-- The **right-translation shift** on configurations, in additive notation. +@[to_additive shift /-- The **right-translation shift** on configurations, in additive notation. We call *configuration* an element of `G → A`. @@ -250,7 +250,7 @@ composed of: * `isClosed`: the set is topologically closed in `A^G`. * `shiftInvariant`: the set is invariant under all right-translation shifts `(mulShift g)`. -/ -@[to_additive existing +@[to_additive existing Subshift /-- A *subshift* on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is composed of: * `carrier`: the underlying set of allowed configurations. @@ -661,7 +661,7 @@ Formally: * the carrier is `forbidden F` (configurations avoiding `F`), * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ -@[to_additive] +@[to_additive subshift_from_forbidden] def mulSubshift_from_forbidden (F : Set (Pattern A G)) : MulSubshift A G where carrier := mulForbidden F isClosed := mulForbidden_closed F @@ -675,7 +675,7 @@ a *finite* family of patterns. Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a `Finset (Pattern A G)`. -/ -@[to_additive] +@[to_additive subshift_of_finite_type] def mulSubshift_of_finite_type (F : Finset (Pattern A G)) : MulSubshift A G := mulSubshift_from_forbidden (F : Set (Pattern A G)) From 31af4c46022aa5aadda66a0ec2af7d4e5da65845 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Mon, 24 Nov 2025 15:02:04 +0100 Subject: [PATCH 60/93] new format for imports --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 5 ++++- lake-manifest.json | 14 +++++++------- lean-toolchain | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index f663fc8fb91ddd..91bdd7eb1a2f9c 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -3,7 +3,9 @@ Copyright (c) 2025 Silvère Gangloff. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Silvère Gangloff -/ -import Mathlib.Topology.Constructions +module + +public import Mathlib.Topology.Constructions /-! # Symbolic dynamics on cancellative monoids @@ -104,6 +106,7 @@ between the two viewpoints, since both may naturally want to reuse names like manipulations and `Function.update`). -/ +@[expose] public section noncomputable section open Set Topology diff --git a/lake-manifest.json b/lake-manifest.json index 42c0727f95c9e7..3398aa0ce83656 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,7 +5,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "ec4a54b5308c1f46b4b52a9c62fb67d193aa0972", + "rev": "74835c84b38e4070b8240a063c6417c767e551ae", "name": "plausible", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -25,7 +25,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "7ff87023a8e1b358d2d01c1bc56b040a60609577", + "rev": "6e3bb4bf31f731ab28891fe229eb347ec7d5dad3", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -45,7 +45,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "c00943d5ff28c6dc623dbc24f8d659a9d3a3d29a", + "rev": "9c70abdd9215b76019340fad65138e2e8d21843e", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -55,7 +55,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "1be06a278c3c249edafb722bfb278622024929d8", + "rev": "a31845b5557fd5e47d52b9e2977a1b0eff3c38c3", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "c278d4e94fe43bc38da4966795dc0c72538e68ab", + "rev": "afe9302d9243cee630b0be95322b38b90342ddbf", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -75,10 +75,10 @@ "type": "git", "subDir": null, "scope": "leanprover", - "rev": "00fad25fa9bedece1f1f988ab9c180dfe3d535b3", + "rev": "7e1ced9e049a4fab2508980ec4877ca9c46dffc9", "name": "Cli", "manifestFile": "lake-manifest.json", - "inputRev": "v4.26.0-rc1", + "inputRev": "v4.26.0-rc2", "inherited": true, "configFile": "lakefile.toml"}], "name": "mathlib", diff --git a/lean-toolchain b/lean-toolchain index bd7c1fde3f7ee4..7035713c5522d1 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.26.0-rc1 +leanprover/lean4:v4.26.0-rc2 \ No newline at end of file From 899dcb116f2fde365d388bcfbdfe4dc7b53adee6 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Mon, 24 Nov 2025 16:35:40 +0100 Subject: [PATCH 61/93] naming convention corrected for MulFixedSupport --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 91bdd7eb1a2f9c..3fc89d2bc4a384 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -152,21 +152,21 @@ step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) -@[to_additive] lemma mulShift_apply (g : G) (x : G → A) (h : G) : +@[to_additive shift_apply] lemma mulShift_apply (g : G) (x : G → A) (h : G) : mulShift g x h = x (h * g) := rfl -@[to_additive] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by +@[to_additive shift_zero] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] /-- Composition of right-translation shifts corresponds to multiplication in the monoid `G`. -/ -lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : +@[to_additive shift_add] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] variable [TopologicalSpace A] /-- The right-translation shift is continuous. -/ -@[to_additive (attr := fun_prop)] lemma continuous_mulShift (g : G) : +@[to_additive (attr := fun_prop) continuous_shift] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) g) := by -- coordinate projections are continuous; composition preserves continuity unfold mulShift @@ -540,14 +540,13 @@ lemma mulForbidden_shift_invariant {A G : Type*} [Monoid G] contrapose! hx simpa [mulOccursInAt_mulShift] using hx - /-- The set of patterns with fixed support `U`. -/ -@[to_additive fixedSupport] -def mulFixedSupport (A : Type*) (G : Type*) (U : Finset G) := +@[to_additive FixedSupport] +def MulFixedSupport (A : Type*) (G : Type*) (U : Finset G) := { p : Pattern A G // p.support = U } -attribute [inherit_doc SymbolicDynamics.FullShift.Pattern.mulFixedSupport] - SymbolicDynamics.FullShift.Pattern.fixedSupport +attribute [inherit_doc SymbolicDynamics.FullShift.Pattern.MulFixedSupport] + SymbolicDynamics.FullShift.Pattern.FixedSupport /-- An equivalence between patterns with fixed support and functions on that support. @@ -562,7 +561,7 @@ This shows immediately that `fixedSupport A G U` is finite whenever `U` is. -/ @[to_additive equivFun /-- Additive version: equivalence between fixed-support additive patterns and functions. -/] def mulEquivFun {U : Finset G} : - mulFixedSupport A G U ≃ (U → A) where + MulFixedSupport A G U ≃ (U → A) where toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl @@ -697,7 +696,7 @@ variable {G : Type*} [Monoid G] with support exactly `U`. This follows from the equivalence with functions `U → A`. -/ @[to_additive SymbolicDynamics.FullShift.fintypeFixedSupport] noncomputable instance mulFintypeFixedSupport {U : Finset G} : - Fintype (Pattern.mulFixedSupport A G U) := by + Fintype (Pattern.MulFixedSupport A G U) := by classical exact Fintype.ofEquiv (U → A) (Pattern.mulEquivFun (A := A) (G := G) (U := U)).symm /-- The language of a set of configurations `X` on a finite shape `U`. @@ -724,10 +723,10 @@ in some configuration of `X`. Since `U` is finite, this is a finite number. -/ @[to_additive languageCardOn] noncomputable def mulLanguageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by -- Image of a map into the finite type `FixedSupport A G U` - let f : {x : G → A // x ∈ X} → Pattern.mulFixedSupport A G U := + let f : {x : G → A // x ∈ X} → Pattern.MulFixedSupport A G U := fun x => ⟨Pattern.fromConfig x.1 U, rfl⟩ have hfin : (Set.range f).Finite := (Set.finite_univ : - (Set.univ : Set (Pattern.mulFixedSupport A G U)).Finite) + (Set.univ : Set (Pattern.MulFixedSupport A G U)).Finite) |>.subset (by intro y hy; simp) exact hfin.toFinset.card From 1aacca8b89db2ea523838015411e8c69a008bd98 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 27 Nov 2025 16:48:09 +0100 Subject: [PATCH 62/93] Replace hypothesis [DiscreteTopology A] with [T1Space A] for closed cylinders --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 3fc89d2bc4a384..8e0554413778a3 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -6,6 +6,7 @@ Authors: Silvère Gangloff module public import Mathlib.Topology.Constructions +public import Mathlib.Topology.Separation.Basic /-! # Symbolic dynamics on cancellative monoids @@ -206,15 +207,15 @@ lemma cylinder_eq_set_pi (U : Finset G) (x : G → A) : lemma mem_cylinder {U : Finset G} {x y : G → A} : y ∈ cylinder U x ↔ ∀ i ∈ U, y i = x i := Iff.rfl -variable [TopologicalSpace A] [DiscreteTopology A] +variable [TopologicalSpace A] /-- Cylinders are open when `A` is discrete. -/ -lemma isOpen_cylinder (U : Finset G) (x : G → A) : +lemma isOpen_cylinder [DiscreteTopology A] (U : Finset G) (x : G → A) : IsOpen (cylinder U x) := by simpa [cylinder_eq_set_pi U x] using isOpen_set_pi (U.finite_toSet) (by simp) /-- Cylinders are closed when `A` is discrete. -/ -lemma isClosed_cylinder (U : Finset G) (x : G → A) : +lemma isClosed_cylinder [T1Space A] (U : Finset G) (x : G → A) : IsClosed (cylinder U x) := by simpa [cylinder_eq_set_pi U x] using isClosed_set_pi (by simp) @@ -614,12 +615,12 @@ end OccursAt section DefSubshiftByForbidden -variable {A : Type*} [TopologicalSpace A] [DiscreteTopology A] [Inhabited A] +variable {A : Type*} [TopologicalSpace A] [Inhabited A] variable {G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] /-- Occurrence sets are open. -/ @[to_additive isOpen_occursInAt] -lemma isOpen_mulOccursInAt (p : Pattern A G) (g : G) : +lemma isOpen_mulOccursInAt [DiscreteTopology A] (p : Pattern A G) (g : G) : IsOpen { x | p.mulOccursInAt x g } := by simpa [mulOccursInAt_eq_cylinder] using isOpen_cylinder _ _ @@ -634,7 +635,7 @@ of these closed sets over `p ∈ F` and `v ∈ G`. -/ Since each occurrence set `{ x | p.occursInAt x v }` is open (when `A` is discrete), its complement `{ x | ¬ p.occursInAt x v }` is closed; `forbidden F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/] -lemma mulForbidden_closed (F : Set (Pattern A G)) : +lemma mulForbidden_closed [DiscreteTopology A] (F : Set (Pattern A G)) : IsClosed (mulForbidden F) := by rw [mulForbidden] have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.mulOccursInAt x v} @@ -649,7 +650,7 @@ lemma mulForbidden_closed (F : Set (Pattern A G)) : /-- Occurrence sets are closed. -/ @[to_additive isClosed_occursInAt] -lemma isClosed_mulOccursInAt (p : Pattern A G) (g : G) : +lemma isClosed_mulOccursInAt [T1Space A] (p : Pattern A G) (g : G) : IsClosed { x | p.mulOccursInAt x g } := by simpa [mulOccursInAt_eq_cylinder] using isClosed_cylinder _ _ @@ -664,7 +665,7 @@ Formally: * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ @[to_additive subshift_from_forbidden] -def mulSubshift_from_forbidden (F : Set (Pattern A G)) : MulSubshift A G where +def mulSubshift_from_forbidden [DiscreteTopology A] (F : Set (Pattern A G)) : MulSubshift A G where carrier := mulForbidden F isClosed := mulForbidden_closed F shiftInvariant := Pattern.mulForbidden_shift_invariant F @@ -678,7 +679,7 @@ a *finite* family of patterns. Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a `Finset (Pattern A G)`. -/ @[to_additive subshift_of_finite_type] -def mulSubshift_of_finite_type (F : Finset (Pattern A G)) : MulSubshift A G := +def mulSubshift_of_finite_type [DiscreteTopology A] (F : Finset (Pattern A G)) : MulSubshift A G := mulSubshift_from_forbidden (F : Set (Pattern A G)) attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_of_finite_type] From f196d49d64d3bb9415a20feb59eca9fa4b92d614 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 27 Nov 2025 16:50:47 +0100 Subject: [PATCH 63/93] T1 Space in comment for cylinder closed lemma --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 8e0554413778a3..7bf13119c4413a 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -214,7 +214,7 @@ lemma isOpen_cylinder [DiscreteTopology A] (U : Finset G) (x : G → A) : IsOpen (cylinder U x) := by simpa [cylinder_eq_set_pi U x] using isOpen_set_pi (U.finite_toSet) (by simp) -/-- Cylinders are closed when `A` is discrete. -/ +/-- Cylinders are closed when `A` is a T1 Space. -/ lemma isClosed_cylinder [T1Space A] (U : Finset G) (x : G → A) : IsClosed (cylinder U x) := by simpa [cylinder_eq_set_pi U x] using isClosed_set_pi (by simp) From 4a169a86874b0a2814e0623cfa0096db13273768 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Tue, 9 Dec 2025 09:41:47 +0100 Subject: [PATCH 64/93] adding to_additive abbreviations back --- Mathlib/Tactic/Translate/ToAdditive.lean | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Mathlib/Tactic/Translate/ToAdditive.lean b/Mathlib/Tactic/Translate/ToAdditive.lean index 5630a997fc9486..5c641a808394ba 100644 --- a/Mathlib/Tactic/Translate/ToAdditive.lean +++ b/Mathlib/Tactic/Translate/ToAdditive.lean @@ -369,7 +369,11 @@ def abbreviationDict : Std.HashMap String String := .ofList [ ("function_addCommute", "Function_commute"), ("divisionAddMonoid", "SubtractionMonoid"), ("subNegZeroAddMonoid", "SubNegZeroMonoid"), - ("modularCharacter", "AddModularCharacter")] + ("modularCharacter", "AddModularCharacter"), + ("addShift", "shift"), + ("AddShift", "Shift"), + ("addSubshift", "subshift"), + ("AddSubshift", "Subshift")] /-- The bundle of environment extensions for `to_additive` -/ def data : TranslateData where From 37259168a23b3cdd5f2e15a78dc2a782f64835d5 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Tue, 9 Dec 2025 09:47:07 +0100 Subject: [PATCH 65/93] removing to_additive names --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 7bf13119c4413a..0481947e1379b2 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -136,7 +136,7 @@ at position `h` in the shifted configuration is the value that was at position For example, if `G = ℤ` (with addition) and `A = {0, 1}`, then `shift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ -@[to_additive shift /-- The **right-translation shift** on configurations, in additive notation. +@[to_additive /-- The **right-translation shift** on configurations, in additive notation. We call *configuration* an element of `G → A`. @@ -153,21 +153,21 @@ step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) -@[to_additive shift_apply] lemma mulShift_apply (g : G) (x : G → A) (h : G) : +@[to_additive] lemma mulShift_apply (g : G) (x : G → A) (h : G) : mulShift g x h = x (h * g) := rfl -@[to_additive shift_zero] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by +@[to_additive] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] /-- Composition of right-translation shifts corresponds to multiplication in the monoid `G`. -/ -@[to_additive shift_add] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : +@[to_additive] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by ext h; simp [mulShift, mul_assoc] variable [TopologicalSpace A] /-- The right-translation shift is continuous. -/ -@[to_additive (attr := fun_prop) continuous_shift] lemma continuous_mulShift (g : G) : +@[to_additive (attr := fun_prop)] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) g) := by -- coordinate projections are continuous; composition preserves continuity unfold mulShift @@ -664,7 +664,7 @@ Formally: * the carrier is `forbidden F` (configurations avoiding `F`), * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ -@[to_additive subshift_from_forbidden] +@[to_additive] def mulSubshift_from_forbidden [DiscreteTopology A] (F : Set (Pattern A G)) : MulSubshift A G where carrier := mulForbidden F isClosed := mulForbidden_closed F @@ -678,7 +678,7 @@ a *finite* family of patterns. Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a `Finset (Pattern A G)`. -/ -@[to_additive subshift_of_finite_type] +@[to_additive] def mulSubshift_of_finite_type [DiscreteTopology A] (F : Finset (Pattern A G)) : MulSubshift A G := mulSubshift_from_forbidden (F : Set (Pattern A G)) From e6a0e665fad870ddf5d6798a27a29d93c31c2cdb Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Tue, 9 Dec 2025 11:48:01 +0100 Subject: [PATCH 66/93] removing counting definitions and use subsets instead of subtypes --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 203 +++++++++---------- 1 file changed, 95 insertions(+), 108 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 0481947e1379b2..0376183179b959 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -103,10 +103,11 @@ between the two viewpoints, since both may naturally want to reuse names like * Openness/closedness results for cylinders and occurrence sets use `[DiscreteTopology A]`. Closedness proofs that enumerate values additionally - require `[Fintype A]`, `[DecidableEq A]`, and `[DecidableEq G]` (for `Finset` - manipulations and `Function.update`). + require `[Fintype A]` and `[DecidableEq A]`. -/ +set_option linter.style.openClassical false + @[expose] public section noncomputable section @@ -153,10 +154,10 @@ step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := fun h => x (h * g) -@[to_additive] lemma mulShift_apply (g : G) (x : G → A) (h : G) : +@[to_additive (attr := simp)] lemma mulShift_apply (g : G) (x : G → A) (h : G) : mulShift g x h = x (h * g) := rfl -@[to_additive] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by +@[to_additive (attr := simp)] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] /-- Composition of right-translation shifts corresponds to multiplication in the monoid `G`. -/ @@ -228,7 +229,7 @@ section SubshiftDef variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [AddMonoid G] -/-- A *subshift* on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is +/-- A *subshift* on an alphabet `A` is a closed, shift-invariant subset of `G → A`. Formally, it is composed of: * `carrier`: the underlying set of allowed configurations. * `isClosed`: the set is topologically closed in `A^G`. @@ -240,7 +241,7 @@ structure Subshift where /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier /-- Shift invariance of `carrier` for the additive shift `shift`. -/ - shiftInvariant : ∀ g : G, ∀ x ∈ carrier, shift g x ∈ carrier + mapsTo : ∀ g : G, MapsTo (shift g) carrier carrier end SubshiftDef @@ -248,26 +249,14 @@ section MulSubshiftDef variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [Monoid G] -/-- A *subshift* on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is -composed of: -* `carrier`: the underlying set of allowed configurations. -* `isClosed`: the set is topologically closed in `A^G`. -* `shiftInvariant`: the set is invariant under all right-translation shifts - `(mulShift g)`. -/ -@[to_additive existing Subshift -/-- A *subshift* on alphabet A is a closed, shift-invariant subset of `G → A`. Formally, it is -composed of: -* `carrier`: the underlying set of allowed configurations. -* `isClosed`: the set is topologically closed in `A^G`. -* `shiftInvariant`: the set is invariant under all right-translation shifts - `(shift g)`. -/] +@[to_additive existing Subshift] structure MulSubshift where /-- The underlying set of configurations. -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ isClosed : IsClosed carrier /-- Shift invariance of `carrier`. -/ - shiftInvariant : ∀ g : G, ∀ x ∈ carrier, mulShift g x ∈ carrier + mapsTo : ∀ g : G, MapsTo (mulShift g) carrier carrier end MulSubshiftDef @@ -277,7 +266,7 @@ end MulSubshiftDef It is the subshift whose underlying set is the set of all configurations `G → A`. -/ -@[to_additive SymbolicDynamics.FullShift.fullShift +@[to_additive fullShift /-- Example: the **full shift** on alphabet `A` over the additive monoid `G`. It is the subshift whose underlying set is the set of all configurations @@ -286,7 +275,7 @@ It is the subshift whose underlying set is the set of all configurations def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : MulSubshift A G where carrier := Set.univ isClosed := isClosed_univ - shiftInvariant := by + mapsTo := by intro _ _ _ simp @@ -375,10 +364,14 @@ def mulForbidden (F : Set (Pattern A G)) : Set (G → A) := end Forbidden -section OccursAt +section OccursInAt + variable {A : Type*} [Inhabited A] -variable {G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] +variable {G : Type*} [Monoid G] [IsRightCancelMul G] + +section PatternExtension +open scoped Classical -- We assume right-cancellation throughout this section for uniqueness of preimages under (_ * v) -- or (_ + v). @@ -428,10 +421,11 @@ noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := simpa [Finset.mem_image] using hmem let w := Classical.choose ex have hw : w ∈ p.support := (Classical.choose_spec ex).1 - have hwv : w * v = h := (Classical.choose_spec ex).2 + have hwv : w * v = h := (Classical.choose_spec ex).2 p.data ⟨w, hw⟩ else default +end PatternExtension namespace Pattern /-- Extract the finite pattern given by restricting a configuration `x : G → A` @@ -465,6 +459,7 @@ under right-multiplication by `v`. -/ lemma mulExtend_apply_mul_right_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : p.mulExtend v (w * v) = p.data ⟨w, hw⟩ := by + classical -- (w*v) is in the translated support have hmem : (w * v) ∈ p.support.image (· * v) := Finset.mem_image.mpr ⟨w, hw, rfl⟩ @@ -531,7 +526,7 @@ the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every po Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] -lemma mulForbidden_shift_invariant {A G : Type*} [Monoid G] +lemma mapsTo_mulShift_mulForbidden {A G : Type*} [Monoid G] (F : Set (Pattern A G)) (h : G) : Set.MapsTo (fun x => mulShift h x) (mulForbidden (A := A) (G := G) F) (mulForbidden F) := by @@ -541,35 +536,11 @@ lemma mulForbidden_shift_invariant {A G : Type*} [Monoid G] contrapose! hx simpa [mulOccursInAt_mulShift] using hx -/-- The set of patterns with fixed support `U`. -/ -@[to_additive FixedSupport] -def MulFixedSupport (A : Type*) (G : Type*) (U : Finset G) := - { p : Pattern A G // p.support = U } - -attribute [inherit_doc SymbolicDynamics.FullShift.Pattern.MulFixedSupport] - SymbolicDynamics.FullShift.Pattern.FixedSupport - -/-- An equivalence between patterns with fixed support and functions on that support. - -Concretely, `fixedSupport A G U` is the subtype of patterns whose support is -exactly `U`. Such a pattern is determined uniquely by its values on `U`, -i.e. by a function `U → A`. This equivalence makes that identification precise: - -* `toFun` sends a fixed-support pattern to the function recording its values, -* `invFun` rebuilds the pattern from a function on `U`. - -This shows immediately that `fixedSupport A G U` is finite whenever `U` is. -/ -@[to_additive equivFun - /-- Additive version: equivalence between fixed-support additive patterns and functions. -/] -def mulEquivFun {U : Finset G} : - MulFixedSupport A G U ≃ (U → A) where - toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ - invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ - left_inv := by rintro ⟨p,hU⟩; apply Subtype.ext; cases hU; rfl - right_inv := by intro f; rfl - end Pattern +section OccursInAtEqCylinder +open scoped Classical + /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations in which a pattern `p` occurs at position `g`. @@ -608,15 +579,15 @@ lemma mulOccursInAt_eq_cylinder H (u * g) (Finset.mem_image_of_mem (· * g) hu) -- rewrite the RHS by the “apply_of_mem” lemma simpa [Pattern.mulExtend_apply_mul_right_of_mem (p := p) (v := g) (w := u) hu] using hx - -end OccursAt +end OccursInAtEqCylinder +end OccursInAt /-! ## Forbidden sets and subshifts -/ section DefSubshiftByForbidden variable {A : Type*} [TopologicalSpace A] [Inhabited A] -variable {G : Type*} [Monoid G] [IsRightCancelMul G] [DecidableEq G] +variable {G : Type*} [Monoid G] [IsRightCancelMul G] /-- Occurrence sets are open. -/ @[to_additive isOpen_occursInAt] @@ -629,24 +600,33 @@ lemma isOpen_mulOccursInAt [DiscreteTopology A] (p : Pattern A G) (g : G) : Since each occurrence set `{ x | p.mulOccursInAt x v }` is open (when `A` is discrete), its complement `{ x | ¬ p.mulOccursInAt x v }` is closed; `forbidden F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/ -@[to_additive forbidden_closed -/-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). +@[to_additive /-- Avoiding a fixed family of patterns is a closed +condition (in the product topology on `G → A`). Since each occurrence set `{ x | p.occursInAt x v }` is open (when `A` is discrete), its complement `{ x | ¬ p.occursInAt x v }` is closed; `forbidden F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/] -lemma mulForbidden_closed [DiscreteTopology A] (F : Set (Pattern A G)) : +lemma isClosed_mulForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : IsClosed (mulForbidden F) := by rw [mulForbidden] - have : {x | ∀ p ∈ F, ∀ v : G, ¬ p.mulOccursInAt x v} - = ⋂ (p : Pattern A G) (h : p ∈ F), ⋂ (v : G), {x | ¬ p.mulOccursInAt x v} := by + -- Rewrite as an intersection indexed by `p ∈ F` and `v : G`. + have h_eq : + {x | ∀ p ∈ F, ∀ v : G, ¬ p.mulOccursInAt x v} + = ⋂ (p : Pattern A G) (hp : p ∈ F) (v : G), {x | ¬ p.mulOccursInAt x v} := by ext x; simp - rw [this] - refine isClosed_iInter ?_; - intro p; refine isClosed_iInter ?_; - intro _; refine isClosed_iInter ?_; - intro v; have : {x | ¬p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by ext x; simp - simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt p v + rw [h_eq] + -- Now prove that this big intersection is closed. + have h_closed : + IsClosed (⋂ (p : Pattern A G) (hp : p ∈ F) (v : G), {x | ¬ p.mulOccursInAt x v}) := by + refine isClosed_iInter (fun p => ?_) + refine isClosed_iInter (fun hp => ?_) + refine isClosed_iInter (fun v => ?_) + -- For each `p, hp, v`, the section is the complement of an open occurrence set. + have : {x | ¬ p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by + ext x; simp + simpa [this, isClosed_compl_iff] using + isOpen_mulOccursInAt (A := A) (G := G) p v + simpa using h_closed /-- Occurrence sets are closed. -/ @[to_additive isClosed_occursInAt] @@ -665,13 +645,13 @@ Formally: * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ @[to_additive] -def mulSubshift_from_forbidden [DiscreteTopology A] (F : Set (Pattern A G)) : MulSubshift A G where +def MulSubshift.ofForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : MulSubshift A G where carrier := mulForbidden F - isClosed := mulForbidden_closed F - shiftInvariant := Pattern.mulForbidden_shift_invariant F + isClosed := isClosed_mulForbidden F + mapsTo := Pattern.mapsTo_mulShift_mulForbidden F -attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_from_forbidden] - SymbolicDynamics.FullShift.subshift_from_forbidden +attribute [inherit_doc SymbolicDynamics.FullShift.MulSubshift.ofForbidden] + SymbolicDynamics.FullShift.Subshift.ofForbidden /-- A subshift of finite type (SFT) is a subshift defined by forbidding a *finite* family of patterns. @@ -680,7 +660,7 @@ Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` i `Finset (Pattern A G)`. -/ @[to_additive] def mulSubshift_of_finite_type [DiscreteTopology A] (F : Finset (Pattern A G)) : MulSubshift A G := - mulSubshift_from_forbidden (F : Set (Pattern A G)) + MulSubshift.ofForbidden (F : Set (Pattern A G)) attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_of_finite_type] SymbolicDynamics.FullShift.subshift_of_finite_type @@ -689,16 +669,49 @@ end DefSubshiftByForbidden section Language -variable {A : Type*} [Fintype A] [TopologicalSpace A] -variable {G : Type*} [Monoid G] +variable {A : Type*} [Fintype A] +variable {G : Type*} - -/-- `fixedSupport A G U` is a finite type: there are only finitely many patterns -with support exactly `U`. This follows from the equivalence with functions `U → A`. -/ -@[to_additive SymbolicDynamics.FullShift.fintypeFixedSupport] noncomputable -instance mulFintypeFixedSupport {U : Finset G} : - Fintype (Pattern.MulFixedSupport A G U) := by - classical exact Fintype.ofEquiv (U → A) (Pattern.mulEquivFun (A := A) (G := G) (U := U)).symm +/-- Patterns with support exactly `U` form a finite set. -/ +lemma finite_patterns_with_support + {A G : Type*} [Fintype A] + (U : Finset G) : + ({ p : Pattern A G | p.support = U } : Set (Pattern A G)).Finite := by + classical + -- Local equivalence between the subtype and functions on U + have e : { p : Pattern A G // p.support = U } ≃ (U → A) := + { toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ + invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ + left_inv := by + rintro ⟨p, hU⟩ + apply Subtype.ext + cases hU + rfl + right_inv := by intro f; rfl } + + -- Give a Fintype structure to the subtype via this equivalence + haveI : Fintype { p : Pattern A G // p.support = U } := + Fintype.ofEquiv (U → A) e.symm + + -- Now prove finiteness of `{ p : Pattern A G | p.support = U }` by + -- viewing it as the image of `univ` in that finite subtype + let T := { p : Pattern A G // p.support = U } + have h_univ : (Set.univ : Set T).Finite := + Set.finite_univ + let coeT : T → Pattern A G := fun p => (p : Pattern A G) + have h_image : (Set.image coeT (Set.univ : Set T)).Finite := + h_univ.image _ + have himage_eq : + Set.image coeT (Set.univ : Set T) + = ({ p : Pattern A G | p.support = U } : Set (Pattern A G)) := by + ext p; constructor + · intro hp + rcases hp with ⟨p', -, rfl⟩ + exact p'.property + · intro hp + refine ⟨⟨p, hp⟩, ?_, rfl⟩ + simp + simpa [himage_eq] using h_image /-- The language of a set of configurations `X` on a finite shape `U`. @@ -717,32 +730,6 @@ def MulSubshift.languageOn {A G} [TopologicalSpace A] [Monoid G] (Y : MulSubshift A G) (U : Finset G) : Set (Pattern A G) := SymbolicDynamics.FullShift.mulLanguageOn (A:=A) (G:=G) Y.carrier U -/-- The cardinality of the language of `X` on a finite set `U`. - -That is, the number of distinct patterns supported on `U` which appear -in some configuration of `X`. Since `U` is finite, this is a finite number. -/ -@[to_additive languageCardOn] -noncomputable def mulLanguageCardOn (X : Set (G → A)) (U : Finset G) : ℕ := by - -- Image of a map into the finite type `FixedSupport A G U` - let f : {x : G → A // x ∈ X} → Pattern.MulFixedSupport A G U := - fun x => ⟨Pattern.fromConfig x.1 U, rfl⟩ - have hfin : (Set.range f).Finite := (Set.finite_univ : - (Set.univ : Set (Pattern.MulFixedSupport A G U)).Finite) - |>.subset (by intro y hy; simp) - exact hfin.toFinset.card - -attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageCardOn] - SymbolicDynamics.FullShift.languageCardOn - -/-- The number of patterns which appear in the configurations of the carrier -of a subshift `Y` on a finite set `U`. -/ -@[to_additive patternCountOn] -noncomputable def mulPatternCountOn (Y : MulSubshift A G) (U : Finset G) : ℕ := - mulLanguageCardOn (A := A) (G := G) Y.carrier U - -attribute [inherit_doc SymbolicDynamics.FullShift.mulPatternCountOn] - SymbolicDynamics.FullShift.patternCountOn - end Language end FullShift From 68601ba0cb16939c12d1ab15b4327ace9703c834 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Tue, 9 Dec 2025 18:10:55 +0100 Subject: [PATCH 67/93] doc for mulShift --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 0376183179b959..28006fc62ba6ff 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -233,7 +233,7 @@ variable (G : Type*) [AddMonoid G] composed of: * `carrier`: the underlying set of allowed configurations. * `isClosed`: the set is topologically closed in `A^G`. -* `shiftInvariant`: the set is invariant under all right-translation shifts +* `mapsTo`: the set is invariant under all right-translation shifts `(shift g)`. -/ structure Subshift where /-- The underlying set of configurations (additive monoid version). -/ @@ -249,6 +249,13 @@ section MulSubshiftDef variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [Monoid G] +/-- A *subshift* on an alphabet `A` over a multiplicative monoid `G` is a closed, +shift-invariant subset of `G → A`, where the shift is given by right-multiplication. +Formally, it is composed of: +* `carrier`: the underlying set of allowed configurations. +* `isClosed`: the set is topologically closed in `A^G`. +* `mapsTo`: the set is invariant under all right-translation shifts + `(mulShift g)`. -/ @[to_additive existing Subshift] structure MulSubshift where /-- The underlying set of configurations. -/ From 0a2b59455065421023867e5fa57160ea0f3fb81c Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Sun, 14 Dec 2025 18:09:22 +0100 Subject: [PATCH 68/93] Adapted docstrings to last changes --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 41 ++++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 28006fc62ba6ff..d112200ac25656 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -52,7 +52,7 @@ so that the theory works not only for groups but also for cancellative monoids. * `Pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. * `forbidden F` — configurations avoiding every pattern in `F`. * `Subshift A G` — closed, shift-invariant subsets of the full shift. -* `subshift_from_forbidden F` — the subshift defined by forbidding a family of patterns. +* `MulSubshift.ofForbidde F` — the subshift defined by forbidding a family of patterns. * `subshift_of_finite_type F` — a subshift of finite type defined by a finite set of forbidden patterns. * `languageOn X U` — the set of patterns of shape `U` obtained by restricting some `x ∈ X`. @@ -135,7 +135,7 @@ at position `h` in the shifted configuration is the value that was at position `h * g` in the original one. For example, if `G = ℤ` (with addition) and `A = {0, 1}`, then -`shift 1 x` is the sequence obtained from `x` by shifting every symbol one +`mulShift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ @[to_additive /-- The **right-translation shift** on configurations, in additive notation. @@ -327,7 +327,8 @@ section Forbidden variable {A G : Type*} [Monoid G] -/-- `p.mulOccursInAt x g` means that the finite pattern `p` appears in the configuration `x` +/-- `p.mulOccursInAt x g` means that the finite pattern +`p` appears in the configuration `x` at position `g`. Formally: for every position `h` in the support of `p`, the value of the configuration @@ -528,7 +529,7 @@ lemma mulOccursInAt_mulShift {A G : Type*} [Monoid G] (p : Pattern A G) (x : G Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every position. -/ -@[to_additive forbidden_shift_invariant +@[to_additive mapsTo_shift_forbidden /-- Configurations that avoid a family `F` of patterns are stable under the shift. Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, @@ -554,7 +555,8 @@ in which a pattern `p` occurs at position `g`. This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. -Equivalently, `p.mulOccursInAt x g` iff on every translated site `w * g` (with `w ∈ p.support`) +Equivalently, `p.mulOccursInAt x g` iff on every translated site +`w * g` (with `w ∈ p.support`) the configuration `x` agrees with the translated pattern `Pattern.mulExtend p g`. (This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ @@ -607,7 +609,7 @@ lemma isOpen_mulOccursInAt [DiscreteTopology A] (p : Pattern A G) (g : G) : Since each occurrence set `{ x | p.mulOccursInAt x v }` is open (when `A` is discrete), its complement `{ x | ¬ p.mulOccursInAt x v }` is closed; `forbidden F` is the intersection of these closed sets over `p ∈ F` and `v ∈ G`. -/ -@[to_additive /-- Avoiding a fixed family of patterns is a closed +@[to_additive isClosed_forbidden /-- Avoiding a fixed family of patterns is a closed condition (in the product topology on `G → A`). Since each occurrence set `{ x | p.occursInAt x v }` is open (when `A` is discrete), @@ -644,34 +646,41 @@ lemma isClosed_mulOccursInAt [T1Space A] (p : Pattern A G) (g : G) : /-- The subshift defined by a family of forbidden patterns `F`. This is a standard way to construct subshifts: -`subshift_from_forbidden F` consists of all configurations `x : G → A` in which no pattern +`MulSubshift.ofForbidden F` consists of all configurations `x : G → A` in which no pattern `p ∈ F` occurs at any position. Formally: * the carrier is `forbidden F` (configurations avoiding `F`), * it is closed because each occurrence set is open, and * it is shift-invariant since avoidance is preserved by shifts. -/ -@[to_additive] +@[to_additive /-- The subshift defined by a family of forbidden patterns `F`. + +This is a standard way to construct subshifts: +`Subshift.ofForbidden F` consists of all configurations `x : G → A` in which no pattern +`p ∈ F` occurs at any position. + +Formally: +* the carrier is `forbidden F` (configurations avoiding `F`), +* it is closed because each occurrence set is open, and +* it is shift-invariant since avoidance is preserved by shifts. -/] def MulSubshift.ofForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : MulSubshift A G where carrier := mulForbidden F isClosed := isClosed_mulForbidden F mapsTo := Pattern.mapsTo_mulShift_mulForbidden F -attribute [inherit_doc SymbolicDynamics.FullShift.MulSubshift.ofForbidden] - SymbolicDynamics.FullShift.Subshift.ofForbidden - /-- A subshift of finite type (SFT) is a subshift defined by forbidding a *finite* family of patterns. -Formally, `subshift_of_finite_type F` is `subshift_from_forbidden F` where `F` is a +Formally, `mulSubshift_of_finite_type F` is `MulSubshift.ofForbidden F` where `F` is a `Finset (Pattern A G)`. -/ -@[to_additive] +@[to_additive /-- A subshift of finite type (SFT) is a subshift defined by forbidding +a *finite* family of patterns. + +Formally, `subshift_of_finite_type F` is `Subshift.ofForbidden F` where `F` is a +`Finset (Pattern A G)`. -/] def mulSubshift_of_finite_type [DiscreteTopology A] (F : Finset (Pattern A G)) : MulSubshift A G := MulSubshift.ofForbidden (F : Set (Pattern A G)) -attribute [inherit_doc SymbolicDynamics.FullShift.mulSubshift_of_finite_type] - SymbolicDynamics.FullShift.subshift_of_finite_type - end DefSubshiftByForbidden section Language From e92f02b5ce6c5c734e5ccff8151717d608656932 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 8 Jan 2026 07:36:03 +0900 Subject: [PATCH 69/93] linters --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index d112200ac25656..1b85815b31e756 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -704,11 +704,9 @@ lemma finite_patterns_with_support cases hU rfl right_inv := by intro f; rfl } - -- Give a Fintype structure to the subtype via this equivalence haveI : Fintype { p : Pattern A G // p.support = U } := Fintype.ofEquiv (U → A) e.symm - -- Now prove finiteness of `{ p : Pattern A G | p.support = U }` by -- viewing it as the image of `univ` in that finite subtype let T := { p : Pattern A G // p.support = U } From b84428e4aee29a7ea908c5e6ebb4f3c1777415bc Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:42:33 +0900 Subject: [PATCH 70/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 1b85815b31e756..2dd5cc5dc66a93 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -619,10 +619,8 @@ lemma isClosed_mulForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : IsClosed (mulForbidden F) := by rw [mulForbidden] -- Rewrite as an intersection indexed by `p ∈ F` and `v : G`. - have h_eq : - {x | ∀ p ∈ F, ∀ v : G, ¬ p.mulOccursInAt x v} - = ⋂ (p : Pattern A G) (hp : p ∈ F) (v : G), {x | ¬ p.mulOccursInAt x v} := by - ext x; simp + have h_eq : {x | ∀ p ∈ F, ∀ v : G, ¬ p.mulOccursInAt x v} + = ⋂ (p : Pattern A G) (hp : p ∈ F) (v : G), {x | ¬ p.mulOccursInAt x v} := by ext; simp rw [h_eq] -- Now prove that this big intersection is closed. have h_closed : From d61cd4e3069b0e8fc4f1d2e70205988bcd6522f4 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:42:55 +0900 Subject: [PATCH 71/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 2dd5cc5dc66a93..94fb703e07f3a5 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -629,8 +629,7 @@ lemma isClosed_mulForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : refine isClosed_iInter (fun hp => ?_) refine isClosed_iInter (fun v => ?_) -- For each `p, hp, v`, the section is the complement of an open occurrence set. - have : {x | ¬ p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by - ext x; simp + have : {x | ¬ p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by ext; simp simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt (A := A) (G := G) p v simpa using h_closed From d2c11a47bf450c737e40936298607b21a272b549 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:43:16 +0900 Subject: [PATCH 72/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 94fb703e07f3a5..dc4b1a7f81ba37 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -630,8 +630,7 @@ lemma isClosed_mulForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : refine isClosed_iInter (fun v => ?_) -- For each `p, hp, v`, the section is the complement of an open occurrence set. have : {x | ¬ p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by ext; simp - simpa [this, isClosed_compl_iff] using - isOpen_mulOccursInAt (A := A) (G := G) p v + simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt (A := A) (G := G) p v simpa using h_closed /-- Occurrence sets are closed. -/ From 1e8a7d7aec035ddd07999be8ac628c03f264ef34 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:43:49 +0900 Subject: [PATCH 73/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index dc4b1a7f81ba37..6f499fddf8ebee 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -738,7 +738,7 @@ attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageOn] @[to_additive /-- The language of a subshift `Y` on a finite shape `U`. -/] def MulSubshift.languageOn {A G} [TopologicalSpace A] [Monoid G] (Y : MulSubshift A G) (U : Finset G) : Set (Pattern A G) := - SymbolicDynamics.FullShift.mulLanguageOn (A:=A) (G:=G) Y.carrier U + SymbolicDynamics.FullShift.mulLanguageOn (A := A) (G := G) Y.carrier U end Language From 0a227ef2e2eb6b8fac4a3a771c4d474be654fb90 Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:44:27 +0900 Subject: [PATCH 74/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 6f499fddf8ebee..66a42c4e4799e9 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -691,7 +691,7 @@ lemma finite_patterns_with_support ({ p : Pattern A G | p.support = U } : Set (Pattern A G)).Finite := by classical -- Local equivalence between the subtype and functions on U - have e : { p : Pattern A G // p.support = U } ≃ (U → A) := + let e : { p : Pattern A G // p.support = U } ≃ (U → A) := { toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ left_inv := by From 3dcf639029f038742c6faef757496603a5c3c93d Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:45:12 +0900 Subject: [PATCH 75/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 66a42c4e4799e9..edd0ed0b15c8fc 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -685,7 +685,7 @@ variable {A : Type*} [Fintype A] variable {G : Type*} /-- Patterns with support exactly `U` form a finite set. -/ -lemma finite_patterns_with_support +lemma finite_setOf_pattern_support_eq {A G : Type*} [Fintype A] (U : Finset G) : ({ p : Pattern A G | p.support = U } : Set (Pattern A G)).Finite := by From dc625ed110a90d1d8eb77189825aebcc0dd70feb Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:46:16 +0900 Subject: [PATCH 76/93] Update Mathlib/Tactic/Translate/ToAdditive.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Tactic/Translate/ToAdditive.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Mathlib/Tactic/Translate/ToAdditive.lean b/Mathlib/Tactic/Translate/ToAdditive.lean index afc3720b695ad4..cd9f52ce726f5e 100644 --- a/Mathlib/Tactic/Translate/ToAdditive.lean +++ b/Mathlib/Tactic/Translate/ToAdditive.lean @@ -376,7 +376,6 @@ def abbreviationDict : Std.HashMap String String := .ofList [ ("addSubshift", "subshift"), ("AddSubshift", "Subshift"), ("isQuotientCoveringMap", "IsAddQuotientCoveringMap"), - ("isQuotientCoveringMap", "IsAddQuotientCoveringMap"), ("addExact", "exact")] /-- The bundle of environment extensions for `to_additive` -/ From 4504528756057dc6ce301abf6ab2bd2a0e881aef Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Wed, 4 Feb 2026 10:44:17 +0900 Subject: [PATCH 77/93] Fix underscores in definition and type definition --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index edd0ed0b15c8fc..8ccca22e34c7dc 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -674,7 +674,7 @@ a *finite* family of patterns. Formally, `subshift_of_finite_type F` is `Subshift.ofForbidden F` where `F` is a `Finset (Pattern A G)`. -/] -def mulSubshift_of_finite_type [DiscreteTopology A] (F : Finset (Pattern A G)) : MulSubshift A G := +def mulSubshiftOfFiniteType [DiscreteTopology A] (F : Finset (Pattern A G)) : MulSubshift A G := MulSubshift.ofForbidden (F : Set (Pattern A G)) end DefSubshiftByForbidden @@ -688,12 +688,12 @@ variable {G : Type*} lemma finite_setOf_pattern_support_eq {A G : Type*} [Fintype A] (U : Finset G) : - ({ p : Pattern A G | p.support = U } : Set (Pattern A G)).Finite := by + ({p : Pattern A G | p.support = U}).Finite := by classical -- Local equivalence between the subtype and functions on U let e : { p : Pattern A G // p.support = U } ≃ (U → A) := - { toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ - invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ + { toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ + invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ left_inv := by rintro ⟨p, hU⟩ apply Subtype.ext @@ -727,13 +727,9 @@ lemma finite_setOf_pattern_support_eq This is the set of all finite patterns obtained by restricting some configuration `x ∈ X` to `U`. -/ -@[to_additive languageOn] def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, Pattern.fromConfig x U = p } -attribute [inherit_doc SymbolicDynamics.FullShift.mulLanguageOn] - SymbolicDynamics.FullShift.languageOn - /-- The language of a subshift `Y` on a finite shape `U`. -/ @[to_additive /-- The language of a subshift `Y` on a finite shape `U`. -/] def MulSubshift.languageOn {A G} [TopologicalSpace A] [Monoid G] From a224edf5e29329a425167f43d6123e4477912fcd Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Wed, 4 Feb 2026 16:56:13 +0900 Subject: [PATCH 78/93] Fix to additive renaming --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- Mathlib/Tactic/Translate/ToAdditive.lean | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 8ccca22e34c7dc..16afb1976ab5b0 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -256,7 +256,7 @@ Formally, it is composed of: * `isClosed`: the set is topologically closed in `A^G`. * `mapsTo`: the set is invariant under all right-translation shifts `(mulShift g)`. -/ -@[to_additive existing Subshift] +@[to_additive existing] structure MulSubshift where /-- The underlying set of configurations. -/ carrier : Set (G → A) diff --git a/Mathlib/Tactic/Translate/ToAdditive.lean b/Mathlib/Tactic/Translate/ToAdditive.lean index cd9f52ce726f5e..5955bb1c2051f2 100644 --- a/Mathlib/Tactic/Translate/ToAdditive.lean +++ b/Mathlib/Tactic/Translate/ToAdditive.lean @@ -371,10 +371,8 @@ def abbreviationDict : Std.HashMap String String := .ofList [ ("divisionAddMonoid", "SubtractionMonoid"), ("subNegZeroAddMonoid", "SubNegZeroMonoid"), ("modularCharacter", "AddModularCharacter"), - ("addShift", "shift"), - ("AddShift", "Shift"), - ("addSubshift", "subshift"), - ("AddSubshift", "Subshift"), + ("addShift", "Shift"), + ("addSubshift", "Subshift"), ("isQuotientCoveringMap", "IsAddQuotientCoveringMap"), ("addExact", "exact")] From 4f82b1f4a8516ef4064472a57ce4dec2939ed9ac Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:47:47 +0900 Subject: [PATCH 79/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: botbaki-review[bot] <258399068+botbaki-review[bot]@users.noreply.github.com> --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 16afb1976ab5b0..3830437d005fe6 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -52,7 +52,7 @@ so that the theory works not only for groups but also for cancellative monoids. * `Pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. * `forbidden F` — configurations avoiding every pattern in `F`. * `Subshift A G` — closed, shift-invariant subsets of the full shift. -* `MulSubshift.ofForbidde F` — the subshift defined by forbidding a family of patterns. +* `MulSubshift.ofForbidden F` — the subshift defined by forbidding a family of patterns. * `subshift_of_finite_type F` — a subshift of finite type defined by a finite set of forbidden patterns. * `languageOn X U` — the set of patterns of shape `U` obtained by restricting some `x ∈ X`. From a190ae1107852bf744be33ee800731690a04481d Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Tue, 17 Feb 2026 09:10:04 +0900 Subject: [PATCH 80/93] suggestions botbaki --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 3830437d005fe6..7512ec103d1b67 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -282,9 +282,7 @@ It is the subshift whose underlying set is the set of all configurations def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : MulSubshift A G where carrier := Set.univ isClosed := isClosed_univ - mapsTo := by - intro _ _ _ - simp + mapsTo := fun _ _ _ => trivial /-- A *pattern* is a finite configuration in the full shift `A^G`. @@ -495,8 +493,7 @@ lemma mulExtend_apply_mul_right_of_mem -- we have h_eq : w' = w and w' := Classical.choose ex simpa [w'] using h_eq -- <-- use `using h_eq`, only unfold `[w']` -- then replace the proof component (same carrier w) - have h3 : (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := by - apply Subtype.ext; rfl + have h3 : (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := rfl -- put the rewrites together calc p.mulExtend v (w * v) @@ -523,7 +520,7 @@ position `g` if and only if it occurs in the original configuration `x` at position `g + h`. -/] lemma mulOccursInAt_mulShift {A G : Type*} [Monoid G] (p : Pattern A G) (x : G → A) (g h : G) : p.mulOccursInAt (mulShift h x) g ↔ p.mulOccursInAt x (g * h) := by - constructor <;> intro H u hu <;> simpa [mulShift, mul_assoc] using H u hu + simp only [mulOccursInAt, mulShift_apply, mul_assoc] /-- Configurations that avoid a family `F` of patterns are stable under the shift. @@ -699,7 +696,7 @@ lemma finite_setOf_pattern_support_eq apply Subtype.ext cases hU rfl - right_inv := by intro f; rfl } + right_inv := fun _ => rfl} -- Give a Fintype structure to the subtype via this equivalence haveI : Fintype { p : Pattern A G // p.support = U } := Fintype.ofEquiv (U → A) e.symm @@ -731,7 +728,6 @@ def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, Pattern.fromConfig x U = p } /-- The language of a subshift `Y` on a finite shape `U`. -/ -@[to_additive /-- The language of a subshift `Y` on a finite shape `U`. -/] def MulSubshift.languageOn {A G} [TopologicalSpace A] [Monoid G] (Y : MulSubshift A G) (U : Finset G) : Set (Pattern A G) := SymbolicDynamics.FullShift.mulLanguageOn (A := A) (G := G) Y.carrier U From f643a4a3fdc4ba8a730825459557f9bf26be6061 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Wed, 18 Feb 2026 09:34:17 +0900 Subject: [PATCH 81/93] removed open scoped Classical --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 38 +++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 7512ec103d1b67..7b3dea566177c1 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -377,7 +377,6 @@ variable {A : Type*} [Inhabited A] variable {G : Type*} [Monoid G] [IsRightCancelMul G] section PatternExtension -open scoped Classical -- We assume right-cancellation throughout this section for uniqueness of preimages under (_ * v) -- or (_ + v). @@ -391,8 +390,13 @@ Formally: given a pattern `p` with finite support in `G`, we define a configurat This produces a canonical "completion" of the pattern to a configuration, filling all unspecified positions with `default`. -/ -def Pattern.extendAtOrigin (p : Pattern A G) : G → A := - fun i ↦ if h : i ∈ p.support then p.data ⟨i, h⟩ else default +def Pattern.extendAtOrigin (p : Pattern A G) : G → A := by + classical + exact fun i ↦ + if h : i ∈ p.support then + p.data ⟨i, h⟩ + else + default /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. @@ -419,18 +423,19 @@ This definition does not assume right-cancellation; it only *chooses* a preimage Uniqueness (and the usual equations such as `Pattern.extend p v (w + v) = p.data ⟨w, _⟩`) require a right-cancellation hypothesis and are proved in separate lemmas. -/] -noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := - fun h => - if hmem : h ∈ p.support.image (· * v) then - -- package existence of a preimage under (_ * v) - let ex : ∃ w, w ∈ p.support ∧ w * v = h := by - simpa [Finset.mem_image] using hmem - let w := Classical.choose ex - have hw : w ∈ p.support := (Classical.choose_spec ex).1 - have hwv : w * v = h := (Classical.choose_spec ex).2 - p.data ⟨w, hw⟩ - else - default +noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := by + classical + intro h + if hmem : h ∈ p.support.image (· * v) then + -- package existence of a preimage under (_ * v) + let ex : ∃ w, w ∈ p.support ∧ w * v = h := by + simpa [Finset.mem_image] using hmem + let w := Classical.choose ex + have hw : w ∈ p.support := (Classical.choose_spec ex).1 + have hwv : w * v = h := (Classical.choose_spec ex).2 + exact p.data ⟨w, hw⟩ + else + exact default end PatternExtension namespace Pattern @@ -544,8 +549,7 @@ lemma mapsTo_mulShift_mulForbidden {A G : Type*} [Monoid G] end Pattern section OccursInAtEqCylinder -open scoped Classical - +open scoped Classical in /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations in which a pattern `p` occurs at position `g`. From 41cd4ca6cce4ec9eb98afa301b135b725dd6bb42 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Wed, 8 Apr 2026 22:45:40 +0900 Subject: [PATCH 82/93] change from right to left action --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 183 ++++++++----------- 1 file changed, 74 insertions(+), 109 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 7b3dea566177c1..57940304a84e45 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -12,22 +12,22 @@ public import Mathlib.Topology.Separation.Basic # Symbolic dynamics on cancellative monoids This file develops a minimal API for symbolic dynamics over a -**right-cancellative monoid** `G`—formally, a structure carrying `[Monoid G]` -and `[IsRightCancelMul G]` (which becomes `[AddMonoid G]` and -`[IsRightCancelAdd G]` in the additive form). Throughout the documentation we use the +**left-cancellative monoid** `G`—formally, a structure carrying `[Monoid G]` +and `[IsLeftCancelMul G]` (which becomes `[AddMonoid G]` and +`[IsLeftCancelAdd G]` in the additive form). Throughout the documentation we use the **additive** notations, which are the most common in symbolic dynamics, although all the notions introduced are defined in the multiplicative notations and adapted to the additive notation. Given a finite alphabet `A`, the ambient configuration space is the set of functions `G → A`, endowed with the product topology. We define the -right-translation action, cylinders, finite patterns, their occurrences, +left-translation action, cylinders, finite patterns, their occurrences, forbidden sets, and subshifts (closed, shift-invariant subsets). Basic topological facts (e.g. cylinders are clopen, occurrence sets are clopen, forbidden sets are closed) are proved under discreteness assumptions on the alphabet. -The development is generic for right-cancellative monoids. This covers both +The development is generic for left-cancellative monoids. This covers both groups (the standard setting of symbolic dynamics) and more general monoids where cancellation holds but inverses may not exist. Geometry specific to `ℤ^d` (boxes/cubes and the box-based entropy) is deferred to a separate @@ -37,16 +37,16 @@ specialization. Some constructions, such as translating a finite pattern to occur at a point `v`, require solving equations of the form `w + v = h`. For this to have a unique -solution `w` given `h` and `v`, we assume **right-cancellation**: -if `a + v = b + v` then `a = b`. This allows us to define +solution `w` given `h` and `v`, we assume **left-cancellation**: +if `v + a = v + b` then `a = b`. This allows us to define `Pattern.extend` (which extends a pattern into a configuration using the default value of `A`) without using inverses, so that the theory works not only for groups but also for cancellative monoids. ## Main definitions -* `shift g x` — right translation: in additive notation `(shift v x) u = x (u + v)` (using the -**right** action of `G` on configurations). +* `shift g x` — left translation: in additive notation `(shift v x) u = x (v + u)` (using the +**left** action of `G` on configurations). * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. * `Pattern A G` — finite support together with values on that support. * `Pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. @@ -101,13 +101,10 @@ between the two viewpoints, since both may naturally want to reuse names like ## Implementation notes -* Openness/closedness results for cylinders and occurrence sets use - `[DiscreteTopology A]`. Closedness proofs that enumerate values additionally - require `[Fintype A]` and `[DecidableEq A]`. +* Openness results for cylinders and occurrence sets use + `[DiscreteTopology A]`. Closeness results use `[T1Space A]`. -/ -set_option linter.style.openClassical false - @[expose] public section noncomputable section @@ -123,51 +120,51 @@ section ShiftDefinition variable {A G : Type*} [Monoid G] -/-- The **right-translation shift** on configurations. +/-- The **left-translation shift** on configurations. We call *configuration* an element of `G → A`. Given a configuration `x : G → A` and an element `g : G` of the monoid, the shifted configuration -`mulShift g x` is defined by `(mulShift g x) h = x (h * g)`. +`mulShift g x` is defined by `(mulShift g x) h = x (g * h)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value at position `h` in the shifted configuration is the value that was at position -`h * g` in the original one. +`g * h` in the original one. For example, if `G = ℤ` (with addition) and `A = {0, 1}`, then `mulShift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/ -@[to_additive /-- The **right-translation shift** on configurations, in additive notation. +@[to_additive /-- The **left-translation shift** on configurations, in additive notation. We call *configuration* an element of `G → A`. Given a configuration `x : G → A` and an element `g : G` of the additive monoid, -the shifted configuration `shift g x` is defined by `(shift g x) h = x (h + g)`. +the shifted configuration `shift g x` is defined by `(shift g x) h = x (g + h)`. Intuitively, this moves the whole configuration "in the direction of `g`": the value at position `h` in the shifted configuration is the value that was at position -`h + g` in the original one. +`g + h` in the original one. For example, if `G = ℤ` and `A = {0, 1}`, then `shift 1 x` is the sequence obtained from `x` by shifting every symbol one step to the left. -/] def mulShift (g : G) (x : G → A) : G → A := - fun h => x (h * g) + fun h => x (g * h) @[to_additive (attr := simp)] lemma mulShift_apply (g : G) (x : G → A) (h : G) : - mulShift g x h = x (h * g) := rfl + mulShift g x h = x (g * h) := rfl @[to_additive (attr := simp)] lemma mulShift_one (x : G → A) : mulShift (1 : G) x = x := by ext h; simp [mulShift] -/-- Composition of right-translation shifts corresponds to multiplication in the monoid `G`. -/ +/-- Composition of left-translation shifts corresponds to multiplication in the monoid `G`. -/ @[to_additive] lemma mulShift_mul (g₁ g₂ : G) (x : G → A) : - mulShift (g₁ * g₂) x = mulShift g₁ (mulShift g₂ x) := by + mulShift (g₁ * g₂) x = mulShift g₂ (mulShift g₁ x) := by ext h; simp [mulShift, mul_assoc] variable [TopologicalSpace A] -/-- The right-translation shift is continuous. -/ +/-- The left-translation shift is continuous. -/ @[to_additive (attr := fun_prop)] lemma continuous_mulShift (g : G) : Continuous (mulShift (A := A) g) := by -- coordinate projections are continuous; composition preserves continuity @@ -224,18 +221,13 @@ end Cylinders /-! ## Patterns and occurrences -/ - -section SubshiftDef -variable (A : Type*) [TopologicalSpace A] -variable (G : Type*) [AddMonoid G] - /-- A *subshift* on an alphabet `A` is a closed, shift-invariant subset of `G → A`. Formally, it is composed of: * `carrier`: the underlying set of allowed configurations. * `isClosed`: the set is topologically closed in `A^G`. -* `mapsTo`: the set is invariant under all right-translation shifts +* `mapsTo`: the set is invariant under all left-translation shifts `(shift g)`. -/ -structure Subshift where +structure Subshift (A : Type*) [TopologicalSpace A] (G : Type*) [AddMonoid G] where /-- The underlying set of configurations (additive monoid version). -/ carrier : Set (G → A) /-- Closedness of `carrier`. -/ @@ -243,18 +235,16 @@ structure Subshift where /-- Shift invariance of `carrier` for the additive shift `shift`. -/ mapsTo : ∀ g : G, MapsTo (shift g) carrier carrier -end SubshiftDef - section MulSubshiftDef variable (A : Type*) [TopologicalSpace A] variable (G : Type*) [Monoid G] /-- A *subshift* on an alphabet `A` over a multiplicative monoid `G` is a closed, -shift-invariant subset of `G → A`, where the shift is given by right-multiplication. +shift-invariant subset of `G → A`, where the shift is given by left-multiplication. Formally, it is composed of: * `carrier`: the underlying set of allowed configurations. * `isClosed`: the set is topologically closed in `A^G`. -* `mapsTo`: the set is invariant under all right-translation shifts +* `mapsTo`: the set is invariant under all left-translation shifts `(mulShift g)`. -/ @[to_additive existing] structure MulSubshift where @@ -267,12 +257,9 @@ structure MulSubshift where end MulSubshiftDef - /-- Example: the **full shift** on alphabet `A` over the multiplicative monoid `G`. - It is the subshift whose underlying set is the set of all configurations -`G → A`. --/ +`G → A`. -/ @[to_additive fullShift /-- Example: the **full shift** on alphabet `A` over the additive monoid `G`. @@ -301,26 +288,6 @@ structure Pattern (A : Type*) (G : Type*) where /-- The value (symbol) at each point of the support. -/ data : support → A -namespace Pattern -section Dominos - -variable (G : Type*) - -/-- A *domino* is a pattern supported on exactly two positions (sometimes -also called cells) `{i, j}`, specifying the value `ai` at `i` and the value `aj` at `j`. - -In symbolic dynamics, dominos (two-cell patterns) are the simplest nontrivial -building blocks: they describe local adjacency conditions between two sites -of a configuration. -/ -def domino {A : Type*} (i j : G) (ai aj : A) : Pattern A G := by - classical - exact - { support := ({i, j} : Finset G) - data := fun ⟨z, _hz⟩ => if z = i then ai else aj } - -end Dominos -end Pattern - section Forbidden variable {A G : Type*} [Monoid G] @@ -330,7 +297,7 @@ variable {A G : Type*} [Monoid G] at position `g`. Formally: for every position `h` in the support of `p`, the value of the configuration -at `h * g` coincides with the value specified by `p` at `h`. +at `g * h` coincides with the value specified by `p` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), then on the support of `p` you exactly recover the pattern `p`. This is the basic @@ -340,13 +307,13 @@ notion of "pattern occurrence" used to define subshifts via forbidden patterns. at position `g`. Formally: for every position `h` in the support of `p`, the value of the configuration -at `h + g` coincides with the value specified by `p` at `h`. +at `g + h` coincides with the value specified by `p` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `shift g`), then on the support of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/] def Pattern.mulOccursInAt (p : Pattern A G) (x : G → A) (g : G) : Prop := - ∀ (h) (hh : h ∈ p.support), x (h * g) = p.data ⟨h, hh⟩ + ∀ (h) (hh : h ∈ p.support), x (g * h) = p.data ⟨h, hh⟩ /-- `mulForbidden F` is the set of configurations that avoid every pattern in `F`. @@ -372,12 +339,11 @@ end Forbidden section OccursInAt - variable {A : Type*} [Inhabited A] -variable {G : Type*} [Monoid G] [IsRightCancelMul G] +variable {G : Type*} [Monoid G] [IsLeftCancelMul G] section PatternExtension --- We assume right-cancellation throughout this section for uniqueness of preimages under (_ * v) +-- We assume left-cancellation throughout this section for uniqueness of preimages under (_ * v) -- or (_ + v). /-- Turn a finite pattern into a configuration, by extending it with @@ -402,37 +368,37 @@ def Pattern.extendAtOrigin (p : Pattern A G) : G → A := by a configuration. On input `h : G`, we proceed as follows: -* if `h` lies in the right-translate of the support, i.e. `h ∈ p.support.image (· * v)`, - choose (noncomputably) `w ∈ p.support` with `w * v = h` and return `p.data ⟨w, _⟩`; +* if `h` lies in the left-translate of the support, i.e. `h ∈ p.support.image (v * ·)`, + choose (noncomputably) `w ∈ p.support` with `v * w = h` and return `p.data ⟨w, _⟩`; * otherwise return `default`. -This definition does not assume right-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.mulExtend p v (w * v) = p.data ⟨w, _⟩`) -require a right-cancellation hypothesis and are proved in separate lemmas. +This definition does not assume left-cancellation; it only *chooses* a preimage. +Uniqueness (and the usual equations such as `Pattern.mulExtend p v (v * w) = p.data ⟨w, _⟩`) +require a left-cancellation hypothesis and are proved in separate lemmas. -/ @[to_additive Pattern.extend /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. On input `h : G`, we proceed as follows: -* if `h` lies in the right-translate of the support, i.e. `h ∈ p.support.image (· + v)`, - choose (noncomputably) `w ∈ p.support` with `w + v = h` and return `p.data ⟨w, _⟩`; +* if `h` lies in the left-translate of the support, i.e. `h ∈ p.support.image (v + ·)`, + choose (noncomputably) `w ∈ p.support` with `v + w = h` and return `p.data ⟨w, _⟩`; * otherwise return `default`. -This definition does not assume right-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.extend p v (w + v) = p.data ⟨w, _⟩`) -require a right-cancellation hypothesis and are proved in separate lemmas. +This definition does not assume left-cancellation; it only *chooses* a preimage. +Uniqueness (and the usual equations such as `Pattern.extend p v (v + w) = p.data ⟨w, _⟩`) +require a left-cancellation hypothesis and are proved in separate lemmas. -/] noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := by classical intro h - if hmem : h ∈ p.support.image (· * v) then + if hmem : h ∈ p.support.image (v * ·) then -- package existence of a preimage under (_ * v) - let ex : ∃ w, w ∈ p.support ∧ w * v = h := by + let ex : ∃ w, w ∈ p.support ∧ v * w = h := by simpa [Finset.mem_image] using hmem let w := Classical.choose ex have hw : w ∈ p.support := (Classical.choose_spec ex).1 - have hwv : w * v = h := (Classical.choose_spec ex).2 + have hwv : v * w = h := (Classical.choose_spec ex).2 exact p.data ⟨w, hw⟩ else exact default @@ -454,39 +420,39 @@ def fromConfig (x : G → A) (U : Finset G) : Pattern A G where /-- On the translated support, `p.mulExtend v` agrees with `p` at the preimage. -More precisely, if `w ∈ p.support`, then at the translated site `w * v`, +More precisely, if `w ∈ p.support`, then at the translated site `v * w`, the configuration `p.mulExtend v` takes the value prescribed by `p` at `w`. -This uses `[IsRightCancelMul G]` to identify the unique preimage of `w * v` -under right-multiplication by `v`. -/ -@[to_additive extend_apply_add_right_of_mem +This uses `[IsLeftCancelMul G]` to identify the unique preimage of `v * w` +under left-multiplication by `v`. -/ +@[to_additive extend_apply_add_left_of_mem /-- On the translated support, `p.extend v` agrees with `p` at the preimage. - More precisely, if `w ∈ p.support`, then at the translated site `w + v`, + More precisely, if `w ∈ p.support`, then at the translated site `v + w`, the configuration `p.extend v` takes the value prescribed by `p` at `w`. - This uses `[IsRightCancelAdd G]` to identify the unique preimage of `w + v` - under right-translation by `v`. -/] -lemma mulExtend_apply_mul_right_of_mem + This uses `[IsLeftCancelAdd G]` to identify the unique preimage of `v + w` + under left-translation by `v`. -/] +lemma mulExtend_apply_mul_left_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : - p.mulExtend v (w * v) = p.data ⟨w, hw⟩ := by + p.mulExtend v (v * w) = p.data ⟨w, hw⟩ := by classical -- (w*v) is in the translated support - have hmem : (w * v) ∈ p.support.image (· * v) := + have hmem : (v * w) ∈ p.support.image (v * ·) := Finset.mem_image.mpr ⟨w, hw, rfl⟩ -- existential used in the branch - have ex : ∃ w', w' ∈ p.support ∧ w' * v = w * v := by + have ex : ∃ w', w' ∈ p.support ∧ v * w' = v * w := by simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition have h1 : - p.mulExtend v (w * v) + p.mulExtend v (v * w) = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := by simp [Pattern.mulExtend, hmem] - -- name the chosen witness and relate it to `w` by right-cancellation + -- name the chosen witness and relate it to `w` by left-cancellation let w' := Classical.choose ex have hw' : w' ∈ p.support := (Classical.choose_spec ex).1 - have hwv' : w' * v = w * v := (Classical.choose_spec ex).2 - have h_eq : w' = w := by simpa using (mul_right_cancel hwv') + have hwv' : v * w' = v * w := (Classical.choose_spec ex).2 + have h_eq : w' = w := by simpa using (mul_left_cancel hwv') -- transport membership along h_eq have hw_w : w ∈ p.support := by simpa [h_eq] using hw' -- identify the subtype inside `p.data` (first replace the value w' by w) @@ -501,7 +467,7 @@ lemma mulExtend_apply_mul_right_of_mem have h3 : (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := rfl -- put the rewrites together calc - p.mulExtend v (w * v) + p.mulExtend v (v * w) = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := h1 _ = p.data ⟨w, hw_w⟩ := by -- push h2 through `p.data` @@ -511,7 +477,6 @@ lemma mulExtend_apply_mul_right_of_mem -- push h3 through `p.data` simp [h3] - /-- Shifting a configuration commutes with occurrences of a pattern. Formally: a pattern `p` occurs in the shifted configuration `mulShift h x` at @@ -524,7 +489,7 @@ Formally: a pattern `p` occurs in the shifted configuration `shift h x` at position `g` if and only if it occurs in the original configuration `x` at position `g + h`. -/] lemma mulOccursInAt_mulShift {A G : Type*} [Monoid G] (p : Pattern A G) (x : G → A) (g h : G) : - p.mulOccursInAt (mulShift h x) g ↔ p.mulOccursInAt x (g * h) := by + p.mulOccursInAt (mulShift g x) h ↔ p.mulOccursInAt x (g * h) := by simp only [mulOccursInAt, mulShift_apply, mul_assoc] /-- Configurations that avoid a family `F` of patterns are stable under the shift. @@ -542,7 +507,7 @@ lemma mapsTo_mulShift_mulForbidden {A G : Type*} [Monoid G] (mulForbidden (A := A) (G := G) F) (mulForbidden F) := by -- unfold `MapsTo` intro x hx p hp g - specialize hx p hp (g * h) + specialize hx p hp (h * g) contrapose! hx simpa [mulOccursInAt_mulShift] using hx @@ -557,10 +522,10 @@ This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. Equivalently, `p.mulOccursInAt x g` iff on every translated site -`w * g` (with `w ∈ p.support`) +`g * w` (with `w ∈ p.support`) the configuration `x` agrees with the translated pattern `Pattern.mulExtend p g`. -(This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/ +(This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/ @[to_additive occursInAt_eq_cylinder /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations in which a pattern `p` occurs at position `g`. @@ -568,27 +533,27 @@ in which a pattern `p` occurs at position `g`. This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. -Equivalently, `p.occursInAt x g` iff on every translated site `w + g` (with `w ∈ p.support`) +Equivalently, `p.occursInAt x g` iff on every translated site `g + w` (with `w ∈ p.support`) the configuration `x` agrees with the translated pattern `Pattern.extend p g`. -(This uses `[IsRightCancelMul G]` to identify the preimage along right-multiplication by `g`.) -/] +(This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/] lemma mulOccursInAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.mulOccursInAt x g } = cylinder (p.support.image (· * g)) (p.mulExtend g) := by + { x | p.mulOccursInAt x g } = cylinder (p.support.image (g * ·)) (p.mulExtend g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ -- want: x (w*g) = Pattern.mulExtend p g (w*g) - have hx : x (w * g) = p.data ⟨w, hw⟩ := H w hw - simpa [Pattern.mulExtend_apply_mul_right_of_mem (p := p) (v := g) (w := w) hw] using hx + have hx : x (g * w) = p.data ⟨w, hw⟩ := H w hw + simpa [Pattern.mulExtend_apply_mul_left_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image - have hx : x (u * g) = p.mulExtend g (u * g) := - H (u * g) (Finset.mem_image_of_mem (· * g) hu) + have hx : x (g * u) = p.mulExtend g (g * u) := + H (g * u) (Finset.mem_image_of_mem (g * ·) hu) -- rewrite the RHS by the “apply_of_mem” lemma - simpa [Pattern.mulExtend_apply_mul_right_of_mem (p := p) (v := g) (w := u) hu] using hx + simpa [Pattern.mulExtend_apply_mul_left_of_mem (p := p) (v := g) (w := u) hu] using hx end OccursInAtEqCylinder end OccursInAt @@ -597,7 +562,7 @@ end OccursInAt section DefSubshiftByForbidden variable {A : Type*} [TopologicalSpace A] [Inhabited A] -variable {G : Type*} [Monoid G] [IsRightCancelMul G] +variable {G : Type*} [Monoid G] [IsLeftCancelMul G] /-- Occurrence sets are open. -/ @[to_additive isOpen_occursInAt] From d0757f0dca179cfcbc18bfe4d1c5f1b6c7f6f08a Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 9 Apr 2026 15:38:19 +0900 Subject: [PATCH 83/93] trigger CI retry for leantar issue From 21a42e12abb8cc9547b7ff715a096a14430bd7de Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 9 Apr 2026 18:17:44 +0900 Subject: [PATCH 84/93] Removed Fintype A hypothesis from finite_setOf_pattern_support_eq --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 27 +++++++++----------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 57940304a84e45..8c8b23491a8ef3 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -652,11 +652,16 @@ variable {G : Type*} /-- Patterns with support exactly `U` form a finite set. -/ lemma finite_setOf_pattern_support_eq - {A G : Type*} [Fintype A] + {A G : Type*} [Finite A] (U : Finset G) : ({p : Pattern A G | p.support = U}).Finite := by + -- 1. Upgrade Finite A to Fintype A locally + cases nonempty_fintype A + -- 2. Explicitly provide the Fintype instance for the Finset U + -- This is often the missing link for the (U → A) synthesis + letI : Fintype U := U.fintypeCoeSort classical - -- Local equivalence between the subtype and functions on U + -- Now Lean should be able to synthesize Fintype (U → A) let e : { p : Pattern A G // p.support = U } ≃ (U → A) := { toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ @@ -666,27 +671,19 @@ lemma finite_setOf_pattern_support_eq cases hU rfl right_inv := fun _ => rfl} - -- Give a Fintype structure to the subtype via this equivalence + -- Now this should synthesize without issue haveI : Fintype { p : Pattern A G // p.support = U } := Fintype.ofEquiv (U → A) e.symm - -- Now prove finiteness of `{ p : Pattern A G | p.support = U }` by - -- viewing it as the image of `univ` in that finite subtype let T := { p : Pattern A G // p.support = U } - have h_univ : (Set.univ : Set T).Finite := - Set.finite_univ + have h_univ : (Set.univ : Set T).Finite := Set.finite_univ let coeT : T → Pattern A G := fun p => (p : Pattern A G) - have h_image : (Set.image coeT (Set.univ : Set T)).Finite := - h_univ.image _ + have h_image : (Set.image coeT (Set.univ : Set T)).Finite := h_univ.image _ have himage_eq : Set.image coeT (Set.univ : Set T) = ({ p : Pattern A G | p.support = U } : Set (Pattern A G)) := by ext p; constructor - · intro hp - rcases hp with ⟨p', -, rfl⟩ - exact p'.property - · intro hp - refine ⟨⟨p, hp⟩, ?_, rfl⟩ - simp + · intro hp; rcases hp with ⟨p', -, rfl⟩; exact p'.property + · intro hp; refine ⟨⟨p, hp⟩, ?_, rfl⟩; simp simpa [himage_eq] using h_image /-- The language of a set of configurations `X` on a finite shape `U`. From 93dd40b9e8107f1c5b810d8df28a975adddb05b6 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Thu, 9 Apr 2026 18:24:52 +0900 Subject: [PATCH 85/93] pattern extension at origin --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 21 -------------------- 1 file changed, 21 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 8c8b23491a8ef3..9e48edf99808ec 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -343,27 +343,6 @@ variable {A : Type*} [Inhabited A] variable {G : Type*} [Monoid G] [IsLeftCancelMul G] section PatternExtension --- We assume left-cancellation throughout this section for uniqueness of preimages under (_ * v) --- or (_ + v). - -/-- Turn a finite pattern into a configuration, by extending it with -the default symbol outside its support. - -Formally: given a pattern `p` with finite support in `G`, we define a configuration -`Pattern.extendAtOrigin p : G → A` by setting -* `Pattern.extendAtOrigin p i = p.data ⟨i, h⟩` if `i ∈ p.support`, -* `Pattern.extendAtOrigin p i = default` otherwise. - -This produces a canonical "completion" of the pattern to a configuration, -filling all unspecified positions with `default`. -/ -def Pattern.extendAtOrigin (p : Pattern A G) : G → A := by - classical - exact fun i ↦ - if h : i ∈ p.support then - p.data ⟨i, h⟩ - else - default - /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. From 9808842e4073c082a169f424b2234768fa7bf4d6 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Fri, 10 Apr 2026 13:54:52 +0900 Subject: [PATCH 86/93] refactor Pattern definition --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 194 +++++++++---------- 1 file changed, 87 insertions(+), 107 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 9e48edf99808ec..f4bc2e8cb7cac0 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -48,7 +48,8 @@ so that the theory works not only for groups but also for cancellative monoids. * `shift g x` — left translation: in additive notation `(shift v x) u = x (v + u)` (using the **left** action of `G` on configurations). * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. -* `Pattern A G` — finite support together with values on that support. +* `Pattern A G` — a configuration which takes +default value outside of a finite domain, together with this domain. * `Pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. * `forbidden F` — configurations avoiding every pattern in `F`. * `Subshift A G` — closed, shift-invariant subsets of the full shift. @@ -274,46 +275,49 @@ def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : MulSubshift A G where /-- A *pattern* is a finite configuration in the full shift `A^G`. It consists of: -* a finite subset `support : Finset G` of coordinates, called the support of `p`; -* an assignment `data : support → A` of symbols to each point in the support. +* a full configuration `config : G → A` in the full shift; +* a finite subset `domain : Finset G` of coordinates, called the domain of `p`; +* a proof `condition` that outside `domain`, `config` takes the default value of `A`. -Intuitively, a pattern is a "partial configuration" (like a finite word), -specifying finitely many values of a configuration in `G → A`. Patterns are -the basic building blocks used to define subshifts via forbidden configurations. +Intuitively, a pattern is a "partial configuration" specifying finitely many values of +a configuration in `G → A` (the rest being `default`). +Patterns are the basic building blocks used to define subshifts via forbidden configurations. Note that each pattern corresponds to a cylinder, which is the set of configurations -which agree with this pattern on its support. -/ -structure Pattern (A : Type*) (G : Type*) where - /-- Finite support of the pattern. -/ - support : Finset G - /-- The value (symbol) at each point of the support. -/ - data : support → A +which agree with this pattern on its domain. -/ +structure Pattern (A : Type*) (G : Type*) [Inhabited A] where + /-- The full configuration in the full shift `A^G`. -/ + config : G → A + /-- Finite domain of the pattern. -/ + domain : Finset G + /-- Outside the domain, `config` takes the default value of `A`. -/ + condition : ∀ g ∉ domain, config g = default section Forbidden -variable {A G : Type*} [Monoid G] +variable {A G : Type*} [Inhabited A] [Monoid G] /-- `p.mulOccursInAt x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. -Formally: for every position `h` in the support of `p`, the value of the configuration -at `g * h` coincides with the value specified by `p` at `h`. +Formally: for every position `h` in the domain of `p`, the value of the configuration +at `g * h` coincides with the value of `p.config` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), -then on the support of `p` you exactly recover the pattern `p`. This is the basic +then on the domain of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ @[to_additive Pattern.occursInAt /-- `p.occursInAt x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. -Formally: for every position `h` in the support of `p`, the value of the configuration -at `g + h` coincides with the value specified by `p` at `h`. +Formally: for every position `h` in the domain of `p`, the value of the configuration +at `g + h` coincides with the value of `p.config` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `shift g`), -then on the support of `p` you exactly recover the pattern `p`. This is the basic +then on the domain of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/] def Pattern.mulOccursInAt (p : Pattern A G) (x : G → A) (g : G) : Prop := - ∀ (h) (hh : h ∈ p.support), x (g * h) = p.data ⟨h, hh⟩ + ∀ (h) (_ : h ∈ p.domain), x (g * h) = p.config h /-- `mulForbidden F` is the set of configurations that avoid every pattern in `F`. @@ -347,12 +351,12 @@ section PatternExtension a configuration. On input `h : G`, we proceed as follows: -* if `h` lies in the left-translate of the support, i.e. `h ∈ p.support.image (v * ·)`, - choose (noncomputably) `w ∈ p.support` with `v * w = h` and return `p.data ⟨w, _⟩`; +* if `h` lies in the left-translate of the domain, i.e. `h ∈ p.domain.image (v * ·)`, + choose (noncomputably) `w ∈ p.domain` with `v * w = h` and return `p.config w`; * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.mulExtend p v (v * w) = p.data ⟨w, _⟩`) +Uniqueness (and the usual equations such as `Pattern.mulExtend p v (v * w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/ @[to_additive Pattern.extend @@ -360,25 +364,22 @@ require a left-cancellation hypothesis and are proved in separate lemmas. a configuration. On input `h : G`, we proceed as follows: -* if `h` lies in the left-translate of the support, i.e. `h ∈ p.support.image (v + ·)`, - choose (noncomputably) `w ∈ p.support` with `v + w = h` and return `p.data ⟨w, _⟩`; +* if `h` lies in the left-translate of the domain, i.e. `h ∈ p.domain.image (v + ·)`, + choose (noncomputably) `w ∈ p.domain` with `v + w = h` and return `p.config w`; * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.extend p v (v + w) = p.data ⟨w, _⟩`) +Uniqueness (and the usual equations such as `Pattern.extend p v (v + w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/] noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := by classical intro h - if hmem : h ∈ p.support.image (v * ·) then - -- package existence of a preimage under (_ * v) - let ex : ∃ w, w ∈ p.support ∧ v * w = h := by + if hmem : h ∈ p.domain.image (v * ·) then + -- package existence of a preimage under (v * ·) + let ex : ∃ w, w ∈ p.domain ∧ v * w = h := by simpa [Finset.mem_image] using hmem - let w := Classical.choose ex - have hw : w ∈ p.support := (Classical.choose_spec ex).1 - have hwv : v * w = h := (Classical.choose_spec ex).2 - exact p.data ⟨w, hw⟩ + exact p.config (Classical.choose ex) else exact default end PatternExtension @@ -387,74 +388,47 @@ namespace Pattern /-- Extract the finite pattern given by restricting a configuration `x : G → A` to a finite subset `U : Finset G`. -Formally: the support is `U`, and for each `i ∈ U` the pattern records the value -`x i`. In other words, `Pattern.fromConfig x U` is the partial configuration of -`x` visible on the coordinates in `U`. - -This is the inverse construction to `Pattern.extendAtOrigin` (which extends a -finite pattern to a configuration by filling with `default`). -/ -def fromConfig (x : G → A) (U : Finset G) : Pattern A G where - support := U - data := fun i => x i.1 +The pattern has `config g = x g` for `g ∈ U` and `config g = default` outside `U`, +with domain `U`. In other words, `Pattern.fromConfig x U` is the partial configuration of +`x` visible on the coordinates in `U`, padded with `default` elsewhere. -/ +noncomputable def fromConfig (x : G → A) (U : Finset G) : Pattern A G := by + classical + exact { config := fun g => if g ∈ U then x g else default, + domain := U, + condition := fun g hg => if_neg hg } -/-- On the translated support, `p.mulExtend v` agrees with `p` at the preimage. +/-- On the translated domain, `p.mulExtend v` agrees with `p.config` at the preimage. -More precisely, if `w ∈ p.support`, then at the translated site `v * w`, -the configuration `p.mulExtend v` takes the value prescribed by `p` at `w`. +More precisely, if `w ∈ p.domain`, then at the translated site `v * w`, +the configuration `p.mulExtend v` takes the value `p.config w`. This uses `[IsLeftCancelMul G]` to identify the unique preimage of `v * w` under left-multiplication by `v`. -/ @[to_additive extend_apply_add_left_of_mem - /-- On the translated support, `p.extend v` agrees with `p` at the preimage. + /-- On the translated domain, `p.extend v` agrees with `p.config` at the preimage. - More precisely, if `w ∈ p.support`, then at the translated site `v + w`, - the configuration `p.extend v` takes the value prescribed by `p` at `w`. + More precisely, if `w ∈ p.domain`, then at the translated site `v + w`, + the configuration `p.extend v` takes the value `p.config w`. This uses `[IsLeftCancelAdd G]` to identify the unique preimage of `v + w` under left-translation by `v`. -/] lemma mulExtend_apply_mul_left_of_mem - (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : - p.mulExtend v (v * w) = p.data ⟨w, hw⟩ := by + (p : Pattern A G) (v w : G) (hw : w ∈ p.domain) : + p.mulExtend v (v * w) = p.config w := by classical - -- (w*v) is in the translated support - have hmem : (v * w) ∈ p.support.image (v * ·) := + -- (v * w) is in the translated domain + have hmem : (v * w) ∈ p.domain.image (v * ·) := Finset.mem_image.mpr ⟨w, hw, rfl⟩ -- existential used in the branch - have ex : ∃ w', w' ∈ p.support ∧ v * w' = v * w := by + have ex : ∃ w', w' ∈ p.domain ∧ v * w' = v * w := by simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition - have h1 : - p.mulExtend v (v * w) - = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := by + have h1 : p.mulExtend v (v * w) = p.config (Classical.choose ex) := by simp [Pattern.mulExtend, hmem] - -- name the chosen witness and relate it to `w` by left-cancellation - let w' := Classical.choose ex - have hw' : w' ∈ p.support := (Classical.choose_spec ex).1 - have hwv' : v * w' = v * w := (Classical.choose_spec ex).2 - have h_eq : w' = w := by simpa using (mul_left_cancel hwv') - -- transport membership along h_eq - have hw_w : w ∈ p.support := by simpa [h_eq] using hw' - -- identify the subtype inside `p.data` (first replace the value w' by w) - have h2 : - (⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ : p.support) - = (⟨w, hw_w⟩ : p.support) := by - apply Subtype.ext - -- goal: Classical.choose ex = w - -- we have h_eq : w' = w and w' := Classical.choose ex - simpa [w'] using h_eq -- <-- use `using h_eq`, only unfold `[w']` - -- then replace the proof component (same carrier w) - have h3 : (⟨w, hw_w⟩ : p.support) = (⟨w, hw⟩ : p.support) := rfl - -- put the rewrites together - calc - p.mulExtend v (v * w) - = p.data ⟨Classical.choose ex, (Classical.choose_spec ex).1⟩ := h1 - _ = p.data ⟨w, hw_w⟩ := by - -- push h2 through `p.data` - simpa using - (congrArg (fun z : {x // x ∈ p.support} => p.data z) h2) - _ = p.data ⟨w, hw⟩ := by - -- push h3 through `p.data` - simp [h3] + -- the chosen witness equals w by left-cancellation + have hwv' : v * Classical.choose ex = v * w := (Classical.choose_spec ex).2 + have h_eq : Classical.choose ex = w := mul_left_cancel hwv' + rw [h1, h_eq] /-- Shifting a configuration commutes with occurrences of a pattern. @@ -467,9 +441,10 @@ position `g * h`. -/ Formally: a pattern `p` occurs in the shifted configuration `shift h x` at position `g` if and only if it occurs in the original configuration `x` at position `g + h`. -/] -lemma mulOccursInAt_mulShift {A G : Type*} [Monoid G] (p : Pattern A G) (x : G → A) (g h : G) : +lemma mulOccursInAt_mulShift {A G : Type*} [Inhabited A] [Monoid G] + (p : Pattern A G) (x : G → A) (g h : G) : p.mulOccursInAt (mulShift g x) h ↔ p.mulOccursInAt x (g * h) := by - simp only [mulOccursInAt, mulShift_apply, mul_assoc] + simp only [Pattern.mulOccursInAt, mulShift_apply, mul_assoc] /-- Configurations that avoid a family `F` of patterns are stable under the shift. @@ -480,7 +455,7 @@ the shifted configuration `mulShift h x` also avoids every `p ∈ F` at every po Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] -lemma mapsTo_mulShift_mulForbidden {A G : Type*} [Monoid G] +lemma mapsTo_mulShift_mulForbidden {A G : Type*} [Inhabited A] [Monoid G] (F : Set (Pattern A G)) (h : G) : Set.MapsTo (fun x => mulShift h x) (mulForbidden (A := A) (G := G) F) (mulForbidden F) := by @@ -518,13 +493,13 @@ the configuration `x` agrees with the translated pattern `Pattern.extend p g`. (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/] lemma mulOccursInAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.mulOccursInAt x g } = cylinder (p.support.image (g * ·)) (p.mulExtend g) := by + { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulExtend g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ - -- want: x (w*g) = Pattern.mulExtend p g (w*g) - have hx : x (g * w) = p.data ⟨w, hw⟩ := H w hw + -- want: x ( w * g) = Pattern.mulExtend p g ( w * g) + have hx : x (g * w) = p.config w := H w hw simpa [Pattern.mulExtend_apply_mul_left_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu @@ -626,40 +601,45 @@ end DefSubshiftByForbidden section Language -variable {A : Type*} [Fintype A] +variable {A : Type*} [Fintype A] [Inhabited A] variable {G : Type*} -/-- Patterns with support exactly `U` form a finite set. -/ +/-- Patterns with domain exactly `U` form a finite set. -/ lemma finite_setOf_pattern_support_eq - {A G : Type*} [Finite A] + {A G : Type*} [Finite A] [Inhabited A] (U : Finset G) : - ({p : Pattern A G | p.support = U}).Finite := by + ({p : Pattern A G | p.domain = U}).Finite := by -- 1. Upgrade Finite A to Fintype A locally cases nonempty_fintype A -- 2. Explicitly provide the Fintype instance for the Finset U - -- This is often the missing link for the (U → A) synthesis letI : Fintype U := U.fintypeCoeSort classical - -- Now Lean should be able to synthesize Fintype (U → A) - let e : { p : Pattern A G // p.support = U } ≃ (U → A) := - { toFun := fun p i => p.1.data ⟨i.1, by simp [p.2]⟩ - invFun := fun f => ⟨{ support := U, data := f }, rfl⟩ + -- Patterns with domain U biject with (U → A) via restriction/extension + let e : { p : Pattern A G // p.domain = U } ≃ (U → A) := + { toFun := fun p i => p.1.config i.1 + invFun := fun f => ⟨{ config := fun g => if h : g ∈ U then f ⟨g, h⟩ else default, + domain := U, + condition := fun g hg => by simp [hg] }, rfl⟩ left_inv := by - rintro ⟨p, hU⟩ + rintro ⟨⟨cfg, dom, cond⟩, hU⟩ + simp only at hU; subst hU apply Subtype.ext - cases hU - rfl - right_inv := fun _ => rfl} + simp only [Pattern.mk.injEq, and_true] + funext g + by_cases hg : g ∈ dom + · simp [hg] + · simp [hg, cond g hg] + right_inv := fun f => by ext i; simp [i.2] } -- Now this should synthesize without issue - haveI : Fintype { p : Pattern A G // p.support = U } := + haveI : Fintype { p : Pattern A G // p.domain = U } := Fintype.ofEquiv (U → A) e.symm - let T := { p : Pattern A G // p.support = U } + let T := { p : Pattern A G // p.domain = U } have h_univ : (Set.univ : Set T).Finite := Set.finite_univ let coeT : T → Pattern A G := fun p => (p : Pattern A G) have h_image : (Set.image coeT (Set.univ : Set T)).Finite := h_univ.image _ have himage_eq : Set.image coeT (Set.univ : Set T) - = ({ p : Pattern A G | p.support = U } : Set (Pattern A G)) := by + = ({ p : Pattern A G | p.domain = U } : Set (Pattern A G)) := by ext p; constructor · intro hp; rcases hp with ⟨p', -, rfl⟩; exact p'.property · intro hp; refine ⟨⟨p, hp⟩, ?_, rfl⟩; simp @@ -673,7 +653,7 @@ def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, Pattern.fromConfig x U = p } /-- The language of a subshift `Y` on a finite shape `U`. -/ -def MulSubshift.languageOn {A G} [TopologicalSpace A] [Monoid G] +def MulSubshift.languageOn {A G} [TopologicalSpace A] [Inhabited A] [Monoid G] (Y : MulSubshift A G) (U : Finset G) : Set (Pattern A G) := SymbolicDynamics.FullShift.mulLanguageOn (A := A) (G := G) Y.carrier U From e98d2973661c08064ec5589f0e96f06bdc1dc25b Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Fri, 10 Apr 2026 14:12:54 +0900 Subject: [PATCH 87/93] remove section Patternextension --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index f4bc2e8cb7cac0..2552c0f4a5fa86 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -346,7 +346,6 @@ section OccursInAt variable {A : Type*} [Inhabited A] variable {G : Type*} [Monoid G] [IsLeftCancelMul G] -section PatternExtension /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. @@ -382,7 +381,6 @@ noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := by exact p.config (Classical.choose ex) else exact default -end PatternExtension namespace Pattern /-- Extract the finite pattern given by restricting a configuration `x : G → A` From 39d56ff372da27304bedf9d3c1d8c516176d9f3e Mon Sep 17 00:00:00 2001 From: Sfgangloff <37847888+Sfgangloff@users.noreply.github.com> Date: Mon, 27 Apr 2026 09:33:08 +0900 Subject: [PATCH 88/93] Update Mathlib/Dynamics/SymbolicDynamics/Basic.lean Co-authored-by: Sebastien Gouezel --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 2552c0f4a5fa86..54cd523eba9c70 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -455,8 +455,7 @@ Formally: if `x` avoids every `p ∈ F` at every position, then for any `h : G`, the shifted configuration `shift h x` also avoids every `p ∈ F` at every position. -/] lemma mapsTo_mulShift_mulForbidden {A G : Type*} [Inhabited A] [Monoid G] (F : Set (Pattern A G)) (h : G) : - Set.MapsTo (fun x => mulShift h x) - (mulForbidden (A := A) (G := G) F) (mulForbidden F) := by + Set.MapsTo (mulShift h) (mulForbidden (A := A) (G := G) F) (mulForbidden F) := by -- unfold `MapsTo` intro x hx p hp g specialize hx p hp (h * g) From 5b5cf6d16f7d5e325152e9d6c7d993d3fc257e88 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Mon, 27 Apr 2026 09:45:20 +0900 Subject: [PATCH 89/93] mulExtend -> mulShiftExtend + remove section OccursInAtEqCylinder --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 42 ++++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 54cd523eba9c70..83d6c31b29f129 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -39,7 +39,7 @@ Some constructions, such as translating a finite pattern to occur at a point `v` require solving equations of the form `w + v = h`. For this to have a unique solution `w` given `h` and `v`, we assume **left-cancellation**: if `v + a = v + b` then `a = b`. This allows us to define -`Pattern.extend` (which extends a pattern into a configuration +`Pattern.shiftExtend` (which extends a pattern into a configuration using the default value of `A`) without using inverses, so that the theory works not only for groups but also for cancellative monoids. @@ -355,10 +355,10 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.mulExtend p v (v * w) = p.config w`) +Uniqueness (and the usual equations such as `Pattern.mulShiftExtend p v (v * w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/ -@[to_additive Pattern.extend +@[to_additive /-- Translate a finite pattern `p` so that it occurs at the translate `v`, before completing into a configuration. @@ -368,10 +368,10 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.extend p v (v + w) = p.config w`) +Uniqueness (and the usual equations such as `Pattern.shiftExtend p v (v + w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/] -noncomputable def Pattern.mulExtend (p : Pattern A G) (v : G) : G → A := by +noncomputable def Pattern.mulShiftExtend (p : Pattern A G) (v : G) : G → A := by classical intro h if hmem : h ∈ p.domain.image (v * ·) then @@ -395,24 +395,24 @@ noncomputable def fromConfig (x : G → A) (U : Finset G) : Pattern A G := by domain := U, condition := fun g hg => if_neg hg } -/-- On the translated domain, `p.mulExtend v` agrees with `p.config` at the preimage. +/-- On the translated domain, `p.mulShiftExtend v` agrees with `p.config` at the preimage. More precisely, if `w ∈ p.domain`, then at the translated site `v * w`, -the configuration `p.mulExtend v` takes the value `p.config w`. +the configuration `p.mulShiftExtend v` takes the value `p.config w`. This uses `[IsLeftCancelMul G]` to identify the unique preimage of `v * w` under left-multiplication by `v`. -/ @[to_additive extend_apply_add_left_of_mem - /-- On the translated domain, `p.extend v` agrees with `p.config` at the preimage. + /-- On the translated domain, `p.shiftExtend v` agrees with `p.config` at the preimage. More precisely, if `w ∈ p.domain`, then at the translated site `v + w`, - the configuration `p.extend v` takes the value `p.config w`. + the configuration `p.shiftExtend v` takes the value `p.config w`. This uses `[IsLeftCancelAdd G]` to identify the unique preimage of `v + w` under left-translation by `v`. -/] -lemma mulExtend_apply_mul_left_of_mem +lemma mulShiftExtend_apply_mul_left_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.domain) : - p.mulExtend v (v * w) = p.config w := by + p.mulShiftExtend v (v * w) = p.config w := by classical -- (v * w) is in the translated domain have hmem : (v * w) ∈ p.domain.image (v * ·) := @@ -421,8 +421,8 @@ lemma mulExtend_apply_mul_left_of_mem have ex : ∃ w', w' ∈ p.domain ∧ v * w' = v * w := by simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition - have h1 : p.mulExtend v (v * w) = p.config (Classical.choose ex) := by - simp [Pattern.mulExtend, hmem] + have h1 : p.mulShiftExtend v (v * w) = p.config (Classical.choose ex) := by + simp [Pattern.mulShiftExtend, hmem] -- the chosen witness equals w by left-cancellation have hwv' : v * Classical.choose ex = v * w := (Classical.choose_spec ex).2 have h_eq : Classical.choose ex = w := mul_left_cancel hwv' @@ -464,7 +464,6 @@ lemma mapsTo_mulShift_mulForbidden {A G : Type*} [Inhabited A] [Monoid G] end Pattern -section OccursInAtEqCylinder open scoped Classical in /-- We call *occurrence set* for pattern `p` and position `g` the set of configurations in which a pattern `p` occurs at position `g`. @@ -474,7 +473,7 @@ pattern obtained by translating `p` by `g`. Equivalently, `p.mulOccursInAt x g` iff on every translated site `g * w` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `Pattern.mulExtend p g`. +the configuration `x` agrees with the translated pattern `Pattern.mulShiftExtend p g`. (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/ @[to_additive occursInAt_eq_cylinder @@ -485,27 +484,26 @@ This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. Equivalently, `p.occursInAt x g` iff on every translated site `g + w` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `Pattern.extend p g`. +the configuration `x` agrees with the translated pattern `Pattern.shiftExtend p g`. (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/] lemma mulOccursInAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulExtend g) := by + { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulShiftExtend g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ - -- want: x ( w * g) = Pattern.mulExtend p g ( w * g) + -- want: x ( w * g) = Pattern.mulShiftExtend p g ( w * g) have hx : x (g * w) = p.config w := H w hw - simpa [Pattern.mulExtend_apply_mul_left_of_mem (p := p) (v := g) (w := w) hw] using hx + simpa [Pattern.mulShiftExtend_apply_mul_left_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image - have hx : x (g * u) = p.mulExtend g (g * u) := + have hx : x (g * u) = p.mulShiftExtend g (g * u) := H (g * u) (Finset.mem_image_of_mem (g * ·) hu) -- rewrite the RHS by the “apply_of_mem” lemma - simpa [Pattern.mulExtend_apply_mul_left_of_mem (p := p) (v := g) (w := u) hu] using hx -end OccursInAtEqCylinder + simpa [Pattern.mulShiftExtend_apply_mul_left_of_mem (p := p) (v := g) (w := u) hu] using hx end OccursInAt /-! ## Forbidden sets and subshifts -/ From db7329c7b64299c398ba5399af2d7e5246c5c86a Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Mon, 27 Apr 2026 16:20:57 +0900 Subject: [PATCH 90/93] rename mulShiftExtend to mulPseudoShift --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 83d6c31b29f129..7b8ed5e05637a9 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -355,7 +355,7 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.mulShiftExtend p v (v * w) = p.config w`) +Uniqueness (and the usual equations such as `Pattern.mulPseudoShift p v (v * w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/ @[to_additive @@ -371,7 +371,7 @@ This definition does not assume left-cancellation; it only *chooses* a preimage. Uniqueness (and the usual equations such as `Pattern.shiftExtend p v (v + w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/] -noncomputable def Pattern.mulShiftExtend (p : Pattern A G) (v : G) : G → A := by +noncomputable def Pattern.mulPseudoShift (p : Pattern A G) (v : G) : G → A := by classical intro h if hmem : h ∈ p.domain.image (v * ·) then @@ -395,10 +395,10 @@ noncomputable def fromConfig (x : G → A) (U : Finset G) : Pattern A G := by domain := U, condition := fun g hg => if_neg hg } -/-- On the translated domain, `p.mulShiftExtend v` agrees with `p.config` at the preimage. +/-- On the translated domain, `p.mulPseudoShift v` agrees with `p.config` at the preimage. More precisely, if `w ∈ p.domain`, then at the translated site `v * w`, -the configuration `p.mulShiftExtend v` takes the value `p.config w`. +the configuration `p.mulPseudoShift v` takes the value `p.config w`. This uses `[IsLeftCancelMul G]` to identify the unique preimage of `v * w` under left-multiplication by `v`. -/ @@ -412,7 +412,7 @@ under left-multiplication by `v`. -/ under left-translation by `v`. -/] lemma mulShiftExtend_apply_mul_left_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.domain) : - p.mulShiftExtend v (v * w) = p.config w := by + p.mulPseudoShift v (v * w) = p.config w := by classical -- (v * w) is in the translated domain have hmem : (v * w) ∈ p.domain.image (v * ·) := @@ -421,8 +421,8 @@ lemma mulShiftExtend_apply_mul_left_of_mem have ex : ∃ w', w' ∈ p.domain ∧ v * w' = v * w := by simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition - have h1 : p.mulShiftExtend v (v * w) = p.config (Classical.choose ex) := by - simp [Pattern.mulShiftExtend, hmem] + have h1 : p.mulPseudoShift v (v * w) = p.config (Classical.choose ex) := by + simp [Pattern.mulPseudoShift, hmem] -- the chosen witness equals w by left-cancellation have hwv' : v * Classical.choose ex = v * w := (Classical.choose_spec ex).2 have h_eq : Classical.choose ex = w := mul_left_cancel hwv' @@ -473,7 +473,7 @@ pattern obtained by translating `p` by `g`. Equivalently, `p.mulOccursInAt x g` iff on every translated site `g * w` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `Pattern.mulShiftExtend p g`. +the configuration `x` agrees with the translated pattern `Pattern.mulPseudoShift p g`. (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/ @[to_additive occursInAt_eq_cylinder @@ -489,18 +489,18 @@ the configuration `x` agrees with the translated pattern `Pattern.shiftExtend p (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/] lemma mulOccursInAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulShiftExtend g) := by + { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulPseudoShift g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ - -- want: x ( w * g) = Pattern.mulShiftExtend p g ( w * g) + -- want: x ( w * g) = Pattern.mulPseudoShift p g ( w * g) have hx : x (g * w) = p.config w := H w hw simpa [Pattern.mulShiftExtend_apply_mul_left_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image - have hx : x (g * u) = p.mulShiftExtend g (g * u) := + have hx : x (g * u) = p.mulPseudoShift g (g * u) := H (g * u) (Finset.mem_image_of_mem (g * ·) hu) -- rewrite the RHS by the “apply_of_mem” lemma simpa [Pattern.mulShiftExtend_apply_mul_left_of_mem (p := p) (v := g) (w := u) hu] using hx From 12695a20883200ec4d18a96c5cff35820ab458b7 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Tue, 28 Apr 2026 10:45:49 +0900 Subject: [PATCH 91/93] pseudoshift -> shift and protected keyword added, extend deleted --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 41 ++++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 7b8ed5e05637a9..00347a787becdb 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -39,8 +39,7 @@ Some constructions, such as translating a finite pattern to occur at a point `v` require solving equations of the form `w + v = h`. For this to have a unique solution `w` given `h` and `v`, we assume **left-cancellation**: if `v + a = v + b` then `a = b`. This allows us to define -`Pattern.shiftExtend` (which extends a pattern into a configuration -using the default value of `A`) without using inverses, +`Pattern.shift` (which shifts a pattern) without using inverses, so that the theory works not only for groups but also for cancellative monoids. ## Main definitions @@ -355,7 +354,7 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.mulPseudoShift p v (v * w) = p.config w`) +Uniqueness (and the usual equations such as `Pattern.mulShift p v (v * w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/ @[to_additive @@ -368,10 +367,10 @@ On input `h : G`, we proceed as follows: * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. -Uniqueness (and the usual equations such as `Pattern.shiftExtend p v (v + w) = p.config w`) +Uniqueness (and the usual equations such as `Pattern.shift p v (v + w) = p.config w`) require a left-cancellation hypothesis and are proved in separate lemmas. -/] -noncomputable def Pattern.mulPseudoShift (p : Pattern A G) (v : G) : G → A := by +protected noncomputable def Pattern.mulShift (p : Pattern A G) (v : G) : G → A := by classical intro h if hmem : h ∈ p.domain.image (v * ·) then @@ -395,24 +394,24 @@ noncomputable def fromConfig (x : G → A) (U : Finset G) : Pattern A G := by domain := U, condition := fun g hg => if_neg hg } -/-- On the translated domain, `p.mulPseudoShift v` agrees with `p.config` at the preimage. +/-- On the translated domain, `p.mulShift v` agrees with `p.config` at the preimage. More precisely, if `w ∈ p.domain`, then at the translated site `v * w`, -the configuration `p.mulPseudoShift v` takes the value `p.config w`. +the configuration `p.mulShift v` takes the value `p.config w`. This uses `[IsLeftCancelMul G]` to identify the unique preimage of `v * w` under left-multiplication by `v`. -/ -@[to_additive extend_apply_add_left_of_mem - /-- On the translated domain, `p.shiftExtend v` agrees with `p.config` at the preimage. +@[to_additive + /-- On the translated domain, `p.shift v` agrees with `p.config` at the preimage. More precisely, if `w ∈ p.domain`, then at the translated site `v + w`, - the configuration `p.shiftExtend v` takes the value `p.config w`. + the configuration `p.shift v` takes the value `p.config w`. This uses `[IsLeftCancelAdd G]` to identify the unique preimage of `v + w` under left-translation by `v`. -/] -lemma mulShiftExtend_apply_mul_left_of_mem +lemma mulShift_apply_mul_left_of_mem (p : Pattern A G) (v w : G) (hw : w ∈ p.domain) : - p.mulPseudoShift v (v * w) = p.config w := by + p.mulShift v (v * w) = p.config w := by classical -- (v * w) is in the translated domain have hmem : (v * w) ∈ p.domain.image (v * ·) := @@ -421,8 +420,8 @@ lemma mulShiftExtend_apply_mul_left_of_mem have ex : ∃ w', w' ∈ p.domain ∧ v * w' = v * w := by simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition - have h1 : p.mulPseudoShift v (v * w) = p.config (Classical.choose ex) := by - simp [Pattern.mulPseudoShift, hmem] + have h1 : p.mulShift v (v * w) = p.config (Classical.choose ex) := by + simp [Pattern.mulShift, hmem] -- the chosen witness equals w by left-cancellation have hwv' : v * Classical.choose ex = v * w := (Classical.choose_spec ex).2 have h_eq : Classical.choose ex = w := mul_left_cancel hwv' @@ -473,7 +472,7 @@ pattern obtained by translating `p` by `g`. Equivalently, `p.mulOccursInAt x g` iff on every translated site `g * w` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `Pattern.mulPseudoShift p g`. +the configuration `x` agrees with the translated pattern `Pattern.mulShift p g`. (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/ @[to_additive occursInAt_eq_cylinder @@ -484,26 +483,26 @@ This proves that it is exactly the cylinder corresponding to the pattern obtained by translating `p` by `g`. Equivalently, `p.occursInAt x g` iff on every translated site `g + w` (with `w ∈ p.support`) -the configuration `x` agrees with the translated pattern `Pattern.shiftExtend p g`. +the configuration `x` agrees with the translated pattern `Pattern.shift p g`. (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/] lemma mulOccursInAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulPseudoShift g) := by + { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulShift g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu rcases Finset.mem_image.mp hu with ⟨w, hw, rfl⟩ - -- want: x ( w * g) = Pattern.mulPseudoShift p g ( w * g) + -- want: x ( w * g) = Pattern.mulShift p g ( w * g) have hx : x (g * w) = p.config w := H w hw - simpa [Pattern.mulShiftExtend_apply_mul_left_of_mem (p := p) (v := g) (w := w) hw] using hx + simpa [Pattern.mulShift_apply_mul_left_of_mem (p := p) (v := g) (w := w) hw] using hx · -- ⇐: from the cylinder, recover an occurrence intro H u hu -- H gives equality with the translated pattern on the image - have hx : x (g * u) = p.mulPseudoShift g (g * u) := + have hx : x (g * u) = p.mulShift g (g * u) := H (g * u) (Finset.mem_image_of_mem (g * ·) hu) -- rewrite the RHS by the “apply_of_mem” lemma - simpa [Pattern.mulShiftExtend_apply_mul_left_of_mem (p := p) (v := g) (w := u) hu] using hx + simpa [Pattern.mulShift_apply_mul_left_of_mem (p := p) (v := g) (w := u) hu] using hx end OccursInAt /-! ## Forbidden sets and subshifts -/ From f9db2fd73a1b071b7feaa38eeee5bdb8f2482972 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Wed, 29 Apr 2026 12:55:20 +0900 Subject: [PATCH 92/93] mullanguageOn -> languageOn + remove SFT definition + simplification of isClosed_mulForbidden proof --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 111 ++++++++----------- 1 file changed, 46 insertions(+), 65 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index 00347a787becdb..acce1e1c543a36 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -48,7 +48,7 @@ so that the theory works not only for groups but also for cancellative monoids. **left** action of `G` on configurations). * `cylinder U x` — configurations agreeing with `x` on a finite set `U ⊆ G`. * `Pattern A G` — a configuration which takes -default value outside of a finite domain, together with this domain. +default value outside of a finite support, together with this support. * `Pattern.occursInAt p x g` — occurrence of `p` in `x` at translate `g`. * `forbidden F` — configurations avoiding every pattern in `F`. * `Subshift A G` — closed, shift-invariant subsets of the full shift. @@ -275,21 +275,21 @@ def mulFullShift (A G) [TopologicalSpace A] [Monoid G] : MulSubshift A G where It consists of: * a full configuration `config : G → A` in the full shift; -* a finite subset `domain : Finset G` of coordinates, called the domain of `p`; -* a proof `condition` that outside `domain`, `config` takes the default value of `A`. +* a finite subset `support : Finset G` of coordinates, called the support of `p`; +* a proof `condition` that outside `support`, `config` takes the default value of `A`. Intuitively, a pattern is a "partial configuration" specifying finitely many values of a configuration in `G → A` (the rest being `default`). Patterns are the basic building blocks used to define subshifts via forbidden configurations. Note that each pattern corresponds to a cylinder, which is the set of configurations -which agree with this pattern on its domain. -/ +which agree with this pattern on its support. -/ structure Pattern (A : Type*) (G : Type*) [Inhabited A] where /-- The full configuration in the full shift `A^G`. -/ config : G → A - /-- Finite domain of the pattern. -/ - domain : Finset G - /-- Outside the domain, `config` takes the default value of `A`. -/ - condition : ∀ g ∉ domain, config g = default + /-- Finite support of the pattern. -/ + support : Finset G + /-- Outside the support, `config` takes the default value of `A`. -/ + condition : ∀ g ∉ support, config g = default section Forbidden @@ -299,24 +299,24 @@ variable {A G : Type*} [Inhabited A] [Monoid G] `p` appears in the configuration `x` at position `g`. -Formally: for every position `h` in the domain of `p`, the value of the configuration +Formally: for every position `h` in the support of `p`, the value of the configuration at `g * h` coincides with the value of `p.config` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `mulShift g`), -then on the domain of `p` you exactly recover the pattern `p`. This is the basic +then on the support of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/ @[to_additive Pattern.occursInAt /-- `p.occursInAt x g` means that the finite pattern `p` appears in the configuration `x` at position `g`. -Formally: for every position `h` in the domain of `p`, the value of the configuration +Formally: for every position `h` in the support of `p`, the value of the configuration at `g + h` coincides with the value of `p.config` at `h`. Intuitively, if you shift the configuration `x` by `g` (using `shift g`), -then on the domain of `p` you exactly recover the pattern `p`. This is the basic +then on the support of `p` you exactly recover the pattern `p`. This is the basic notion of "pattern occurrence" used to define subshifts via forbidden patterns. -/] def Pattern.mulOccursInAt (p : Pattern A G) (x : G → A) (g : G) : Prop := - ∀ (h) (_ : h ∈ p.domain), x (g * h) = p.config h + ∀ (h) (_ : h ∈ p.support), x (g * h) = p.config h /-- `mulForbidden F` is the set of configurations that avoid every pattern in `F`. @@ -349,8 +349,8 @@ variable {G : Type*} [Monoid G] [IsLeftCancelMul G] a configuration. On input `h : G`, we proceed as follows: -* if `h` lies in the left-translate of the domain, i.e. `h ∈ p.domain.image (v * ·)`, - choose (noncomputably) `w ∈ p.domain` with `v * w = h` and return `p.config w`; +* if `h` lies in the left-translate of the support, i.e. `h ∈ p.support.image (v * ·)`, + choose (noncomputably) `w ∈ p.support` with `v * w = h` and return `p.config w`; * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. @@ -362,8 +362,8 @@ require a left-cancellation hypothesis and are proved in separate lemmas. a configuration. On input `h : G`, we proceed as follows: -* if `h` lies in the left-translate of the domain, i.e. `h ∈ p.domain.image (v + ·)`, - choose (noncomputably) `w ∈ p.domain` with `v + w = h` and return `p.config w`; +* if `h` lies in the left-translate of the support, i.e. `h ∈ p.support.image (v + ·)`, + choose (noncomputably) `w ∈ p.support` with `v + w = h` and return `p.config w`; * otherwise return `default`. This definition does not assume left-cancellation; it only *chooses* a preimage. @@ -373,9 +373,9 @@ require a left-cancellation hypothesis and are proved in separate lemmas. protected noncomputable def Pattern.mulShift (p : Pattern A G) (v : G) : G → A := by classical intro h - if hmem : h ∈ p.domain.image (v * ·) then + if hmem : h ∈ p.support.image (v * ·) then -- package existence of a preimage under (v * ·) - let ex : ∃ w, w ∈ p.domain ∧ v * w = h := by + let ex : ∃ w, w ∈ p.support ∧ v * w = h := by simpa [Finset.mem_image] using hmem exact p.config (Classical.choose ex) else @@ -386,38 +386,38 @@ namespace Pattern to a finite subset `U : Finset G`. The pattern has `config g = x g` for `g ∈ U` and `config g = default` outside `U`, -with domain `U`. In other words, `Pattern.fromConfig x U` is the partial configuration of +with support `U`. In other words, `Pattern.fromConfig x U` is the partial configuration of `x` visible on the coordinates in `U`, padded with `default` elsewhere. -/ noncomputable def fromConfig (x : G → A) (U : Finset G) : Pattern A G := by classical exact { config := fun g => if g ∈ U then x g else default, - domain := U, + support := U, condition := fun g hg => if_neg hg } -/-- On the translated domain, `p.mulShift v` agrees with `p.config` at the preimage. +/-- On the translated support, `p.mulShift v` agrees with `p.config` at the preimage. -More precisely, if `w ∈ p.domain`, then at the translated site `v * w`, +More precisely, if `w ∈ p.support`, then at the translated site `v * w`, the configuration `p.mulShift v` takes the value `p.config w`. This uses `[IsLeftCancelMul G]` to identify the unique preimage of `v * w` under left-multiplication by `v`. -/ @[to_additive - /-- On the translated domain, `p.shift v` agrees with `p.config` at the preimage. + /-- On the translated support, `p.shift v` agrees with `p.config` at the preimage. - More precisely, if `w ∈ p.domain`, then at the translated site `v + w`, + More precisely, if `w ∈ p.support`, then at the translated site `v + w`, the configuration `p.shift v` takes the value `p.config w`. This uses `[IsLeftCancelAdd G]` to identify the unique preimage of `v + w` under left-translation by `v`. -/] lemma mulShift_apply_mul_left_of_mem - (p : Pattern A G) (v w : G) (hw : w ∈ p.domain) : + (p : Pattern A G) (v w : G) (hw : w ∈ p.support) : p.mulShift v (v * w) = p.config w := by classical - -- (v * w) is in the translated domain - have hmem : (v * w) ∈ p.domain.image (v * ·) := + -- (v * w) is in the translated support + have hmem : (v * w) ∈ p.support.image (v * ·) := Finset.mem_image.mpr ⟨w, hw, rfl⟩ -- existential used in the branch - have ex : ∃ w', w' ∈ p.domain ∧ v * w' = v * w := by + have ex : ∃ w', w' ∈ p.support ∧ v * w' = v * w := by simpa [Finset.mem_image] using hmem -- open the `if` branch as returned by the definition have h1 : p.mulShift v (v * w) = p.config (Classical.choose ex) := by @@ -488,7 +488,7 @@ the configuration `x` agrees with the translated pattern `Pattern.shift p g`. (This uses `[IsLeftCancelMul G]` to identify the preimage along left-multiplication by `g`.) -/] lemma mulOccursInAt_eq_cylinder (p : Pattern A G) (g : G) : - { x | p.mulOccursInAt x g } = cylinder (p.domain.image (g * ·)) (p.mulShift g) := by + { x | p.mulOccursInAt x g } = cylinder (p.support.image (g * ·)) (p.mulShift g) := by ext x; constructor · -- ⇒: from an occurrence, get membership in the cylinder intro H u hu @@ -537,15 +537,12 @@ lemma isClosed_mulForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : = ⋂ (p : Pattern A G) (hp : p ∈ F) (v : G), {x | ¬ p.mulOccursInAt x v} := by ext; simp rw [h_eq] -- Now prove that this big intersection is closed. - have h_closed : - IsClosed (⋂ (p : Pattern A G) (hp : p ∈ F) (v : G), {x | ¬ p.mulOccursInAt x v}) := by - refine isClosed_iInter (fun p => ?_) - refine isClosed_iInter (fun hp => ?_) - refine isClosed_iInter (fun v => ?_) - -- For each `p, hp, v`, the section is the complement of an open occurrence set. - have : {x | ¬ p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by ext; simp - simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt (A := A) (G := G) p v - simpa using h_closed + refine isClosed_iInter (fun p => ?_) + refine isClosed_iInter (fun hp => ?_) + refine isClosed_iInter (fun v => ?_) + -- For each `p, hp, v`, the section is the complement of an open occurrence set. + have : {x | ¬ p.mulOccursInAt x v} = {x | p.mulOccursInAt x v}ᶜ := by ext; simp + simpa [this, isClosed_compl_iff] using isOpen_mulOccursInAt (A := A) (G := G) p v /-- Occurrence sets are closed. -/ @[to_additive isClosed_occursInAt] @@ -578,19 +575,6 @@ def MulSubshift.ofForbidden [DiscreteTopology A] (F : Set (Pattern A G)) : MulSu isClosed := isClosed_mulForbidden F mapsTo := Pattern.mapsTo_mulShift_mulForbidden F -/-- A subshift of finite type (SFT) is a subshift defined by forbidding -a *finite* family of patterns. - -Formally, `mulSubshift_of_finite_type F` is `MulSubshift.ofForbidden F` where `F` is a -`Finset (Pattern A G)`. -/ -@[to_additive /-- A subshift of finite type (SFT) is a subshift defined by forbidding -a *finite* family of patterns. - -Formally, `subshift_of_finite_type F` is `Subshift.ofForbidden F` where `F` is a -`Finset (Pattern A G)`. -/] -def mulSubshiftOfFiniteType [DiscreteTopology A] (F : Finset (Pattern A G)) : MulSubshift A G := - MulSubshift.ofForbidden (F : Set (Pattern A G)) - end DefSubshiftByForbidden section Language @@ -598,21 +582,19 @@ section Language variable {A : Type*} [Fintype A] [Inhabited A] variable {G : Type*} -/-- Patterns with domain exactly `U` form a finite set. -/ +/-- Patterns with support exactly `U` form a finite set. -/ lemma finite_setOf_pattern_support_eq {A G : Type*} [Finite A] [Inhabited A] (U : Finset G) : - ({p : Pattern A G | p.domain = U}).Finite := by + ({p : Pattern A G | p.support = U}).Finite := by -- 1. Upgrade Finite A to Fintype A locally cases nonempty_fintype A - -- 2. Explicitly provide the Fintype instance for the Finset U - letI : Fintype U := U.fintypeCoeSort classical - -- Patterns with domain U biject with (U → A) via restriction/extension - let e : { p : Pattern A G // p.domain = U } ≃ (U → A) := + -- Patterns with support U biject with (U → A) via restriction/extension + let e : { p : Pattern A G // p.support = U } ≃ (U → A) := { toFun := fun p i => p.1.config i.1 invFun := fun f => ⟨{ config := fun g => if h : g ∈ U then f ⟨g, h⟩ else default, - domain := U, + support := U, condition := fun g hg => by simp [hg] }, rfl⟩ left_inv := by rintro ⟨⟨cfg, dom, cond⟩, hU⟩ @@ -624,16 +606,15 @@ lemma finite_setOf_pattern_support_eq · simp [hg] · simp [hg, cond g hg] right_inv := fun f => by ext i; simp [i.2] } - -- Now this should synthesize without issue - haveI : Fintype { p : Pattern A G // p.domain = U } := + haveI : Fintype { p : Pattern A G // p.support = U } := Fintype.ofEquiv (U → A) e.symm - let T := { p : Pattern A G // p.domain = U } + let T := { p : Pattern A G // p.support = U } have h_univ : (Set.univ : Set T).Finite := Set.finite_univ let coeT : T → Pattern A G := fun p => (p : Pattern A G) have h_image : (Set.image coeT (Set.univ : Set T)).Finite := h_univ.image _ have himage_eq : Set.image coeT (Set.univ : Set T) - = ({ p : Pattern A G | p.domain = U } : Set (Pattern A G)) := by + = ({ p : Pattern A G | p.support = U } : Set (Pattern A G)) := by ext p; constructor · intro hp; rcases hp with ⟨p', -, rfl⟩; exact p'.property · intro hp; refine ⟨⟨p, hp⟩, ?_, rfl⟩; simp @@ -643,13 +624,13 @@ lemma finite_setOf_pattern_support_eq This is the set of all finite patterns obtained by restricting some configuration `x ∈ X` to `U`. -/ -def mulLanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := +def LanguageOn (X : Set (G → A)) (U : Finset G) : Set (Pattern A G) := { p | ∃ x ∈ X, Pattern.fromConfig x U = p } /-- The language of a subshift `Y` on a finite shape `U`. -/ def MulSubshift.languageOn {A G} [TopologicalSpace A] [Inhabited A] [Monoid G] (Y : MulSubshift A G) (U : Finset G) : Set (Pattern A G) := - SymbolicDynamics.FullShift.mulLanguageOn (A := A) (G := G) Y.carrier U + SymbolicDynamics.FullShift.LanguageOn (A := A) (G := G) Y.carrier U end Language From 9ae1a1593c2813f1a07de667e72fae394a3ff1c4 Mon Sep 17 00:00:00 2001 From: Sfgangloff Date: Wed, 29 Apr 2026 13:00:08 +0900 Subject: [PATCH 93/93] simplified proof of finite_setOf_pattern_support_eq --- Mathlib/Dynamics/SymbolicDynamics/Basic.lean | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean index acce1e1c543a36..7a1b4e3ff47d53 100644 --- a/Mathlib/Dynamics/SymbolicDynamics/Basic.lean +++ b/Mathlib/Dynamics/SymbolicDynamics/Basic.lean @@ -606,19 +606,8 @@ lemma finite_setOf_pattern_support_eq · simp [hg] · simp [hg, cond g hg] right_inv := fun f => by ext i; simp [i.2] } - haveI : Fintype { p : Pattern A G // p.support = U } := - Fintype.ofEquiv (U → A) e.symm - let T := { p : Pattern A G // p.support = U } - have h_univ : (Set.univ : Set T).Finite := Set.finite_univ - let coeT : T → Pattern A G := fun p => (p : Pattern A G) - have h_image : (Set.image coeT (Set.univ : Set T)).Finite := h_univ.image _ - have himage_eq : - Set.image coeT (Set.univ : Set T) - = ({ p : Pattern A G | p.support = U } : Set (Pattern A G)) := by - ext p; constructor - · intro hp; rcases hp with ⟨p', -, rfl⟩; exact p'.property - · intro hp; refine ⟨⟨p, hp⟩, ?_, rfl⟩; simp - simpa [himage_eq] using h_image + let : Fintype { p : Pattern A G | p.support = U } := Fintype.ofEquiv (U → A) e.symm + apply toFinite /-- The language of a set of configurations `X` on a finite shape `U`.