Make FiniteHeightLattice extend Lattice and derive Top/Bot

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 18:42:28 -05:00
parent acef0f202b
commit cbad43efdc
11 changed files with 61 additions and 102 deletions

View File

@@ -7,7 +7,7 @@ namespace Spa
namespace Forward namespace Forward
variable {L : Type} [Lattice L] {prog : Program} [E : StmtEvaluator L prog] variable {L : Type} [FiniteHeightLattice L] {prog : Program} [E : StmtEvaluator L prog]
def updateVariablesForState (s : prog.State) (sv : StateVariables L prog) : def updateVariablesForState (s : prog.State) (sv : StateVariables L prog) :
VariableValues L prog := VariableValues L prog :=
@@ -33,8 +33,6 @@ lemma variablesAt_updateAll (s : prog.State) (sv : StateVariables L prog) :
variablesAt s (updateAll sv) = updateVariablesForState s sv := variablesAt s (updateAll sv) = updateVariablesForState s sv :=
updateAll_mem_eq (variablesAt_mem s (updateAll sv)) updateAll_mem_eq (variablesAt_mem s (updateAll sv))
variable [FiniteHeightLattice L]
def analyze (sv : StateVariables L prog) : StateVariables L prog := def analyze (sv : StateVariables L prog) : StateVariables L prog :=
updateAll (joinAll sv) updateAll (joinAll sv)
@@ -58,7 +56,7 @@ lemma joinForKey_initialState :
variable [I : LatticeInterpretation L] [V : ValidStmtEvaluator L prog] variable [I : LatticeInterpretation L] [V : ValidStmtEvaluator L prog]
omit [FiniteHeightLattice L] [DecidableEq L] in omit [DecidableEq L] in
lemma eval_fold_valid {s : prog.State} {bss : List BasicStmt} lemma eval_fold_valid {s : prog.State} {bss : List BasicStmt}
{vs : VariableValues L prog} {ρ₁ ρ₂ : Env} {vs : VariableValues L prog} {ρ₁ ρ₂ : Env}
(hbss : EvalBasicStmts ρ₁ bss ρ₂) (hvs : vs ρ₁) : (hbss : EvalBasicStmts ρ₁ bss ρ₂) (hvs : vs ρ₁) :
@@ -67,7 +65,7 @@ lemma eval_fold_valid {s : prog.State} {bss : List BasicStmt}
| nil => exact hvs | nil => exact hvs
| cons hbs _ ih => exact ih (ValidStmtEvaluator.valid hbs hvs) | cons hbs _ ih => exact ih (ValidStmtEvaluator.valid hbs hvs)
omit [FiniteHeightLattice L] [DecidableEq L] in omit [DecidableEq L] in
lemma updateVariablesForState_matches {s : prog.State} lemma updateVariablesForState_matches {s : prog.State}
{sv : StateVariables L prog} {ρ₁ ρ₂ : Env} {sv : StateVariables L prog} {ρ₁ ρ₂ : Env}
(hbss : EvalBasicStmts ρ₁ (prog.code s) ρ₂) (hbss : EvalBasicStmts ρ₁ (prog.code s) ρ₂)
@@ -75,7 +73,7 @@ lemma updateVariablesForState_matches {s : prog.State}
updateVariablesForState s sv ρ₂ := updateVariablesForState s sv ρ₂ :=
eval_fold_valid hbss hvs eval_fold_valid hbss hvs
omit [FiniteHeightLattice L] [DecidableEq L] in omit [DecidableEq L] in
lemma updateAll_matches {s : prog.State} {sv : StateVariables L prog} lemma updateAll_matches {s : prog.State} {sv : StateVariables L prog}
{ρ₁ ρ₂ : Env} (hbss : EvalBasicStmts ρ₁ (prog.code s) ρ₂) {ρ₁ ρ₂ : Env} (hbss : EvalBasicStmts ρ₁ (prog.code s) ρ₂)
(hvs : variablesAt s sv ρ₁) : (hvs : variablesAt s sv ρ₁) :

View File

@@ -6,13 +6,13 @@ namespace Fixedpoint
open FiniteHeightLattice (height) open FiniteHeightLattice (height)
variable {α : Type*} [Lattice α] [DecidableEq α] [FiniteHeightLattice α] variable {α : Type*} [DecidableEq α] [FiniteHeightLattice α]
def doStep (f : α α) (hf : Monotone f) : def doStep (f : α α) (hf : Monotone f) :
(g : ) (c : LTSeries α), c.length + g = height (α := α) + 1 (g : ) (c : LTSeries α), c.length + g = height (α := α) + 1
c.last f c.last {a : α // a = f a} c.last f c.last {a : α // a = f a}
| 0, c, hlen, _ => | 0, c, hlen, _ =>
absurd (FiniteHeightLattice.chains_bounded c) (by omega) absurd (FiniteHeightLattice.chains_bounded c) (by simp only [height] at hlen; omega)
| g + 1, c, hlen, hle => | g + 1, c, hlen, hle =>
if heq : c.last = f c.last then if heq : c.last = f c.last then
c.last, heq c.last, heq
@@ -39,7 +39,8 @@ lemma doStep_le (f : αα) (hf : Monotone f)
(g : ) (c : LTSeries α) (hlen : c.length + g = height (α := α) + 1) (g : ) (c : LTSeries α) (hlen : c.length + g = height (α := α) + 1)
(hle : c.last f c.last), c.last b (hle : c.last f c.last), c.last b
(doStep f hf g c hlen hle : α) b (doStep f hf g c hlen hle : α) b
| 0, c, hlen, _ => fun _ => absurd (FiniteHeightLattice.chains_bounded c) (by omega) | 0, c, hlen, _ => fun _ =>
absurd (FiniteHeightLattice.chains_bounded c) (by simp only [height] at hlen; omega)
| g + 1, c, hlen, hle => fun hcb => by | g + 1, c, hlen, hle => fun hcb => by
rw [doStep] rw [doStep]
split split

View File

@@ -2,20 +2,14 @@ import Spa.Lattice
namespace Spa namespace Spa
def FiniteHeightLattice.transport {α β : Type*} [Lattice α] [Lattice β] def FiniteHeightLattice.transport {α β : Type*} [Lattice β]
[I : FiniteHeightLattice α] (f : α β) (g : β α) [I : FiniteHeightLattice α] (f : α β) (g : β α)
(hf : Monotone f) (hg : Monotone g) (hf : Monotone f) (hg : Monotone g)
(hgf : Function.LeftInverse g f) (hfg : Function.LeftInverse f g) : (hgf : Function.LeftInverse g f) (hfg : Function.LeftInverse f g) :
FiniteHeightLattice β where FiniteHeightLattice β where
bot := f toLattice := inferInstance
top := f
height := I.height
longestChain := longestChain :=
{ series := I.longestChain.map f (hf.strictMono_of_injective hgf.injective)
I.longestChain.series.map f (hf.strictMono_of_injective hgf.injective)
head_series := congrArg f I.longestChain.head_series
last_series := congrArg f I.longestChain.last_series
length_series := I.longestChain.length_series }
chains_bounded := fun c => chains_bounded := fun c =>
I.chains_bounded (c.map g (hg.strictMono_of_injective hfg.injective)) I.chains_bounded (c.map g (hg.strictMono_of_injective hfg.injective))

View File

@@ -67,34 +67,44 @@ end Folds
def BoundedChains (α : Type*) [Preorder α] (n : ) : Prop := def BoundedChains (α : Type*) [Preorder α] (n : ) : Prop :=
c : LTSeries α, c.length n c : LTSeries α, c.length n
/-- Wrapper over `LTSeries` that exposes its beginning and end points, as well as its length, as part of the type. -/
structure PointedLTSeries (α : Type*) (f t : α) (n : ) [Preorder α] where
series : LTSeries α
head_series : series.head = f
last_series : series.last = t
length_series : series.length = n
/-- A finite height lattice is a lattice in which all chains $a < \ldots < z$ have a maximum height `height`. -/ /-- A finite height lattice is a lattice in which all chains $a < \ldots < z$ have a maximum height `height`. -/
class FiniteHeightLattice (α : Type*) [Lattice α] extends Bot α, Top α where class FiniteHeightLattice (α : Type*) extends Lattice α where
height : longestChain : LTSeries α
longestChain : PointedLTSeries α height chains_bounded : BoundedChains α longestChain.length
chains_bounded : BoundedChains α height
-- a < ... < z
-- ----------- length <= height
namespace FiniteHeightLattice namespace FiniteHeightLattice
variable (α : Type*) [Lattice α] [FiniteHeightLattice α] def height (α : Type*) [FiniteHeightLattice α] : :=
(longestChain (α := α)).length
variable (α : Type*) [FiniteHeightLattice α]
instance (priority := 100) : Bot α := (longestChain (α := α)).head
instance (priority := 100) : Top α := (longestChain (α := α)).last
/-- The bottom element `⊥` of a finite height lattice is _actually_ the least element. -/ /-- The bottom element `⊥` of a finite height lattice is _actually_ the least element. -/
lemma bot_le (a : α) : ( : α) a := by lemma bot_le (a : α) : ( : α) a := by
by_cases heq : a = by_cases heq : a =
· exact inf_eq_left.mp heq · exact inf_eq_left.mp heq
· exfalso · exfalso
have lc := FiniteHeightLattice.longestChain (α := α) have hlt : a < (longestChain (α := α)).head :=
have hlt : a < lc.series.head := by lt_of_le_of_ne inf_le_left heq
rw [lc.head_series] have hbound := chains_bounded ((longestChain (α := α)).cons ( a) hlt)
exact lt_of_le_of_ne inf_le_left heq rw [RelSeries.cons_length] at hbound
have hbound := FiniteHeightLattice.chains_bounded (lc.series.cons ( a) hlt) omega
rw [RelSeries.cons_length, lc.length_series] at hbound
/-- The top element `` of a finite height lattice is _actually_ the greatest element. -/
lemma le_top (a : α) : a ( : α) := by
by_cases heq : a =
· exact sup_eq_right.mp heq
· exfalso
have hlt : (longestChain (α := α)).last < a :=
lt_of_le_of_ne le_sup_right (Ne.symm heq)
have hbound := chains_bounded ((longestChain (α := α)).snoc (a ) hlt)
rw [RelSeries.snoc_length] at hbound
omega omega
end FiniteHeightLattice end FiniteHeightLattice

View File

@@ -223,17 +223,11 @@ lemma boundedChains : BoundedChains (AboveBelow α) 2 := fun c => by
omega omega
instance [Inhabited α] : FiniteHeightLattice (AboveBelow α) where instance [Inhabited α] : FiniteHeightLattice (AboveBelow α) where
bot := bot toLattice := inferInstance
top := top
height := 2
longestChain := longestChain :=
{ series :=
((RelSeries.singleton _ bot).snoc (mk default) ((RelSeries.singleton _ bot).snoc (mk default)
(by rw [RelSeries.last_singleton]; exact bot_lt_mk default)).snoc top (by rw [RelSeries.last_singleton]; exact bot_lt_mk default)).snoc top
(by rw [RelSeries.last_snoc]; exact mk_lt_top default) (by rw [RelSeries.last_snoc]; exact mk_lt_top default)
head_series := by simp
last_series := by simp
length_series := by simp [RelSeries.snoc, RelSeries.append] }
chains_bounded := boundedChains chains_bounded := boundedChains
end AboveBelow end AboveBelow

View File

@@ -28,13 +28,9 @@ lemma boundedChains : BoundedChains Bool 1 := fun c => by
omega omega
instance : FiniteHeightLattice Bool where instance : FiniteHeightLattice Bool where
height := 1 toLattice := inferInstance
longestChain := longestChain := (RelSeries.singleton _ ( : Bool)).snoc ( : Bool)
{ series := (RelSeries.singleton _ ( : Bool)).snoc ( : Bool)
(by rw [RelSeries.last_singleton]; exact bot_lt_top) (by rw [RelSeries.last_singleton]; exact bot_lt_top)
head_series := by simp
last_series := by simp
length_series := by simp [RelSeries.snoc, RelSeries.append] }
chains_bounded := boundedChains chains_bounded := boundedChains
end Bool end Bool

View File

@@ -12,7 +12,7 @@ variable {A B : Type*} {ks : List A}
instance [Lattice B] : Lattice (FiniteMap A B ks) := instance [Lattice B] : Lattice (FiniteMap A B ks) :=
inferInstanceAs (Lattice (Fin ks.length B)) inferInstanceAs (Lattice (Fin ks.length B))
instance [Lattice B] [FiniteHeightLattice B] : FiniteHeightLattice (FiniteMap A B ks) := instance [FiniteHeightLattice B] : FiniteHeightLattice (FiniteMap A B ks) :=
inferInstanceAs (FiniteHeightLattice (Fin ks.length B)) inferInstanceAs (FiniteHeightLattice (Fin ks.length B))
instance [DecidableEq B] : DecidableEq (FiniteMap A B ks) := instance [DecidableEq B] : DecidableEq (FiniteMap A B ks) :=

View File

@@ -13,11 +13,6 @@ namespace IterProd
variable {A B : Type u} variable {A B : Type u}
instance lattice [Lattice A] [Lattice B] :
k, Lattice (IterProd A B k)
| 0 => inferInstanceAs (Lattice B)
| k + 1 => @Prod.instLattice A (IterProd A B k) _ (lattice k)
instance decidableEq [DecidableEq A] [DecidableEq B] : instance decidableEq [DecidableEq A] [DecidableEq B] :
k, DecidableEq (IterProd A B k) k, DecidableEq (IterProd A B k)
| 0 => inferInstanceAs (DecidableEq B) | 0 => inferInstanceAs (DecidableEq B)
@@ -27,24 +22,14 @@ def build (a : A) (b : B) : (k : ) → IterProd A B k
| 0 => b | 0 => b
| k + 1 => (a, build a b k) | k + 1 => (a, build a b k)
variable [Lattice A] [Lattice B]
def fixedHeight [FiniteHeightLattice A] [FiniteHeightLattice B] : def fixedHeight [FiniteHeightLattice A] [FiniteHeightLattice B] :
k, FiniteHeightLattice (IterProd A B k) k, FiniteHeightLattice (IterProd A B k)
| 0 => inferInstanceAs (FiniteHeightLattice B) | 0 => inferInstanceAs (FiniteHeightLattice B)
| k + 1 => @Spa.prod A (IterProd A B k) _ (lattice k) _ (fixedHeight k) | k + 1 => @Spa.prod A (IterProd A B k) _ (fixedHeight k)
instance finiteHeight [FiniteHeightLattice A] [FiniteHeightLattice B] (k : ) : instance finiteHeight [FiniteHeightLattice A] [FiniteHeightLattice B] (k : ) :
FiniteHeightLattice (IterProd A B k) := fixedHeight k FiniteHeightLattice (IterProd A B k) := fixedHeight k
lemma bot_fixedHeight [FiniteHeightLattice A] [FiniteHeightLattice B] :
k, (fixedHeight (A := A) (B := B) k).bot = build ( : A) ( : B) k
| 0 => rfl
| k + 1 => by
show (( : A), (fixedHeight (A := A) (B := B) k).bot)
= (( : A), build ( : A) ( : B) k)
rw [bot_fixedHeight k]
end IterProd end IterProd
end Spa end Spa

View File

@@ -58,36 +58,23 @@ end Unzip
section FixedHeight section FixedHeight
variable {α β : Type*} [Lattice α] [Lattice β] variable {α β : Type*}
instance prod [A : FiniteHeightLattice α] [B : FiniteHeightLattice β] : instance prod [A : FiniteHeightLattice α] [B : FiniteHeightLattice β] :
FiniteHeightLattice (α × β) where FiniteHeightLattice (α × β) where
bot := (( : α), ( : β)) toLattice := inferInstance
top := (( : α), ( : β))
height := A.height + B.height
longestChain := longestChain :=
{ series :=
RelSeries.smash RelSeries.smash
(A.longestChain.series.map (fun a => (a, ( : β))) (A.longestChain.map (fun a => (a, ( : β)))
(fun _ _ h => Prod.mk_lt_mk_iff_left.mpr h)) (fun _ _ h => Prod.mk_lt_mk_iff_left.mpr h))
(B.longestChain.series.map (fun b => (( : α), b)) (B.longestChain.map (fun b => (( : α), b))
(fun _ _ h => Prod.mk_lt_mk_iff_right.mpr h)) (fun _ _ h => Prod.mk_lt_mk_iff_right.mpr h))
(by simp [A.longestChain.last_series, B.longestChain.head_series]) rfl
head_series :=
(RelSeries.head_smash _).trans
((LTSeries.head_map _ _ _).trans
(congrArg (·, ( : β)) A.longestChain.head_series))
last_series :=
(RelSeries.last_smash _).trans
((LTSeries.last_map _ _ _).trans
(congrArg (( : α), ·) B.longestChain.last_series))
length_series := by
show A.longestChain.series.length + B.longestChain.series.length = _
rw [A.longestChain.length_series, B.longestChain.length_series] }
chains_bounded := fun c => by chains_bounded := fun c => by
obtain c₁, c₂, -, -, -, -, hlen := LTSeries.exists_unzip c obtain c₁, c₂, -, -, -, -, hlen := LTSeries.exists_unzip c
have h₁ := A.chains_bounded c₁ have h₁ := A.chains_bounded c₁
have h₂ := B.chains_bounded c₂ have h₂ := B.chains_bounded c₂
show c.length A.longestChain.length + B.longestChain.length
omega omega
end FixedHeight end FixedHeight

View File

@@ -32,7 +32,7 @@ private lemma iterOfFun_funOfIter : ∀ {n : } (ip : IterProd B PUnit n),
rw [show funOfIter ip = Fin.cons ip.1 (funOfIter ip.2) from rfl] rw [show funOfIter ip = Fin.cons ip.1 (funOfIter ip.2) from rfl]
simp [Fin.cons_zero, Fin.tail_cons, iterOfFun_funOfIter ip.2] simp [Fin.cons_zero, Fin.tail_cons, iterOfFun_funOfIter ip.2]
variable [Lattice B] variable [FiniteHeightLattice B]
private lemma funOfIter_mono {n : } : private lemma funOfIter_mono {n : } :
Monotone (funOfIter : IterProd B PUnit n (Fin n B)) := by Monotone (funOfIter : IterProd B PUnit n (Fin n B)) := by
@@ -55,7 +55,7 @@ private lemma iterOfFun_mono {n : } :
intro f g h intro f g h
exact Prod.le_def.mpr h 0, ih fun i => h i.succ exact Prod.le_def.mpr h 0, ih fun i => h i.succ
instance instFiniteHeight {n : } [FiniteHeightLattice B] : instance instFiniteHeight {n : } :
FiniteHeightLattice (Fin n B) := FiniteHeightLattice (Fin n B) :=
FiniteHeightLattice.transport funOfIter iterOfFun FiniteHeightLattice.transport funOfIter iterOfFun
funOfIter_mono iterOfFun_mono iterOfFun_funOfIter funOfIter_iterOfFun funOfIter_mono iterOfFun_mono iterOfFun_funOfIter funOfIter_iterOfFun

View File

@@ -9,14 +9,8 @@ lemma boundedChains_of_subsingleton (α : Type*) [Preorder α] [Subsingleton α]
exact (c.step 0, by omega).ne (Subsingleton.elim _ _) exact (c.step 0, by omega).ne (Subsingleton.elim _ _)
instance : FiniteHeightLattice PUnit where instance : FiniteHeightLattice PUnit where
bot := PUnit.unit toLattice := inferInstance
top := PUnit.unit longestChain := RelSeries.singleton _ PUnit.unit
height := 0
longestChain :=
{ series := RelSeries.singleton _ PUnit.unit
head_series := rfl
last_series := rfl
length_series := rfl }
chains_bounded := boundedChains_of_subsingleton PUnit 0 chains_bounded := boundedChains_of_subsingleton PUnit 0
end Spa end Spa