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>
184 lines
10 KiB
Text
184 lines
10 KiB
Text
/-
|
||
Topolei.Cubical.Syntax
|
||
======================
|
||
Deep embedding of the cubical term language (CCHM §2–3).
|
||
|
||
Grammar:
|
||
A, B ::= U | Π A B | Path A a b
|
||
t, u ::= x | λx.t | t u | ⟨i⟩t | t@r | transpⁱ A φ t | compⁱ A φ u t
|
||
|
||
CType and CTerm are mutually inductive because path types carry endpoint
|
||
terms, and terms carry path applications over DimExprs.
|
||
|
||
transp and comp store (i : DimVar) (A : CType) inline rather than DimLine,
|
||
because DimLine is defined later in the import chain (Subst → DimLine).
|
||
The typing rules in Typing.lean use DimLine as a convenient wrapper.
|
||
|
||
The path β-rule (⟨i⟩ t) @ r ↝ t[i := r]
|
||
and the four "fully-reducing" transport/comp cases (T1, T2, C1, C2)
|
||
are NbE theorems in `Cubical/Readback.lean`. The residual step-level
|
||
axioms — T3, T5, C4 (subject reduction + face congruence) and T4
|
||
(path-line shape preservation) — live in `TransportLaws.lean` /
|
||
`CompLaws.lean`.
|
||
-/
|
||
|
||
import CubicalTransport.Face
|
||
|
||
-- ── Syntax ────────────────────────────────────────────────────────────────────
|
||
|
||
mutual
|
||
/-- Types in the cubical calculus. -/
|
||
inductive CType where
|
||
| univ : CType -- U
|
||
| pi (A : CType) (B : CType) : CType -- Π A B
|
||
| path (A : CType) (a b : CTerm) : CType -- Path A a b
|
||
/-- Non-dependent Σ type (cells-spec §6.2, §8.1, §9.2).
|
||
|
||
`Sigma A B` — pairs whose first component has type `A` and whose
|
||
second has type `B`. Non-dependent: `B` does not refer to the
|
||
first component. Dependent Σ (where `B : A → CType`) is deferred
|
||
for the same reason as dependent Π — requires a term evaluator
|
||
to apply `B` to a term. -/
|
||
| sigma (A B : CType) : CType -- Σ A B
|
||
/-- Glue type (CCHM §6).
|
||
`Glue [φ ↦ (T, e)] A` — on face `φ` the type is `T` with `e : T ≃ A`
|
||
as witness; off face `φ` the type is `A`. The equivalence `e` is
|
||
inlined as five `CTerm` fields (f, fInv, sec, ret, coh) rather than
|
||
a nested `EquivData` so that `CType` / `CTerm` remain a closed
|
||
mutual inductive block — `EquivData` lives in `Equiv.lean` and is
|
||
downstream in the import chain. Use `EquivData.toGlueType` in
|
||
`Equiv.lean` for an ergonomic wrapper. -/
|
||
| glue (φ : FaceFormula) (T : CType)
|
||
(f fInv sec ret coh : CTerm)
|
||
(A : CType) : CType -- Glue [φ ↦ (T, e)] A
|
||
deriving Repr
|
||
|
||
/-- Terms in the cubical calculus. -/
|
||
inductive CTerm where
|
||
| var (x : String) : CTerm -- x
|
||
| lam (x : String) (t : CTerm) : CTerm -- λx. t
|
||
| app (f a : CTerm) : CTerm -- f a
|
||
| plam (i : DimVar) (t : CTerm) : CTerm -- ⟨i⟩ t
|
||
| papp (t : CTerm) (r : DimExpr) : CTerm -- t @ r
|
||
| transp (i : DimVar) (A : CType) (φ : FaceFormula)
|
||
(t : CTerm) : CTerm -- transpⁱ A φ t
|
||
| comp (i : DimVar) (A : CType) (φ : FaceFormula)
|
||
(u t : CTerm) : CTerm -- compⁱ A φ u t
|
||
/-- Multi-clause heterogeneous composition.
|
||
`compⁱ A [φ₁ ↦ u₁, …, φₙ ↦ uₙ] t` — a partial element defined
|
||
over the union of the clause faces. Coherence (clauses agree
|
||
on overlaps and with `t` at `i = 0`) is a typing-level side
|
||
condition, not enforced syntactically. Used by CCHM path
|
||
transport and heterogeneous Π composition to express systems
|
||
that a single-clause `.comp` cannot represent. -/
|
||
| compN (i : DimVar) (A : CType)
|
||
(clauses : List (FaceFormula × CTerm))
|
||
(t : CTerm) : CTerm -- compⁱ A [φ₁↦u₁,…] t
|
||
/-- Glue introduction (CCHM §6.1).
|
||
`glueIn [φ ↦ t] a` — on face `φ`, equals `t : T`; off face `φ`,
|
||
equals `a : A`. Well-typedness requires `e.f t = a` on the
|
||
overlap (a typing-side condition, not enforced syntactically).
|
||
The equivalence `e` is carried by the type, not the term. -/
|
||
| glueIn (φ : FaceFormula) (t a : CTerm) : CTerm -- glue [φ↦t] a
|
||
/-- Glue elimination (CCHM §6.1).
|
||
`unglue [φ ↦ f] g` — extract the underlying `A`-value from a
|
||
glued term. On face `φ`, equals `f g` (apply the forward map);
|
||
off face `φ`, equals `g` (already an `A`-value). `f` is the
|
||
`f`-field of the equivalence witnessing `T ≃ A` — carried
|
||
explicitly at the term level because we don't have type
|
||
annotations on terms. -/
|
||
| unglue (φ : FaceFormula) (f g : CTerm) : CTerm -- unglue [φ↦f] g
|
||
/-- Σ introduction (pair). -/
|
||
| pair (a b : CTerm) : CTerm -- (a, b)
|
||
/-- Σ elimination (first projection). -/
|
||
| fst (t : CTerm) : CTerm -- t.1
|
||
/-- Σ elimination (second projection). -/
|
||
| snd (t : CTerm) : CTerm -- t.2
|
||
deriving Repr
|
||
end
|
||
|
||
-- ── Dimension substitution ────────────────────────────────────────────────────
|
||
-- Substitute dimension variable i with DimExpr r throughout a term.
|
||
--
|
||
-- Scope inside transp/comp:
|
||
-- · j is the binder of the transport line, bound in A and in φ.
|
||
-- · The base term t (and system u) are in outer scope — we substitute there.
|
||
--
|
||
-- Approximation: `substDim` does NOT descend into A or φ — even when j ≠ i
|
||
-- and i would be free under the binder. Consequence: this substitution is
|
||
-- only faithful for *endpoint* calls (`substDimBool`), where downstream
|
||
-- uses the dimension-absent predicate to justify correctness. Full
|
||
-- DimExpr-in-FaceFormula substitution is deferred (see cells-spec §5.5).
|
||
|
||
mutual
|
||
def CTerm.substDim (i : DimVar) (r : DimExpr) : CTerm → CTerm
|
||
| .var x => .var x
|
||
| .lam x t => .lam x (t.substDim i r)
|
||
| .app f a => .app (f.substDim i r) (a.substDim i r)
|
||
| .plam j t => if j = i then .plam j t -- i bound; stop
|
||
else .plam j (t.substDim i r)
|
||
| .papp t s => .papp (t.substDim i r) (DimExpr.subst i r s)
|
||
-- transp/comp: leave A alone (approximation); descend into t, u and
|
||
-- substitute in φ via the general DimExpr face-formula substitution.
|
||
| .transp j A φ t => .transp j A (φ.substDim i r) (t.substDim i r)
|
||
| .comp j A φ u t => .comp j A (φ.substDim i r) (u.substDim i r) (t.substDim i r)
|
||
-- Multi-clause comp: substitute in each clause's face and body, and in t.
|
||
-- Uses an explicit recursive helper `substDim.clauses` so Lean can see
|
||
-- structural termination through the clause list.
|
||
| .compN j A clauses t =>
|
||
.compN j A (CTerm.substDim.clauses i r clauses) (t.substDim i r)
|
||
-- Glue introduction / elimination: descend into all sub-terms and
|
||
-- substitute into the face formula. Same approximation for types
|
||
-- as transp/comp (A not touched — the `φ` face formula carries the
|
||
-- whole dim-dependency story; in our approximation we still don't
|
||
-- recurse into CType sub-trees here, matching `.transp`/`.comp`).
|
||
| .glueIn φ t a => .glueIn (φ.substDim i r) (t.substDim i r) (a.substDim i r)
|
||
| .unglue φ f g => .unglue (φ.substDim i r) (f.substDim i r) (g.substDim i r)
|
||
-- Σ constructors: structural recursion into sub-terms.
|
||
| .pair a b => .pair (a.substDim i r) (b.substDim i r)
|
||
| .fst t => .fst (t.substDim i r)
|
||
| .snd t => .snd (t.substDim i r)
|
||
|
||
/-- Helper: apply `CTerm.substDim i r` to each clause body (and
|
||
`FaceFormula.substDim` to each face) in a system's clause list.
|
||
Defined mutually with `substDim` so Lean can verify termination. -/
|
||
def CTerm.substDim.clauses (i : DimVar) (r : DimExpr) :
|
||
List (FaceFormula × CTerm) → List (FaceFormula × CTerm)
|
||
| [] => []
|
||
| (φ, u) :: rest =>
|
||
(φ.substDim i r, u.substDim i r) :: CTerm.substDim.clauses i r rest
|
||
end
|
||
|
||
-- ── One-step reduction ────────────────────────────────────────────────────────
|
||
-- `CTerm.step` is left *opaque*. Semantically it is what a CCHM-style
|
||
-- evaluator will compute. Keeping `step` opaque is required for
|
||
-- soundness: if `step` were a concrete `def` with a wildcard identity
|
||
-- arm, any axiom of the shape `step (.transp …) = t` would rfl-collapse
|
||
-- to `.transp … = t`, contradicting `CTerm.noConfusion`.
|
||
--
|
||
-- **Stage 4.4 decision (2026-04-23).** After the Phase 1 step↔eval
|
||
-- bridge + Stream B #2d + Stage 2.3, only one step-level axiom remains:
|
||
-- `transp_plam_is_plam_path` (T4, path-restricted form; Stage 4.2).
|
||
-- T1/T2/C1/C2/T5/`step_papp_plam` are NbE theorems in `Readback.lean`;
|
||
-- T3/C4 are theorems via `CTerm.step_preserves_type` (ValueTyping.lean);
|
||
-- glue β/η are theorems via `eval_unglue_of_glueIn`/`eval_glueIn_of_unglue`.
|
||
--
|
||
-- **Rust discharge flexibility.** The Rust backend has two valid
|
||
-- implementation strategies for `CTerm.step`:
|
||
--
|
||
-- · *Option A — native step*: implement `step` directly as a C ABI
|
||
-- entry point. The single T4 axiom is discharged by emitting the
|
||
-- CCHM comp-shaped body for path-typed transp-of-plam inputs, plus
|
||
-- identity behaviour on other shapes.
|
||
--
|
||
-- · *Option B — derived step*: define `step := readback ∘ eval .nil`
|
||
-- entirely in Rust (no separate `step` FFI entry). This matches
|
||
-- the Lean-side "bridge" intuition and keeps the Rust FFI surface
|
||
-- smaller by one function. Satisfies T4 on path-typed lines via
|
||
-- the `vPathTransp` → `.compN` readback arm.
|
||
--
|
||
-- The Lean-side spec is agnostic to which strategy Rust picks — both
|
||
-- satisfy the same axiom set. See FFI_DESIGN.md (Stage 4.5) for the
|
||
-- concrete recommendation.
|
||
|
||
opaque CTerm.step : CTerm → CTerm := id
|