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>
218 lines
8.4 KiB
Text
218 lines
8.4 KiB
Text
/-
|
||
CubicalTransport.Inductive
|
||
==========================
|
||
Helper combinators and canonical schema instances for the REL1
|
||
schema-based inductive (and higher-inductive) type system.
|
||
|
||
Universe-aware (Layer 0 §0.1 cascade): helpers that take CType
|
||
arguments are level-polymorphic via implicit `{ℓ : ULevel}`; lists
|
||
of parameters carry their levels via `Σ ℓ : ULevel, CType ℓ`.
|
||
|
||
This module sits *on top of* `Syntax.lean` — it doesn't add new
|
||
primitives, only ergonomic builders.
|
||
|
||
## Sections
|
||
|
||
· §1 Argument-shape helpers
|
||
· §2 Schema constructors (mkSchema, mkCtor, mkPath)
|
||
· §3 Type-level helpers (CType.list, CType.nat, …, CType.s1, …)
|
||
· §4 Term-level helpers (zeroC, succC, nilC, consC, baseC, loopC, …)
|
||
· §5 Eliminator builders (natElim, listElim, …)
|
||
|
||
## Design notes
|
||
|
||
· Boundary clauses inside HIT path constructors reference *dim args*
|
||
via `DimVar.mk "$d_k"` (zero-indexed among `.dim` args) and
|
||
*non-dim args* via `CTerm.var "$arg_k"` (zero-indexed in the full
|
||
arg list). See INDUCTIVE_TYPES.md §4 for the discipline.
|
||
-/
|
||
|
||
import CubicalTransport.Syntax
|
||
|
||
namespace CubicalTransport.Inductive
|
||
|
||
-- ── §1. Argument-shape helpers ─────────────────────────────────────────────
|
||
|
||
/-- A non-recursive argument of a closed CType at any universe level. -/
|
||
@[inline] def argType {ℓ : ULevel} (A : CType ℓ) : CTypeArg := .type A
|
||
|
||
/-- A reference to the schema's `i`th type parameter. -/
|
||
@[inline] def argParam (i : Nat) : CTypeArg := .param i
|
||
|
||
/-- A recursive argument of the inductive being defined. -/
|
||
@[inline] def argSelf : CTypeArg := .self
|
||
|
||
/-- A dimension argument (path-constructor binder). -/
|
||
@[inline] def argDim : CTypeArg := .dim
|
||
|
||
-- ── §2. Schema constructors ────────────────────────────────────────────────
|
||
|
||
/-- A point constructor (no boundary system, empty boundary list). -/
|
||
@[inline] def mkCtor (name : String) (args : List CTypeArg) : CtorSpec :=
|
||
.mk name args []
|
||
|
||
/-- A path constructor: a constructor whose argument list contains at
|
||
least one `.dim` arg, and whose boundary system specifies the
|
||
canonical reduction on the corresponding cube faces. -/
|
||
@[inline] def mkPath (name : String) (args : List CTypeArg)
|
||
(boundary : List (FaceFormula × CTerm)) : CtorSpec :=
|
||
.mk name args boundary
|
||
|
||
/-- Build a schema from name, parameter count, and constructor list. -/
|
||
@[inline] def mkSchema (name : String) (numParams : Nat)
|
||
(ctors : List CtorSpec) : CTypeSchema :=
|
||
.mk name numParams ctors
|
||
|
||
-- ── §3. Canonical plain inductive schemas ──────────────────────────────────
|
||
|
||
/-- The natural numbers as a schema. -/
|
||
def natSchema : CTypeSchema :=
|
||
mkSchema "Nat" 0
|
||
[ mkCtor "zero" []
|
||
, mkCtor "succ" [.self] ]
|
||
|
||
/-- The booleans as a schema. -/
|
||
def boolSchema : CTypeSchema :=
|
||
mkSchema "Bool" 0
|
||
[ mkCtor "false" []
|
||
, mkCtor "true" [] ]
|
||
|
||
/-- Polymorphic lists as a schema, parameterised by the element type. -/
|
||
def listSchema : CTypeSchema :=
|
||
mkSchema "List" 1
|
||
[ mkCtor "nil" []
|
||
, mkCtor "cons" [.param 0, .self] ]
|
||
|
||
-- ── §4. Canonical HIT schemas ──────────────────────────────────────────────
|
||
|
||
/-- The circle `S¹` as a HIT. `loop @ 0 = base = loop @ 1`. -/
|
||
def s1Schema : CTypeSchema :=
|
||
let baseAt (s : CTypeSchema) : CTerm := .ctor s "base" [] []
|
||
let stub : CTypeSchema :=
|
||
mkSchema "S¹" 0
|
||
[ mkCtor "base" []
|
||
, mkPath "loop" [.dim] [] ]
|
||
let d : DimVar := ⟨"$d_0"⟩
|
||
mkSchema "S¹" 0
|
||
[ mkCtor "base" []
|
||
, mkPath "loop" [.dim]
|
||
[ (.eq0 d, baseAt stub)
|
||
, (.eq1 d, baseAt stub) ] ]
|
||
|
||
/-- The interval as a HIT (REL1). `seg @ 0 = zero`, `seg @ 1 = one`. -/
|
||
def intervalSchema : CTypeSchema :=
|
||
let stub : CTypeSchema :=
|
||
mkSchema "I" 0
|
||
[ mkCtor "zero" []
|
||
, mkCtor "one" []
|
||
, mkPath "seg" [.dim] [] ]
|
||
let zeroAt (s : CTypeSchema) : CTerm := .ctor s "zero" [] []
|
||
let oneAt (s : CTypeSchema) : CTerm := .ctor s "one" [] []
|
||
let d : DimVar := ⟨"$d_0"⟩
|
||
mkSchema "I" 0
|
||
[ mkCtor "zero" []
|
||
, mkCtor "one" []
|
||
, mkPath "seg" [.dim]
|
||
[ (.eq0 d, zeroAt stub)
|
||
, (.eq1 d, oneAt stub) ] ]
|
||
|
||
/-- Propositional truncation `‖A‖₋₁` as a HIT. -/
|
||
def propTruncSchema : CTypeSchema :=
|
||
let d : DimVar := ⟨"$d_0"⟩
|
||
mkSchema "‖_‖₋₁" 1
|
||
[ mkCtor "inT" [.param 0]
|
||
, mkPath "squash" [.self, .self, .dim]
|
||
[ (.eq0 d, .var "$arg_0")
|
||
, (.eq1 d, .var "$arg_1") ] ]
|
||
|
||
-- ── §5. Type-level helpers ─────────────────────────────────────────────────
|
||
|
||
/-- The `CType` for natural numbers, at the bottom universe. -/
|
||
@[inline] def CType.natC : CType .zero := .ind natSchema []
|
||
|
||
/-- The `CType` for booleans, at the bottom universe. -/
|
||
@[inline] def CType.boolC : CType .zero := .ind boolSchema []
|
||
|
||
/-- The `CType` for lists with element type `A` at level ℓ. The list
|
||
type lives at the same level as its element. -/
|
||
@[inline] def CType.listC {ℓ : ULevel} (A : CType ℓ) : CType ℓ :=
|
||
.ind listSchema [⟨ℓ, A⟩]
|
||
|
||
/-- The cubical interval `𝕀` as a CType (REL2). Lives at the bottom
|
||
universe. Inhabited by `CTerm.dimExpr r` for any `r : DimExpr`. -/
|
||
@[inline] def CType.intervalC : CType .zero := .interval
|
||
|
||
/-- The `CType` for the circle, at the bottom universe. -/
|
||
@[inline] def CType.s1C : CType .zero := .ind s1Schema []
|
||
|
||
/-- The HIT-encoded interval as a CType (REL1 form). -/
|
||
@[inline] def CType.intervalHitC : CType .zero := .ind intervalSchema []
|
||
|
||
/-- The `CType` for propositional truncation `‖A‖₋₁`. -/
|
||
@[inline] def CType.propTruncC {ℓ : ULevel} (A : CType ℓ) : CType ℓ :=
|
||
.ind propTruncSchema [⟨ℓ, A⟩]
|
||
|
||
-- ── §6. Term-level helpers ─────────────────────────────────────────────────
|
||
|
||
namespace CTerm
|
||
|
||
/-- The `CTerm` `zero : Nat`. -/
|
||
@[inline] def zeroC : CTerm := .ctor natSchema "zero" [] []
|
||
|
||
/-- The `CTerm` `succ n` for a given `n : Nat`. -/
|
||
@[inline] def succC (n : CTerm) : CTerm := .ctor natSchema "succ" [] [n]
|
||
|
||
/-- The `CTerm` `false : Bool`. -/
|
||
@[inline] def falseC : CTerm := .ctor boolSchema "false" [] []
|
||
|
||
/-- The `CTerm` `true : Bool`. -/
|
||
@[inline] def trueC : CTerm := .ctor boolSchema "true" [] []
|
||
|
||
/-- The `CTerm` `nil : List A`. `A` is the element CType at any level. -/
|
||
@[inline] def nilC {ℓ : ULevel} (A : CType ℓ) : CTerm :=
|
||
.ctor listSchema "nil" [⟨ℓ, A⟩] []
|
||
|
||
/-- The `CTerm` `cons x xs : List A`. -/
|
||
@[inline] def consC {ℓ : ULevel} (A : CType ℓ) (x xs : CTerm) : CTerm :=
|
||
.ctor listSchema "cons" [⟨ℓ, A⟩] [x, xs]
|
||
|
||
/-- The `CTerm` `base : S¹`. -/
|
||
@[inline] def baseC : CTerm := .ctor s1Schema "base" [] []
|
||
|
||
/-- The `CTerm` `loop @ r : S¹` where `r : DimExpr`. -/
|
||
@[inline] def loopC (r : DimExpr) : CTerm :=
|
||
.ctor s1Schema "loop" [] [.dimExpr r]
|
||
|
||
/-- The `CTerm` `inT a : ‖A‖₋₁`. -/
|
||
@[inline] def inTC {ℓ : ULevel} (A : CType ℓ) (a : CTerm) : CTerm :=
|
||
.ctor propTruncSchema "inT" [⟨ℓ, A⟩] [a]
|
||
|
||
/-- The `CTerm` `squash x y @ r : ‖A‖₋₁`. -/
|
||
@[inline] def squashC {ℓ : ULevel} (A : CType ℓ) (x y : CTerm) (r : DimExpr) : CTerm :=
|
||
.ctor propTruncSchema "squash" [⟨ℓ, A⟩] [x, y, .dimExpr r]
|
||
|
||
/-- Build a Nat literal `n` as a tower of `succ`s on `zero`. -/
|
||
def natLit : Nat → CTerm
|
||
| 0 => zeroC
|
||
| n + 1 => succC (natLit n)
|
||
|
||
end CTerm
|
||
|
||
-- ── §7. Eliminator builders ────────────────────────────────────────────────
|
||
|
||
/-- Build an `indElim` for `Nat`. -/
|
||
def natElim (motive caseZero caseSucc target : CTerm) : CTerm :=
|
||
.indElim natSchema [] motive
|
||
[("zero", caseZero), ("succ", caseSucc)] target
|
||
|
||
/-- Build an `indElim` for `Bool`. -/
|
||
def boolElim (motive caseFalse caseTrue target : CTerm) : CTerm :=
|
||
.indElim boolSchema [] motive
|
||
[("false", caseFalse), ("true", caseTrue)] target
|
||
|
||
/-- Build an `indElim` for `List A`. -/
|
||
def listElim {ℓ : ULevel} (A : CType ℓ) (motive caseNil caseCons target : CTerm) : CTerm :=
|
||
.indElim listSchema [⟨ℓ, A⟩] motive
|
||
[("nil", caseNil), ("cons", caseCons)] target
|
||
|
||
end CubicalTransport.Inductive
|