/- Port of `Fixedpoint.agda`. Same gas-based algorithm: iterate `f` starting at the chain-bottom `⊥`; since the lattice has fixed height `h`, a fixed point must be reached within `h + 1` steps, or we would build a `<`-chain longer than the longest one. We deliberately do *not* use mathlib's `OrderHom.lfp` (different proof approach, and not computable). As in Agda — where the module took `{{flA : IsFiniteHeightLattice A h …}}` — the finite-height structure arrives by instance resolution (`[FiniteHeightLattice α]`); only `f` and its monotonicity are explicit. Correspondence: doStep ↦ Spa.Fixedpoint.doStep (the chain argument now carries `a₁ = ⊥` and its length in the `LTSeries` structure itself) fix ↦ Spa.Fixedpoint.fix aᶠ ↦ Spa.Fixedpoint.aFix aᶠ≈faᶠ ↦ Spa.Fixedpoint.aFix_eq stepPreservesLess ↦ Spa.Fixedpoint.doStep_le aᶠ≼ ↦ Spa.Fixedpoint.aFix_le -/ import Spa.Lattice namespace Spa.Fixedpoint open FiniteHeightLattice (height fixedHeight) variable {α : Type*} [Lattice α] [DecidableEq α] [FiniteHeightLattice α] /-- Agda: `doStep`. `g` is gas; the invariant `c.length + g = h + 1` guarantees that when gas runs out the chain contradicts boundedness. -/ def doStep (f : α → α) (hf : Monotone f) : ∀ (g : ℕ) (c : LTSeries α), c.length + g = height (α := α) + 1 → c.last ≤ f c.last → {a : α // a = f a} | 0, c, hlen, _ => absurd ((fixedHeight (α := α)).bounded c) (by omega) | g + 1, c, hlen, hle => if heq : c.last = f c.last then ⟨c.last, heq⟩ else doStep f hf g (c.snoc (f c.last) (lt_of_le_of_ne hle heq)) (by simp [RelSeries.snoc]; omega) (by rw [RelSeries.last_snoc]; exact hf hle) /-- Agda: `fix`. Start iterating from `⊥`. -/ def fix (f : α → α) (hf : Monotone f) : {a : α // a = f a} := doStep f hf (height (α := α) + 1) (RelSeries.singleton _ (FiniteHeightLattice.bot α)) (by simp) (by simpa [RelSeries.last_singleton] using FiniteHeightLattice.bot_le α (f (FiniteHeightLattice.bot α))) /-- Agda: `aᶠ`. -/ def aFix (f : α → α) (hf : Monotone f) : α := (fix f hf).1 /-- Agda: `aᶠ≈faᶠ`. -/ theorem aFix_eq (f : α → α) (hf : Monotone f) : aFix f hf = f (aFix f hf) := (fix f hf).2 /-- Agda: `stepPreservesLess` — iteration stays below any fixed point. -/ theorem doStep_le (f : α → α) (hf : Monotone f) {b : α} (hb : b = f b) : ∀ (g : ℕ) (c : LTSeries α) (hlen : c.length + g = height (α := α) + 1) (hle : c.last ≤ f c.last), c.last ≤ b → (doStep f hf g c hlen hle : α) ≤ b | 0, c, hlen, _ => fun _ => absurd ((fixedHeight (α := α)).bounded c) (by omega) | g + 1, c, hlen, hle => fun hcb => by rw [doStep] split · exact hcb · exact doStep_le f hf hb g _ _ _ (by rw [RelSeries.last_snoc]; exact le_of_le_of_eq (hf hcb) hb.symm) /-- Agda: `aᶠ≼` — `aFix` is below every fixed point of `f`. -/ theorem aFix_le (f : α → α) (hf : Monotone f) {a : α} (ha : a = f a) : aFix f hf ≤ a := doStep_le f hf ha _ _ _ _ (by simpa using FiniteHeightLattice.bot_le α a) end Spa.Fixedpoint