cubical-transport-hott-lean4/CubicalTransport/Equiv.lean
Maximus Gorog 19928d040a
Some checks failed
Lean Action CI / build (push) Has been cancelled
REL2 universe stratification + topolei naming cleanup + Rust ABI v4
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>
2026-05-04 00:21:14 -06:00

199 lines
8.2 KiB
Text
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.

/-
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