2026-06-25 13:28:30 -05:00
|
|
|
|
import Spa.Lattice.Tuple
|
|
|
|
|
|
import Mathlib.Data.List.Nodup
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
namespace Spa
|
|
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
def FiniteMap (A B : Type*) (ks : List A) : Type _ := Fin ks.length → B
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
namespace FiniteMap
|
|
|
|
|
|
|
|
|
|
|
|
variable {A B : Type*} {ks : List A}
|
|
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
instance [Lattice B] : Lattice (FiniteMap A B ks) :=
|
|
|
|
|
|
inferInstanceAs (Lattice (Fin ks.length → B))
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
instance [Lattice B] [FiniteHeightLattice B] : FiniteHeightLattice (FiniteMap A B ks) :=
|
|
|
|
|
|
inferInstanceAs (FiniteHeightLattice (Fin ks.length → B))
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
instance [DecidableEq B] : DecidableEq (FiniteMap A B ks) :=
|
|
|
|
|
|
inferInstanceAs (DecidableEq (Fin ks.length → B))
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
instance : Membership (A × B) (FiniteMap A B ks) :=
|
2026-06-25 13:28:30 -05:00
|
|
|
|
⟨fun fm p => ∃ i : Fin ks.length, ks.get i = p.1 ∧ fm i = p.2⟩
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
theorem mem_iff {fm : FiniteMap A B ks} {p : A × B} :
|
|
|
|
|
|
p ∈ fm ↔ ∃ i : Fin ks.length, ks.get i = p.1 ∧ fm i = p.2 := Iff.rfl
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
def MemKey (k : A) (_fm : FiniteMap A B ks) : Prop := k ∈ ks
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
theorem MemKey_iff {k : A} {fm : FiniteMap A B ks} : MemKey k fm ↔ k ∈ ks := Iff.rfl
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
instance {k : A} {fm : FiniteMap A B ks} [DecidableEq A] : Decidable (MemKey k fm) :=
|
|
|
|
|
|
decidable_of_iff _ MemKey_iff.symm
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
theorem mem_key_of_mem {k : A} {v : B} {fm : FiniteMap A B ks}
|
2026-06-25 13:28:30 -05:00
|
|
|
|
(h : (k, v) ∈ fm) : MemKey k fm := by
|
|
|
|
|
|
obtain ⟨i, hi, _⟩ := h
|
|
|
|
|
|
have hik : ks.get i = k := hi
|
|
|
|
|
|
exact hik ▸ ks.get_mem i
|
|
|
|
|
|
|
|
|
|
|
|
def toList (fm : FiniteMap A B ks) : List (A × B) :=
|
|
|
|
|
|
(List.finRange ks.length).map fun i => (ks.get i, fm i)
|
|
|
|
|
|
|
|
|
|
|
|
theorem le_def [Lattice B] {fm₁ fm₂ : FiniteMap A B ks} :
|
|
|
|
|
|
fm₁ ≤ fm₂ ↔ ∀ i, fm₁ i ≤ fm₂ i := Iff.rfl
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
section Locate
|
|
|
|
|
|
|
|
|
|
|
|
variable [DecidableEq A]
|
|
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
/-- Recover the value stored under a present key. -/
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
def locate {k : A} {fm : FiniteMap A B ks} (h : MemKey k fm) :
|
|
|
|
|
|
{v : B // (k, v) ∈ fm} :=
|
2026-06-25 13:28:30 -05:00
|
|
|
|
let i : Fin ks.length := ⟨ks.idxOf k, List.idxOf_lt_length_iff.mpr h⟩
|
|
|
|
|
|
⟨fm i, i, List.idxOf_get _, rfl⟩
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
end Locate
|
|
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
variable [Lattice B]
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
theorem le_of_mem_mem (hks : ks.Nodup) {fm₁ fm₂ : FiniteMap A B ks}
|
|
|
|
|
|
(hle : fm₁ ≤ fm₂) {k : A} {v₁ v₂ : B}
|
2026-06-25 13:28:30 -05:00
|
|
|
|
(h₁ : (k, v₁) ∈ fm₁) (h₂ : (k, v₂) ∈ fm₂) : v₁ ≤ v₂ := by
|
|
|
|
|
|
obtain ⟨i, hi, rfl⟩ := h₁
|
|
|
|
|
|
obtain ⟨j, hj, rfl⟩ := h₂
|
|
|
|
|
|
have hij : i = j := hks.get_inj_iff.mp (hi.trans hj.symm)
|
|
|
|
|
|
subst hij
|
|
|
|
|
|
exact le_def.mp hle i
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
theorem mem_sup {fm₁ fm₂ : FiniteMap A B ks} {k : A} {v : B}
|
|
|
|
|
|
(h : (k, v) ∈ fm₁ ⊔ fm₂) :
|
2026-06-25 13:28:30 -05:00
|
|
|
|
∃ v₁ v₂, v = v₁ ⊔ v₂ ∧ (k, v₁) ∈ fm₁ ∧ (k, v₂) ∈ fm₂ := by
|
|
|
|
|
|
obtain ⟨i, hi, rfl⟩ := h
|
|
|
|
|
|
exact ⟨fm₁ i, fm₂ i, rfl, ⟨i, hi, rfl⟩, ⟨i, hi, rfl⟩⟩
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
section Updating
|
|
|
|
|
|
|
|
|
|
|
|
variable [DecidableEq A]
|
|
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
def updating (fm : FiniteMap A B ks) (ks' : List A) (g : A → B) : FiniteMap A B ks :=
|
|
|
|
|
|
fun i => if ks.get i ∈ ks' then g (ks.get i) else fm i
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
omit [Lattice B] in
|
|
|
|
|
|
theorem eq_of_mem_updating {k : A} {v : B} {fm : FiniteMap A B ks}
|
|
|
|
|
|
{ks' : List A} {g : A → B} (hk : k ∈ ks')
|
|
|
|
|
|
(h : (k, v) ∈ updating fm ks' g) : v = g k := by
|
2026-06-25 13:28:30 -05:00
|
|
|
|
obtain ⟨i, hi, rfl⟩ := h
|
|
|
|
|
|
show (if ks.get i ∈ ks' then g (ks.get i) else fm i) = g k
|
|
|
|
|
|
rw [if_pos (by rw [hi]; exact hk), hi]
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
omit [Lattice B] in
|
|
|
|
|
|
theorem mem_of_mem_updating {k : A} {v : B} {fm : FiniteMap A B ks}
|
|
|
|
|
|
{ks' : List A} {g : A → B} (hk : k ∉ ks')
|
|
|
|
|
|
(h : (k, v) ∈ updating fm ks' g) : (k, v) ∈ fm := by
|
2026-06-25 13:28:30 -05:00
|
|
|
|
obtain ⟨i, hi, rfl⟩ := h
|
|
|
|
|
|
refine ⟨i, hi, ?_⟩
|
|
|
|
|
|
show fm i = (if ks.get i ∈ ks' then g (ks.get i) else fm i)
|
|
|
|
|
|
rw [if_neg (by rw [hi]; exact hk)]
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
theorem updating_mono {fm₁ fm₂ : FiniteMap A B ks} {ks' : List A}
|
|
|
|
|
|
{g₁ g₂ : A → B} (hfm : fm₁ ≤ fm₂) (hg : ∀ k, g₁ k ≤ g₂ k) :
|
|
|
|
|
|
updating fm₁ ks' g₁ ≤ updating fm₂ ks' g₂ := by
|
2026-06-25 13:28:30 -05:00
|
|
|
|
rw [le_def]
|
|
|
|
|
|
intro i
|
|
|
|
|
|
show (if ks.get i ∈ ks' then g₁ (ks.get i) else fm₁ i)
|
|
|
|
|
|
≤ (if ks.get i ∈ ks' then g₂ (ks.get i) else fm₂ i)
|
|
|
|
|
|
split
|
|
|
|
|
|
· exact hg (ks.get i)
|
|
|
|
|
|
· exact le_def.mp hfm i
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
end Updating
|
|
|
|
|
|
|
|
|
|
|
|
section GeneralizedUpdate
|
|
|
|
|
|
|
|
|
|
|
|
variable [DecidableEq A] {L : Type*} [Lattice L]
|
|
|
|
|
|
|
|
|
|
|
|
def generalizedUpdate (f : L → FiniteMap A B ks) (g : A → L → B)
|
2026-06-25 13:28:30 -05:00
|
|
|
|
(ks' : List A) : L → FiniteMap A B ks := fun l =>
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
(f l).updating ks' (fun k => g k l)
|
|
|
|
|
|
|
|
|
|
|
|
variable {f : L → FiniteMap A B ks} {g : A → L → B} {ks' : List A}
|
|
|
|
|
|
|
|
|
|
|
|
theorem generalizedUpdate_monotone (hf : Monotone f)
|
|
|
|
|
|
(hg : ∀ k, Monotone (g k)) : Monotone (generalizedUpdate f g ks') :=
|
|
|
|
|
|
fun _ _ hl => updating_mono (hf hl) (fun k => hg k hl)
|
|
|
|
|
|
|
|
|
|
|
|
omit [Lattice B] [Lattice L] in
|
|
|
|
|
|
theorem generalizedUpdate_mem_eq {k : A} {v : B} {l : L} (hk : k ∈ ks')
|
2026-06-25 13:28:30 -05:00
|
|
|
|
(h : (k, v) ∈ generalizedUpdate f g ks' l) : v = g k l :=
|
|
|
|
|
|
eq_of_mem_updating (g := fun k => g k l) hk h
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
omit [Lattice B] [Lattice L] in
|
|
|
|
|
|
theorem generalizedUpdate_not_mem_backward {k : A} {v : B} {l : L} (hk : k ∉ ks')
|
2026-06-25 13:28:30 -05:00
|
|
|
|
(h : (k, v) ∈ generalizedUpdate f g ks' l) : (k, v) ∈ f l :=
|
|
|
|
|
|
mem_of_mem_updating hk h
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
end GeneralizedUpdate
|
|
|
|
|
|
|
|
|
|
|
|
section ValuesAt
|
|
|
|
|
|
|
|
|
|
|
|
variable [DecidableEq A]
|
|
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
/-- The value stored under `k`, if `k` is a key. -/
|
|
|
|
|
|
private def lookup (fm : FiniteMap A B ks) (k : A) : Option B :=
|
|
|
|
|
|
if h : k ∈ ks then some (fm ⟨ks.idxOf k, List.idxOf_lt_length_iff.mpr h⟩) else none
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
2026-06-25 13:28:30 -05:00
|
|
|
|
/-- The values stored under the keys `ks'` (skipping any that are not keys). -/
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
def valuesAt (fm : FiniteMap A B ks) (ks' : List A) : List B :=
|
2026-06-25 13:28:30 -05:00
|
|
|
|
ks'.filterMap fm.lookup
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
omit [Lattice B] in
|
|
|
|
|
|
theorem mem_valuesAt (hks : ks.Nodup) {fm : FiniteMap A B ks} {k : A} {v : B}
|
2026-06-25 13:28:30 -05:00
|
|
|
|
{ks' : List A} (hk : k ∈ ks') (h : (k, v) ∈ fm) : v ∈ valuesAt fm ks' := by
|
|
|
|
|
|
refine List.mem_filterMap.mpr ⟨k, hk, ?_⟩
|
|
|
|
|
|
obtain ⟨i, hi, rfl⟩ := h
|
|
|
|
|
|
have hik : ks.get i = k := hi
|
|
|
|
|
|
have hmem : k ∈ ks := hik ▸ ks.get_mem i
|
|
|
|
|
|
show (if h : k ∈ ks then
|
|
|
|
|
|
some (fm ⟨ks.idxOf k, List.idxOf_lt_length_iff.mpr h⟩) else none) = some (fm i)
|
|
|
|
|
|
rw [dif_pos hmem]
|
|
|
|
|
|
have : (⟨ks.idxOf k, List.idxOf_lt_length_iff.mpr hmem⟩ : Fin ks.length) = i :=
|
|
|
|
|
|
hks.get_inj_iff.mp (by rw [List.idxOf_get, hi])
|
|
|
|
|
|
rw [this]
|
|
|
|
|
|
|
|
|
|
|
|
private theorem lookup_rel {fm₁ fm₂ : FiniteMap A B ks} (hle : fm₁ ≤ fm₂) (k : A) :
|
|
|
|
|
|
Option.Rel (· ≤ ·) (fm₁.lookup k) (fm₂.lookup k) := by
|
|
|
|
|
|
show Option.Rel _
|
|
|
|
|
|
(if h : k ∈ ks then some (fm₁ ⟨ks.idxOf k, List.idxOf_lt_length_iff.mpr h⟩) else none)
|
|
|
|
|
|
(if h : k ∈ ks then some (fm₂ ⟨ks.idxOf k, List.idxOf_lt_length_iff.mpr h⟩) else none)
|
|
|
|
|
|
by_cases hk : k ∈ ks
|
|
|
|
|
|
· rw [dif_pos hk, dif_pos hk]; exact Option.Rel.some (le_def.mp hle _)
|
|
|
|
|
|
· rw [dif_neg hk, dif_neg hk]; exact Option.Rel.none
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
|
|
|
|
|
|
theorem valuesAt_le {fm₁ fm₂ : FiniteMap A B ks} (hle : fm₁ ≤ fm₂)
|
|
|
|
|
|
(ks' : List A) :
|
|
|
|
|
|
List.Forall₂ (· ≤ ·) (valuesAt fm₁ ks') (valuesAt fm₂ ks') := by
|
|
|
|
|
|
induction ks' with
|
|
|
|
|
|
| nil => exact List.Forall₂.nil
|
|
|
|
|
|
| cons k ks'' ih =>
|
2026-06-25 13:28:30 -05:00
|
|
|
|
have hrel := lookup_rel hle k
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
rw [valuesAt, valuesAt, List.filterMap_cons, List.filterMap_cons]
|
|
|
|
|
|
revert hrel
|
2026-06-25 13:28:30 -05:00
|
|
|
|
generalize fm₁.lookup k = o₁
|
|
|
|
|
|
generalize fm₂.lookup k = o₂
|
Lean migration: Phase 4 (IterProd + FiniteMap lattices)
- Spa.Lattice.IterProd: k-fold product, recursive Lattice instance,
fixed height k*hA + hB, bot = build of bottoms
- Spa.Lattice.FiniteMap: spine-pinned assoc lists ({l // l.map fst = ks});
with = the 1100-line Map.agda collapses into positional 'combine'.
Same lemma inventory (membership, locate, updating, GeneralizedUpdate,
valuesAt, Provenance-union, le_of_mem_mem) — Nodup is now an explicit
hypothesis where the Agda Map carried it intrinsically. Fixed height
|ks|*hB still via transport along the IterProd isomorphism, which no
longer needs Unique ks (representation is canonical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:12:39 -07:00
|
|
|
|
intro hrel
|
|
|
|
|
|
cases hrel with
|
|
|
|
|
|
| none => simpa [valuesAt] using ih
|
|
|
|
|
|
| some hv => exact List.Forall₂.cons hv (by simpa [valuesAt] using ih)
|
|
|
|
|
|
|
|
|
|
|
|
end ValuesAt
|
|
|
|
|
|
|
|
|
|
|
|
end FiniteMap
|
|
|
|
|
|
|
|
|
|
|
|
end Spa
|