Some checks are pending
Lean Action CI / build (push) Waiting to run
Restructure to engine-only contents. Application code (Topolei.*
namespace, canvas-rs / render Rust crates, Main / ProbeTest, naga IR
pipeline, Selection / Subobject / Trace / Obs.Ctx hypothesis stack,
cells-spec / HYPOTHESES / STATUS / NAGA_IR_PLAN docs) moves to the
sibling repo max/topolei.
What moved:
- `Topolei/Cubical/*.lean` (22 files) → `CubicalTransport/*.lean`
with namespace `Topolei.Cubical.*` renamed to `CubicalTransport.*`.
Fully-qualified test types `TopoleiCubical{FFI,Property}Test` →
`CubicalTransport{FFI,Property}Test` for consistency.
- New root file `CubicalTransport.lean` re-exporting all 22 modules.
- Lakefile: package `cubicalTransport`; lib `CubicalTransport`; only
`cubical-test` and `cubical-bench` exes (no GPU link path).
The split criterion: anything an AI shortcut could break that would
cascade-corrupt downstream proofs lives here. Anything that would
only break the application stays in the topolei interface repo.
cubical-test passes 62/62 (smoke + properties) on the renamed engine.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
216 lines
8.9 KiB
Text
216 lines
8.9 KiB
Text
/-
|
|
Topolei.Cubical.Equiv
|
|
=====================
|
|
Half-adjoint equivalences between cubical types (cells-spec §5.8).
|
|
|
|
`EquivData` packages a forward map, inverse, section, retraction, and a
|
|
coherence 2-cell. It is the parameter for `Glue` types in §5.7.
|
|
|
|
Shape: we store the five components as raw `CTerm`s rather than as a
|
|
Σ-type of such, because CType does not yet have a Σ constructor. Typing
|
|
(that `f : A → B`, `fInv : B → A`, etc.) is a per-use proof obligation;
|
|
inhabitants such as `idEquiv` exhibit the shape directly and the boundary
|
|
reductions fall out from substDim on term variables.
|
|
|
|
The half-adjoint discipline follows HoTT Book §4.2:
|
|
f : A → B forward map
|
|
fInv: B → A inverse
|
|
sec : Π b : B. Path B (f (fInv b)) b ε (section)
|
|
ret : Π a : A. Path A (fInv (f a)) a η (retraction)
|
|
coh : Π a : A. Path (Path B (f a) (f a))
|
|
(ap f (ret a))
|
|
(sec (f a)) τ (coherence)
|
|
|
|
In our non-dependent Π, the inner types depend on the outer λ's bound
|
|
variable through `CTerm` endpoints (which can reference any term variable).
|
|
|
|
Fiber types / contractibility of fibers are intentionally deferred: they
|
|
need `.sigma` on `CType`, which is not yet in the syntax (STATUS.md
|
|
"Priority order" item 3).
|
|
-/
|
|
|
|
import CubicalTransport.Typing
|
|
|
|
-- ── Equivalence data ─────────────────────────────────────────────────────────
|
|
|
|
/-- Half-adjoint equivalence between two types, represented as five `CTerm`s. -/
|
|
structure EquivData where
|
|
/-- Forward map `f : A → B`. -/
|
|
f : CTerm
|
|
/-- Inverse map `fInv : B → A`. -/
|
|
fInv : CTerm
|
|
/-- Section `ε : Π b. Path B (f (fInv b)) b`. -/
|
|
sec : CTerm
|
|
/-- Retraction `η : Π a. Path A (fInv (f a)) a`. -/
|
|
ret : CTerm
|
|
/-- Coherence 2-cell `τ : Π a. Path (Path B (f a) (f a))
|
|
(ap f (ret a))
|
|
(sec (f a))`. -/
|
|
coh : CTerm
|
|
deriving Repr
|
|
|
|
-- ── Named-variable hygiene constants ─────────────────────────────────────────
|
|
-- Reserved names for the identity equivalence's bound variables.
|
|
-- Chosen with `$` prefixes to avoid collision with user code, consistent
|
|
-- with the `"$y"` / `⟨"$fj"⟩` convention used by `vApp vCompFun`.
|
|
|
|
namespace EquivData
|
|
|
|
/-- Reserved term variable for the identity equivalence's forward / inverse
|
|
bound argument. User code using `$`-prefixed names is assumed absent. -/
|
|
def idEquivVar : String := "$x"
|
|
|
|
/-- Reserved dimension variable for the sec/ret path. -/
|
|
def idEquivDim : DimVar := ⟨"$e"⟩
|
|
|
|
/-- Reserved outer dimension variable for the coherence 2-cell. -/
|
|
def idEquivDimOuter : DimVar := ⟨"$eo"⟩
|
|
|
|
/-- Reserved inner dimension variable for the coherence 2-cell. -/
|
|
def idEquivDimInner : DimVar := ⟨"$ei"⟩
|
|
|
|
end EquivData
|
|
|
|
-- ── Identity equivalence ─────────────────────────────────────────────────────
|
|
|
|
/-- The identity equivalence on any type `A`.
|
|
|
|
All five components are constant in their path arguments:
|
|
f = λx. x
|
|
fInv = λx. x
|
|
sec = λx. ⟨e⟩ x -- refl_x
|
|
ret = λx. ⟨e⟩ x -- refl_x
|
|
coh = λx. ⟨eo⟩⟨ei⟩ x -- refl_refl_x (constant 2-cell)
|
|
|
|
`A` is not mentioned in the term structure; the types are implied by
|
|
the calling context (e.g., a `HasType` derivation or a `.glue` face).
|
|
This matches CCHM's treatment where `idEquiv` is universe-polymorphic
|
|
and the type is inferred. -/
|
|
def idEquiv (_A : CType) : EquivData :=
|
|
let x := EquivData.idEquivVar
|
|
let e := EquivData.idEquivDim
|
|
let eo := EquivData.idEquivDimOuter
|
|
let ei := EquivData.idEquivDimInner
|
|
{ f := .lam x (.var x)
|
|
fInv := .lam x (.var x)
|
|
sec := .lam x (.plam e (.var x))
|
|
ret := .lam x (.plam e (.var x))
|
|
coh := .lam x (.plam eo (.plam ei (.var x))) }
|
|
|
|
-- ── Projection rfl-lemmas ────────────────────────────────────────────────────
|
|
-- These are not strictly necessary (the definition is transparent) but they
|
|
-- let downstream code rewrite through `idEquiv` without unfolding.
|
|
|
|
namespace idEquiv
|
|
|
|
theorem f_def (A : CType) :
|
|
(idEquiv A).f = .lam EquivData.idEquivVar (.var EquivData.idEquivVar) := rfl
|
|
|
|
theorem fInv_def (A : CType) :
|
|
(idEquiv A).fInv = .lam EquivData.idEquivVar (.var EquivData.idEquivVar) := rfl
|
|
|
|
theorem sec_def (A : CType) :
|
|
(idEquiv A).sec =
|
|
.lam EquivData.idEquivVar
|
|
(.plam EquivData.idEquivDim (.var EquivData.idEquivVar)) := rfl
|
|
|
|
theorem ret_def (A : CType) :
|
|
(idEquiv A).ret =
|
|
.lam EquivData.idEquivVar
|
|
(.plam EquivData.idEquivDim (.var EquivData.idEquivVar)) := rfl
|
|
|
|
theorem coh_def (A : CType) :
|
|
(idEquiv A).coh =
|
|
.lam EquivData.idEquivVar
|
|
(.plam EquivData.idEquivDimOuter
|
|
(.plam EquivData.idEquivDimInner (.var EquivData.idEquivVar))) := rfl
|
|
|
|
/-- `idEquiv` is constant in its type argument up to the five component terms. -/
|
|
theorem components_independent_of_A (A B : CType) :
|
|
(idEquiv A).f = (idEquiv B).f ∧
|
|
(idEquiv A).fInv = (idEquiv B).fInv ∧
|
|
(idEquiv A).sec = (idEquiv B).sec ∧
|
|
(idEquiv A).ret = (idEquiv B).ret ∧
|
|
(idEquiv A).coh = (idEquiv B).coh :=
|
|
⟨rfl, rfl, rfl, rfl, rfl⟩
|
|
|
|
end idEquiv
|
|
|
|
-- ── Forward map typing for idEquiv ───────────────────────────────────────────
|
|
-- The five components type-check in the empty context. We prove typing for
|
|
-- `f` and `fInv` directly (they are `λx. x`); `sec` and `ret` follow from
|
|
-- `HasType.plam` giving the reflexivity path at `var x` (substDim on a term
|
|
-- variable is identity, so both endpoints are `var x`).
|
|
|
|
namespace idEquiv
|
|
|
|
/-- `(idEquiv A).f : A → A`. -/
|
|
theorem hasType_f (Γ : Ctx) (A : CType) :
|
|
HasType Γ (idEquiv A).f (.pi A A) := by
|
|
show HasType Γ (.lam EquivData.idEquivVar (.var EquivData.idEquivVar)) (.pi A A)
|
|
exact HasType.lam (HasType.var (by simp))
|
|
|
|
/-- `(idEquiv A).fInv : A → A`. -/
|
|
theorem hasType_fInv (Γ : Ctx) (A : CType) :
|
|
HasType Γ (idEquiv A).fInv (.pi A A) :=
|
|
hasType_f Γ A
|
|
|
|
/-- `(idEquiv A).sec : A → Path A x x` (reflexivity at the bound variable).
|
|
|
|
Under our non-dependent Π, the codomain is a fixed `CType` whose path
|
|
endpoints reference the bound term variable `$x`. `HasType.plam` on a
|
|
term variable gives a path whose boundaries are both `.var x` because
|
|
`substDim` does not descend into term variables.
|
|
|
|
Note: this does *not* match the "full" section type
|
|
`Path A (f (fInv x)) x` because identity-of-β-reduction is not part of
|
|
our typing relation. We return the propositionally-reduced type. -/
|
|
theorem hasType_sec_refl (Γ : Ctx) (A : CType) :
|
|
HasType Γ (idEquiv A).sec
|
|
(.pi A (.path A
|
|
(CTerm.var EquivData.idEquivVar)
|
|
(CTerm.var EquivData.idEquivVar))) := by
|
|
show HasType Γ
|
|
(.lam EquivData.idEquivVar
|
|
(.plam EquivData.idEquivDim (.var EquivData.idEquivVar)))
|
|
(.pi A (.path A (.var EquivData.idEquivVar) (.var EquivData.idEquivVar)))
|
|
-- plam gives Path A (var[i:=0]) (var[i:=1]) = Path A (var x) (var x) since
|
|
-- CTerm.substDim does not descend into term variables.
|
|
exact HasType.lam (HasType.plam (HasType.var (by simp)))
|
|
|
|
/-- `(idEquiv A).ret : A → Path A x x`. -/
|
|
theorem hasType_ret_refl (Γ : Ctx) (A : CType) :
|
|
HasType Γ (idEquiv A).ret
|
|
(.pi A (.path A
|
|
(CTerm.var EquivData.idEquivVar)
|
|
(CTerm.var EquivData.idEquivVar))) :=
|
|
hasType_sec_refl Γ A
|
|
|
|
/-- `(idEquiv A).coh : A → Path (Path A x x) (⟨ei⟩ x) (⟨ei⟩ x)`.
|
|
|
|
The inner plam gives `Path A x x` (by the same argument as `sec`); the
|
|
outer plam gives a path between two copies of `⟨ei⟩ x` — because the
|
|
outer `substDim eo` leaves `plam ei (var x)` alone (the var is a term
|
|
variable, unaffected by dim substitution). This is the "constant
|
|
2-cell at refl". -/
|
|
theorem hasType_coh_refl_refl (Γ : Ctx) (A : CType) :
|
|
HasType Γ (idEquiv A).coh
|
|
(.pi A
|
|
(.path
|
|
(.path A
|
|
(CTerm.var EquivData.idEquivVar)
|
|
(CTerm.var EquivData.idEquivVar))
|
|
(CTerm.plam EquivData.idEquivDimInner
|
|
(CTerm.var EquivData.idEquivVar))
|
|
(CTerm.plam EquivData.idEquivDimInner
|
|
(CTerm.var EquivData.idEquivVar)))) := by
|
|
show HasType Γ
|
|
(.lam EquivData.idEquivVar
|
|
(.plam EquivData.idEquivDimOuter
|
|
(.plam EquivData.idEquivDimInner (.var EquivData.idEquivVar))))
|
|
_
|
|
exact HasType.lam
|
|
(HasType.plam
|
|
(HasType.plam (HasType.var (by simp))))
|
|
|
|
end idEquiv
|