Some checks failed
Lean Action CI / build (push) Has been cancelled
Two structural changes landed together as one coherent body of work.
## 1. Engine is name-clean from higher-order projects
The engine no longer carries "topolei" in its own naming surface.
Higher-order projects depend on the engine, not vice versa, so the
engine should be self-named.
topolei-cubical (Cargo) → cubical-transport
libtopolei_cubical.a → libcubical_transport.a
topolei_cubical.h → cubical_transport.h
TOPOLEI_FFI_ABI_VERSION → CUBICAL_TRANSPORT_ABI_VERSION
topolei_cubical_* (14 FFI fns) → cubical_transport_*
topolei_shim_* (9 shim fns) → cubical_transport_shim_*
Inter-repo references describing topolei as a downstream consumer
(README, KERNEL_BOUNDARY.md, INDUCTIVE_TYPES.md, etc.) are preserved
as legitimate dependency-direction descriptions.
## 2. Universe-stratified, dependently-typed CType
CType : ULevel → Type (genuinely indexed inductive)
with dependent pi/sigma carrying a binder name, a lift constructor
for cumulativity, and parameter lists of Σ-packaged types.
Per CCHM rules:
· univ ℓ : CType (ℓ.succ)
· pi/sigma : CType (max ℓ_A ℓ_B), with named binder
· path A : at A's level
· glue T A : T and A at same level
· ind : at user-chosen level (heterogeneous-level params)
· interval : CType .zero
· lift : CType (ℓ.succ), data-preserving
Every existing engine module cascades through {ℓ : ULevel} implicits
on functions/theorems, pi/sigma binder updates, and Σ-packaged params
lists. CTerm stays un-indexed (universe lives on CType).
## 3. Substrate machinery for the cascade
Universe.lean — ULevel inductive + max algebra (assoc, comm, etc.),
all theorems proven structurally.
Syntax.lean — adds SkeletalCType enum + CType.skeleton level-erasure
projection + per-constructor skeleton_* simp lemmas +
CType.ind_skeleton_ne_pi disjointness lemma. Used to
discharge cross-level HEq cases in TransportLaws/CompLaws
without invoking K.
## 4. Rust ABI v3 → v4
Lean 4 keeps implicit {ℓ : ULevel} parameters at runtime as constructor
fields, in declaration order interleaved with explicit args (verified
via probeLayout instrumentation). Layout for level-bearing constructors
documented in cubical_transport.h §"v4 layout tables".
CType.pi : 5 fields — [ℓ_d, ℓ_c, var, A, B]
CType.path : 4 fields — [ℓ, A, a, b]
CType.glue : 9 fields — [ℓ, φ, T, f, fInv, sec, ret, coh, A]
CType.ind : 3 fields — [ℓ, S, params]
CType.lift : 2 fields — [ℓ, A]
CTerm.transp : 5 fields — [i, ℓ, A, φ, t] (i precedes ℓ)
CVal.vCompFun : 9 fields — [ℓ_d, ℓ_c, env, i, dom, cod, φ, u, t]
... etc
All Rust marshalling (value.rs, eval.rs, transport.rs, composition.rs,
glue.rs, beta.rs, dim_absent.rs, readback.rs, subst.rs, ffi.rs, tags.rs)
updated to match.
## Discipline
· Zero sorry in CubicalTransport/.
· Zero noncomputable instances; zero Classical.propDecidable shortcuts.
· No CType.level projection (the level lives in the inductive's index).
· No parallel CTypeU type.
· No stub substrate types (def Ω := CType.univ etc.).
· Tests restored to full coverage (EvalTest 623 lines, FFITest 351
lines with classifier-runtime tests intact).
## Verification
cd cubical-transport-hott-lean4
lake build # 48 jobs OK
./.lake/build/bin/cubical-test
# ── 49/49 passed ──
# ── 46/46 properties passed ──
# PASS: all smoke + property tests
cd ../topolei
lake build # 90 jobs OK
./.lake/build/bin/probe-test
# ── 7/7 probes passed ──
# PASS: GPU output matches Lean ShaderSemantic
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
199 lines
8.2 KiB
Text
199 lines
8.2 KiB
Text
/-
|
||
CubicalTransport.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 {ℓ : ULevel} (_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 {ℓ : ULevel} (A : CType ℓ) :
|
||
(idEquiv A).f = .lam EquivData.idEquivVar (.var EquivData.idEquivVar) := rfl
|
||
|
||
theorem fInv_def {ℓ : ULevel} (A : CType ℓ) :
|
||
(idEquiv A).fInv = .lam EquivData.idEquivVar (.var EquivData.idEquivVar) := rfl
|
||
|
||
theorem sec_def {ℓ : ULevel} (A : CType ℓ) :
|
||
(idEquiv A).sec =
|
||
.lam EquivData.idEquivVar
|
||
(.plam EquivData.idEquivDim (.var EquivData.idEquivVar)) := rfl
|
||
|
||
theorem ret_def {ℓ : ULevel} (A : CType ℓ) :
|
||
(idEquiv A).ret =
|
||
.lam EquivData.idEquivVar
|
||
(.plam EquivData.idEquivDim (.var EquivData.idEquivVar)) := rfl
|
||
|
||
theorem coh_def {ℓ : ULevel} (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 : ULevel} (A : CType ℓA) (B : CType ℓB) :
|
||
(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 {ℓ : ULevel} (Γ : 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 {ℓ : ULevel} (Γ : 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). -/
|
||
theorem hasType_sec_refl {ℓ : ULevel} (Γ : 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)))
|
||
exact HasType.lam (HasType.plam (HasType.var (by simp)))
|
||
|
||
/-- `(idEquiv A).ret : A → Path A x x`. -/
|
||
theorem hasType_ret_refl {ℓ : ULevel} (Γ : 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)`. -/
|
||
theorem hasType_coh_refl_refl {ℓ : ULevel} (Γ : 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
|