2026-06-09 18:36:43 -07:00
|
|
|
|
import Mathlib.Order.Lattice
|
|
|
|
|
|
import Mathlib.Order.RelSeries
|
|
|
|
|
|
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-!
|
|
|
|
|
|
|
2026-06-25 17:05:21 -05:00
|
|
|
|
# Lattice Definitions
|
2026-06-25 15:39:51 -05:00
|
|
|
|
|
|
|
|
|
|
This file provides some definitions for lattices. It used to be more critical
|
|
|
|
|
|
when this was an Agda project, since it defined (semi)lattices, the ordering
|
|
|
|
|
|
relation, etc. However, these have been lifted into `Mathlib.Order.Lattice`
|
|
|
|
|
|
etc.. What remains are a couple of theorems about folds, as well
|
|
|
|
|
|
as `FiniteHeightLattice`, the core concept of lattice-based static
|
|
|
|
|
|
program analyses. See the documentation on that class for more information. -/
|
|
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
namespace Option
|
|
|
|
|
|
|
|
|
|
|
|
/-- Equality-sensitive eliminator for options in which the `some` case
|
|
|
|
|
|
is sensitive to the base `β`. This makes it mirror a one-element fold
|
|
|
|
|
|
more closely. -/
|
|
|
|
|
|
def elimEq {α : Type*} {β : Sort*} :
|
|
|
|
|
|
(o : Option α) → β → ((a : α) → o = some a → β → β) → β
|
|
|
|
|
|
| none, b, _ => b
|
|
|
|
|
|
| some a, b, f => f a rfl b
|
|
|
|
|
|
|
|
|
|
|
|
end Option
|
|
|
|
|
|
|
2026-06-09 18:36:43 -07:00
|
|
|
|
namespace Spa
|
|
|
|
|
|
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-- Predicate for binary functions independently monotone in both their arguments. -/
|
2026-06-09 18:36:43 -07:00
|
|
|
|
def Monotone₂ {α β γ : Type*} [Preorder α] [Preorder β] [Preorder γ]
|
|
|
|
|
|
(f : α → β → γ) : Prop :=
|
2026-06-22 18:33:48 -05:00
|
|
|
|
(∀ b, Monotone (f · b)) ∧ (∀ a, Monotone (f a ·))
|
2026-06-09 18:36:43 -07:00
|
|
|
|
|
|
|
|
|
|
section Folds
|
|
|
|
|
|
|
|
|
|
|
|
variable {α β : Type*} [Preorder α] [Preorder β]
|
|
|
|
|
|
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-- (right) folds are monotonic in both their arguments if the underlying accumulator function is. -/
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma foldr_mono {l₁ l₂ : List α} (f : α → β → β) {b₁ b₂ : β}
|
2026-06-09 18:36:43 -07:00
|
|
|
|
(hl : List.Forall₂ (· ≤ ·) l₁ l₂) (hb : b₁ ≤ b₂)
|
2026-06-25 15:39:51 -05:00
|
|
|
|
(hf₁ : ∀ b, Monotone (f · b)) (hf₂ : ∀ a, Monotone (f a ·)) :
|
2026-06-09 18:36:43 -07:00
|
|
|
|
l₁.foldr f b₁ ≤ l₂.foldr f b₂ := by
|
|
|
|
|
|
induction hl with
|
|
|
|
|
|
| nil => exact hb
|
|
|
|
|
|
| cons hxy _ ih =>
|
|
|
|
|
|
exact le_trans (hf₁ _ hxy) (hf₂ _ ih)
|
|
|
|
|
|
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-- (left) folds are monotinic in both their arguments if the underlying accumulator function is. -/
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma foldl_mono {l₁ l₂ : List α} (f : β → α → β) {b₁ b₂ : β}
|
2026-06-09 18:36:43 -07:00
|
|
|
|
(hl : List.Forall₂ (· ≤ ·) l₁ l₂) (hb : b₁ ≤ b₂)
|
2026-06-25 15:39:51 -05:00
|
|
|
|
(hf₁ : ∀ a, Monotone (f · a)) (hf₂ : ∀ b, Monotone (f b ·)) :
|
2026-06-09 18:36:43 -07:00
|
|
|
|
l₁.foldl f b₁ ≤ l₂.foldl f b₂ := by
|
|
|
|
|
|
induction hl generalizing b₁ b₂ with
|
|
|
|
|
|
| nil => exact hb
|
|
|
|
|
|
| cons hxy _ ih =>
|
|
|
|
|
|
exact ih (le_trans (hf₁ _ hb) (hf₂ _ hxy))
|
|
|
|
|
|
|
|
|
|
|
|
omit [Preorder α] in
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-- (right) folds on a particular list are monotonic if the underlying accumulator is monotonic in its accumulator argument. -/
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma foldr_mono' (l : List α) (f : α → β → β)
|
2026-06-25 15:39:51 -05:00
|
|
|
|
(hf : ∀ a, Monotone (f a ·)) : Monotone (l.foldr f ·) := by
|
2026-06-09 18:36:43 -07:00
|
|
|
|
intro b₁ b₂ hb
|
|
|
|
|
|
induction l with
|
|
|
|
|
|
| nil => exact hb
|
|
|
|
|
|
| cons x xs ih => exact hf x ih
|
|
|
|
|
|
|
|
|
|
|
|
omit [Preorder α] in
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-- (left) folds on a particular list are monotonic if the underlying accumulator is monotonic in its accumulator argument. -/
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma foldl_mono' (l : List α) (f : β → α → β)
|
2026-06-22 18:33:48 -05:00
|
|
|
|
(hf : ∀ a, Monotone (f · a)) : Monotone fun b => l.foldl f b := by
|
2026-06-09 18:36:43 -07:00
|
|
|
|
intro b₁ b₂ hb
|
|
|
|
|
|
induction l generalizing b₁ b₂ with
|
|
|
|
|
|
| nil => exact hb
|
|
|
|
|
|
| cons x xs ih => exact ih (hf x hb)
|
|
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
omit [Preorder α] in
|
|
|
|
|
|
/-- The equality-aware eliminator (that also alters its behavior dependent on base case)
|
|
|
|
|
|
for option is monotonic. -/
|
|
|
|
|
|
lemma elimEq_self_mono (o : Option α) (g : (a : α) → o = some a → β → β)
|
|
|
|
|
|
(hg : ∀ a h, Monotone (g a h)) :
|
|
|
|
|
|
Monotone (o.elimEq · g) := by
|
|
|
|
|
|
cases o with
|
|
|
|
|
|
| none => exact monotone_id
|
|
|
|
|
|
| some a => exact hg a rfl
|
|
|
|
|
|
|
2026-06-09 18:36:43 -07:00
|
|
|
|
end Folds
|
|
|
|
|
|
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-- Predicate on types with `Preorder` that claims all $<$ chains in the type have at most `n` comparisons. -/
|
2026-06-09 18:36:43 -07:00
|
|
|
|
def BoundedChains (α : Type*) [Preorder α] (n : ℕ) : Prop :=
|
|
|
|
|
|
∀ c : LTSeries α, c.length ≤ n
|
|
|
|
|
|
|
2026-06-26 10:17:25 -05:00
|
|
|
|
/-- Since a singleton type's preorder has no nonempty `<` chains,
|
|
|
|
|
|
they are vacuously bounded by any minimum height. -/
|
|
|
|
|
|
lemma boundedChains_of_subsingleton (α : Type*) [Preorder α] [Subsingleton α]
|
|
|
|
|
|
(n : ℕ) : BoundedChains α n := fun c => by
|
|
|
|
|
|
by_contra hc
|
|
|
|
|
|
push_neg at hc
|
|
|
|
|
|
exact (c.step ⟨0, by omega⟩).ne (Subsingleton.elim _ _)
|
|
|
|
|
|
|
2026-06-25 15:39:51 -05:00
|
|
|
|
/-- A finite height lattice is a lattice in which all chains $a < \ldots < z$ have a maximum height `height`. -/
|
2026-06-26 14:49:57 -05:00
|
|
|
|
class FiniteHeightLattice (α : Type*) extends Lattice α, OrderBot α, OrderTop α where
|
2026-06-26 15:04:18 -05:00
|
|
|
|
height : ℕ
|
|
|
|
|
|
chains_bounded : BoundedChains α height
|
2026-06-25 18:42:28 -05:00
|
|
|
|
|
|
|
|
|
|
-- a < ... < z
|
|
|
|
|
|
-- ----------- length <= height
|
2026-06-09 18:36:43 -07:00
|
|
|
|
|
2026-06-24 13:30:27 -05:00
|
|
|
|
namespace FiniteHeightLattice
|
2026-06-09 18:36:43 -07:00
|
|
|
|
|
2026-06-26 08:52:31 -05:00
|
|
|
|
/-- This is something like a lemma about isomorphic types having the same height.
|
|
|
|
|
|
Given a finite-height lattice `α`, lattice `β`, and a `Monotone` bijection
|
|
|
|
|
|
between the two, we can show that lattice `β` also has a finite height.
|
|
|
|
|
|
|
2026-06-26 15:04:18 -05:00
|
|
|
|
The proof is fairly trivial: any chain in `β` can be transported to a chain in `α`,
|
2026-06-26 08:52:31 -05:00
|
|
|
|
and must be bounded by the same height by `FiniteHeightLattice.chains_bounded`. -/
|
|
|
|
|
|
def transport {α β : Type*} [Lattice β]
|
|
|
|
|
|
[I : FiniteHeightLattice α] (f : α → β) (g : β → α)
|
|
|
|
|
|
(hf : Monotone f) (hg : Monotone g)
|
2026-06-26 15:04:18 -05:00
|
|
|
|
(hfg : Function.LeftInverse f g) :
|
2026-06-26 08:52:31 -05:00
|
|
|
|
FiniteHeightLattice β where
|
|
|
|
|
|
toLattice := inferInstance
|
2026-06-26 14:49:57 -05:00
|
|
|
|
toOrderBot := {
|
|
|
|
|
|
bot := f (⊥ : α)
|
|
|
|
|
|
bot_le := fun b => by
|
|
|
|
|
|
rw [← hfg b]
|
|
|
|
|
|
exact hf (_root_.bot_le : (⊥ : α) ≤ g b) }
|
|
|
|
|
|
toOrderTop := {
|
|
|
|
|
|
top := f (⊤ : α)
|
|
|
|
|
|
le_top := fun b => by
|
|
|
|
|
|
rw [← hfg b]
|
|
|
|
|
|
exact hf (_root_.le_top : g b ≤ (⊤ : α)) }
|
2026-06-26 15:04:18 -05:00
|
|
|
|
height := I.height
|
2026-06-26 08:52:31 -05:00
|
|
|
|
chains_bounded := fun c =>
|
|
|
|
|
|
I.chains_bounded (c.map g (hg.strictMono_of_injective hfg.injective))
|
|
|
|
|
|
|
2026-06-26 10:17:25 -05:00
|
|
|
|
/-- A `Unique` lattice trivially has finite height: its only chain is the singleton
|
|
|
|
|
|
`[default]`, and there are no nontrivial `<` chains in a subsingleton. -/
|
2026-06-26 14:49:57 -05:00
|
|
|
|
def ofUnique (α : Type*) [Lattice α] [Unique α] :
|
|
|
|
|
|
FiniteHeightLattice α where
|
2026-06-26 10:17:25 -05:00
|
|
|
|
toLattice := inferInstance
|
2026-06-26 14:49:57 -05:00
|
|
|
|
toOrderBot := {
|
|
|
|
|
|
bot := default
|
|
|
|
|
|
bot_le := fun _ => le_of_eq (Subsingleton.elim _ _) }
|
|
|
|
|
|
toOrderTop := {
|
|
|
|
|
|
top := default
|
|
|
|
|
|
le_top := fun _ => le_of_eq (Subsingleton.elim _ _) }
|
2026-06-26 15:04:18 -05:00
|
|
|
|
height := 0
|
2026-06-26 10:17:25 -05:00
|
|
|
|
chains_bounded := boundedChains_of_subsingleton α 0
|
|
|
|
|
|
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
end FiniteHeightLattice
|
|
|
|
|
|
|
2026-06-09 18:36:43 -07:00
|
|
|
|
end Spa
|