Files
agda-spa/lean/Spa/Lattice/IterProd.lean
Danila Fedorin 781d7947e0 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

77 lines
2.7 KiB
Lean4
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/-
Port of `Lattice/IterProd.agda`: the `k`-fold product `A × (A ×× B)`.
With propositional equality and typeclasses, the Agda `Everything` record
(which threaded the lattice operations and the conditional fixed-height proof
through one recursion, so that the operations built by separate recursions
would agree) is no longer needed: the `Lattice` instance is one recursive
definition, and the fixed-height structure is another recursion over it.
Correspondence:
IterProd ↦ Spa.IterProd
build ↦ Spa.IterProd.build
isLattice/lattice ↦ instance Spa.IterProd.instLattice
fixedHeight,
isFiniteHeightLattice,
finiteHeightLattice ↦ Spa.IterProd.fixedHeight (+ FiniteHeightLattice instance)
-built ↦ Spa.IterProd.bot_fixedHeight
-/
import Spa.Lattice.Prod
import Spa.Lattice.Unit
import Mathlib.Tactic.Ring
namespace Spa
universe u
/-- Agda: `IterProd k = iterate k (A × ·) B`. (As in the Agda module, `A` and
`B` are constrained to the same universe to keep the recursion simple.) -/
def IterProd (A B : Type u) : Type u
| 0 => B
| k + 1 => A × IterProd A B k
namespace IterProd
variable {A B : Type u}
instance instLattice [Lattice A] [Lattice B] :
k, Lattice (IterProd A B k)
| 0 => inferInstanceAs (Lattice B)
| k + 1 => @Prod.instLattice A (IterProd A B k) _ (instLattice k)
instance instDecidableEq [DecidableEq A] [DecidableEq B] :
k, DecidableEq (IterProd A B k)
| 0 => inferInstanceAs (DecidableEq B)
| k + 1 => @instDecidableEqProd A (IterProd A B k) _ (instDecidableEq k)
/-- Agda: `build`. -/
def build (a : A) (b : B) : (k : ) IterProd A B k
| 0 => b
| k + 1 => (a, build a b k)
variable [Lattice A] [Lattice B]
/-- Agda: `fixedHeight` (the `isFiniteHeightIfSupported` recursion). -/
def fixedHeight {hA hB : } (fhA : FixedHeight A hA) (fhB : FixedHeight B hB) :
(k : ) FixedHeight (IterProd A B k) (k * hA + hB)
| 0 => fhB.cast (by ring)
| k + 1 => (fhA.prod (fixedHeight fhA fhB k)).cast (by ring)
/-- Agda: `⊥-built` — the bottom of the iterated product is built from the
component bottoms. -/
theorem bot_fixedHeight {hA hB : } (fhA : FixedHeight A hA) (fhB : FixedHeight B hB) :
k, (fixedHeight fhA fhB k).bot = build fhA.bot fhB.bot k
| 0 => rfl
| k + 1 => by
show (fhA.bot, (fixedHeight fhA fhB k).bot) = (fhA.bot, build fhA.bot fhB.bot k)
rw [bot_fixedHeight fhA fhB k]
instance [IA : FiniteHeightLattice A] [IB : FiniteHeightLattice B] (k : ) :
FiniteHeightLattice (IterProd A B k) where
height := k * IA.height + IB.height
fixedHeight := fixedHeight IA.fixedHeight IB.fixedHeight k
end IterProd
end Spa