cubical-transport-hott-lean4/docs/PHASE1_HISTORY.md
Maximus Gorog d9f952fa6c
Some checks are pending
Lean Action CI / build (push) Waiting to run
Reorganize: move non-README docs into docs/ subfolder
Standard convention: README.md at root, everything else in docs/.

Engine docs/: FFI_DESIGN, FFI_COMPLETENESS, KERNEL_BOUNDARY, NUMERICAL,
PHASE1_HISTORY, ZIGZAG_PORT.  README.md links updated to docs/<name>.
Cross-repo reference in NUMERICAL.md (to topolei's STATUS.md) now
includes the relative path `../topolei/docs/STATUS.md`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:57:10 -06:00

13 KiB
Raw Permalink Blame History

Phase 1 History — Transport & Composition Formalization Plan

Archival. This document is the original implementation plan that drove Phase 1 of the cubical-transport HoTT formalization (CCHM §56). Every stage listed below is closed: see the CubicalTransport/* modules for the delivered code and CubicalTest.lean (62/62 passing) for the verification.

Paths in the original plan referred to Topolei/Cubical/* from the pre-split monolithic repo. They have been mechanically updated to the post-split CubicalTransport/* location, but otherwise the document is preserved as-is — methodology and step decomposition remain useful as a template for future formalization phases (e.g. the zigzag port: see ZIGZAG_PORT.md).

Stage goal (original): formally verify the CCHM transport and composition operations in the deep embedding before writing any Rust — per the project's discipline of stating all external-to-Lean behavior as Lean axioms before the Rust FFI side is built.

Each step has one clear deliverable, depends only on prior steps, and can be built and checked independently with lake build.

Reference: CCHM §56 (Cohen, Coquand, Huber, Mörtberg 2016)


Current state (completed)

File Contents
Interval.lean DimVar, DimExpr, de Morgan laws, DimExpr.subst, eval_subst
Face.lean FaceFormula, face laws, restrict, Entails, endpoint lemmas
Syntax.lean CType/CTerm mutual inductives, substDim, step, PathWitness
Typing.lean HasType judgment, inversion lemmas, face-boundary connection

Step 1 — CType dimension substitution

File: extend Syntax.lean (or new Syntax/Subst.lean)

What: CType needs its own dimension substitution so that a type A can be evaluated at a specific endpoint of the interval.

Definition:

mutual
  def CType.substDim (i : DimVar) (b : Bool) : CType → CType
    | .univ       => .univ
    | .pi A B     => .pi (A.substDim i b) (B.substDim i b)
    | .path A a t => .path (A.substDim i b)
                           (a.substDimBool i b) (t.substDimBool i b)

  def CTerm.substDimBool (i : DimVar) (b : Bool) : CTerm → CTerm
    -- same as substDim with r = (if b then .one else .zero)
end

Note: CTerm.substDimBool i b is definitionally CTerm.substDim i (if b then .one else .zero). We may define one in terms of the other to avoid duplication.

Key theorems:

  • CType.substDim_univ, substDim_pi, substDim_path — reduction lemmas
  • CType.substDim_comm — substituting disjoint dimensions commutes
  • CType.substDim_face — connection to FaceFormula.restrict: (FaceFormula.eq0 i).eval env = true → A.substDim i false = A (at the face, the substitution matches what the face formula asserts)

Acceptance: lake build with no errors; all three reduction lemmas proved.


Step 2 — DimLine: lines of types

File: CubicalTransport/DimLine.lean

What: A line of types λi. A — the domain of transport. Syntactically, it is a pair of a bound dimension variable and a body type. This is the A in transpⁱ A φ t.

Definition:

structure DimLine where
  binder : DimVar
  body   : CType

def DimLine.at0 (L : DimLine) : CType := L.body.substDim L.binder false
def DimLine.at1 (L : DimLine) : CType := L.body.substDim L.binder true
def DimLine.atBool (L : DimLine) (b : Bool) : CType := L.body.substDim L.binder b

def DimLine.const (A : CType) (i : DimVar) : DimLine := { binder := i, body := A }

Key theorems:

  • DimLine.atBool_false : L.atBool false = L.at0
  • DimLine.atBool_true : L.atBool true = L.at1
  • DimLine.const_at0 : (DimLine.const A i).at0 = A
  • DimLine.const_at1 : (DimLine.const A i).at1 = A (a constant line has the same type at both endpoints — used in Step 5)
  • DimLine.at_face_zero — if (FaceFormula.eq0 L.binder).eval env = true then L.body.substDim L.binder (env L.binder) = L.at0 (the face formula witnesses which endpoint we are at)

Acceptance: lake build; const_at0 and const_at1 proved without sorry.


Step 3 — Extend CTerm with transp and comp; transport typing rule

File: revise Syntax.lean and Typing.lean

What: Add transp and comp as constructors of CTerm now, so we do not have to reopen the inductive later. Add the HasType.transp rule in Typing.lean.

New CTerm constructors:

| transp (L : DimLine) (φ : FaceFormula) (t : CTerm) : CTerm
  -- transpⁱ (λi.A) φ t

| comp   (L : DimLine) (φ : FaceFormula)
         (u : CTerm)   (t : CTerm)         : CTerm
  -- compⁱ (λi.A) [φ↦u] t
  -- u is the system term; compatibility is enforced in the typing rule

New HasType rule (transport only at this step):

| transp : HasType Γ t L.at0 →
           HasType Γ (.transp L φ t) L.at1

comp constructor is added to CTerm here but its typing rule is deferred to Step 7, after System is defined.

Also: update CTerm.substDim and CTerm.substDimBool to handle the two new constructors:

| .transp L φ t => .transp (L with body := L.body.substDim i b) φ (t.substDimBool i b)
| .comp L φ u t => .comp   (L with body := L.body.substDim i b) φ
                            (u.substDimBool i b) (t.substDimBool i b)

Acceptance: lake build; HasType.transp rule present; existing Syntax/Typing theorems still hold.


Step 4 — Transport identity law

File: CubicalTransport/TransportLaws.lean

What: The fundamental CCHM axiom: transport under the trivial cofibration 1_F is the identity.

Axiom:

axiom transp_id (L : DimLine) (t : CTerm) :
    CTerm.step (.transp L .top t) = t

This cannot be proved from the syntax alone — it is a claim about what the evaluator/kernel must compute. Same pattern as GPU/Spec.lean.

Key theorems derived from transp_id:

  • transp_id_typed — if t : L.at0 and we apply transp_id, then t : L.at1 (using the fact that L.at0 = L.at1 when the line is constant — from Step 2)
  • transp_const_id — transport along a constant line is identity regardless of φ: Proof sketch: constant line has at0 = at1 = A; transp_id gives the 1_F case; the general φ case requires transp_monotone (below) or is itself axiomatic.
  • transp_monotone (axiom or derived): if FaceFormula.Entails φ ψ then transp L φ t = transp L ψ t — stronger face → more constrained transport.

Acceptance: transp_id stated as axiom; transp_const_id proved or stated as axiom with comment explaining which direction is derivable.


Step 5 — Transportpath connection

File: CubicalTransport/TransportLaws.lean (continued)

What: Transport along a constant line recovers path application. A path p : Path A a b is a term that, when transported with transp, moves from a to b. This step makes that connection explicit.

Key theorem:

theorem transp_path_apply
    (i : DimVar) (p : CTerm) (A : CType) (a b : CTerm)
    (hp : HasType Γ p (.path A a b)) :
    CTerm.step (.transp (DimLine.const A i) .bot p) =
    CTerm.papp p DimExpr.zero

(Transport along a constant line with empty face = path application at 0. The 1_F direction gives b.)

Also:

  • path_as_transp — states that every path induces a transport: p : Path A a b gives transp (const A) _ p : A (the path is itself the transport data)
  • PathWitness_of_transp — if we have a transport that reduces to a at φ = eq0 i and to b at φ = eq1 i, then there is a PathWitness for the abstracted term. Connects back to Syntax.lean.

Acceptance: transp_path_apply proved (may use sorry for one Float/Bool boundary if needed); PathWitness_of_transp stated with proof or clear sorry marking the missing evaluator.


Step 6 — System: partial elements

File: CubicalTransport/System.lean

What: A system [φ↦u] is a partial term — defined only on the face where φ holds. This is the new concept that composition requires beyond transport.

Definition:

structure System where
  face : FaceFormula
  body : CTerm

/-- Compatibility: the system agrees with base term t₀ on the face φ at i=0.
    Formally: whenever φ holds and i=0 holds, body[i:=0] = t₀. -/
def System.CompatAt0 (s : System) (i : DimVar) (t₀ : CTerm) : Prop :=
  ∀ env : DimVar → Bool,
    s.face.eval env = true →
    env i = false →
    s.body.substDimBool i false = t₀

Key theorems:

  • System.compat_trivial — the system [1_F↦u] is compatible with u[i:=0] for any u (trivial face covers everything)
  • System.compat_bot — the empty system [0_F↦u] is compatible with any t₀ (vacuously true; the face never holds)
  • System.compat_meet — if s₁ and s₂ are both compatible with t₀, their join system is too (used when combining systems)
  • Typing rule for system body:
    structure System.Typed (Γ : Ctx) (s : System) (L : DimLine) where
      body_typed : HasType Γ s.body L.at1
      -- (body is typed at the *output* end of the line)
    

Acceptance: compat_trivial and compat_bot proved without sorry.


Step 7 — Composition declaration + typing rule

File: CubicalTransport/Typing.lean (extended)

What: Add HasType.comp — the typing rule for the composition operation. This is the main event: composition is what makes the type theory Kan (all cubes have fillers).

New HasType rule:

| comp : HasType Γ t₀ L.at0 →
         System.Typed Γ s L →
         s.CompatAt0 L.binder t₀ →
         HasType Γ (.comp L s.face s.body t₀) L.at1

Reading: given a base term t₀ : L.at0, a system [φ↦u] where u : L.at1 on the face φ, and a proof that they agree at i=0, the composition compⁱ (λi.A) [φ↦u] t₀ has type L.at1.

Key theorem:

theorem HasType.comp_inv (h : HasType Γ (.comp L φ u t₀) A) :
    A = L.at1 ∧
    HasType Γ t₀ L.at0 ∧
    ∃ s : System, s.face = φ ∧ s.body = u ∧ System.Typed Γ s L

(Inversion: reading off the components of a comp judgment.)

Acceptance: HasType.comp rule compiles; comp_inv proved.


Step 8 — Composition laws

File: CubicalTransport/CompLaws.lean

What: The three fundamental laws of composition. All three are CCHM axioms — not derivable from the syntax.

Axioms:

-- Full system: when the face is 1_F, the system fully determines the result.
axiom comp_full (L : DimLine) (u t₀ : CTerm) :
    CTerm.step (.comp L .top u t₀) = u.substDimBool L.binder true

-- Empty system: when the face is 0_F, comp reduces to transport.
axiom comp_empty (L : DimLine) (t₀ : CTerm) :
    CTerm.step (.comp L .bot u t₀) =
    CTerm.step (.transp L .bot t₀)

-- Transport as special case of composition.
-- (This is the definitional reduction in CCHM.)
axiom transp_as_comp (L : DimLine) (φ : FaceFormula) (t₀ : CTerm) :
    CTerm.step (.transp L φ t₀) =
    CTerm.step (.comp L φ t₀ t₀)
    -- system body = constant t₀; compat holds by substDim idempotence

Key derived theorems:

  • comp_full_typed — if HasType.comp holds with φ = 1_F, the result equals u[i:=1] and has the expected type
  • transp_id_from_comp — re-derive transp_id from transp_as_comp and comp_full (sanity check that the axioms are consistent)
  • comp_absorbs_transp — if a system already covers the whole face, adding a transport does nothing; states the Kan filling property informally

Acceptance: All three axioms stated; transp_id_from_comp proved as a derived theorem (closes the loop between Steps 4 and 8).


Summary

Step File Deliverable New sorry?
1 Syntax.lean extension CType.substDim, reduction lemmas No
2 DimLine.lean DimLine, endpoint lemmas, const No
3 Syntax.lean + Typing.lean transp/comp constructors, HasType.transp No
4 TransportLaws.lean transp_id axiom, transp_const_id Axiom (not sorry)
5 TransportLaws.lean transp_path_apply, PathWitness_of_transp Maybe 1
6 System.lean System, CompatAt0, compat lemmas No
7 Typing.lean HasType.comp, comp_inv No
8 CompLaws.lean Three comp axioms, transp_id_from_comp Axioms (not sorry)

The distinction between axiom and sorry is intentional: axioms are explicit claims about what the evaluator must satisfy (same as GPU/Spec.lean); sorry marks genuinely incomplete proofs that need more work.

Once Step 8 is complete, the cubical core is verified up to the stated axioms, and the Rust FFI implementation of transport/composition can begin against those as a formal spec — linked back into Lean via @[extern] + @[implemented_by] so the kernel can reduce cubical terms at native speed.