/- Topolei.Cubical.Subst ===================== Dimension substitution for CType (Step 1 of the transport plan). CTerm already has substDim : DimVar → DimExpr → CTerm → CTerm (Syntax.lean). Here we add: CTerm.substDimBool : DimVar → Bool → CTerm → CTerm — specialises substDim to the two canonical endpoints (false = 0, true = 1). — Defined as a thin wrapper; no new recursion. CType.substDim : DimVar → Bool → CType → CType — Substitutes a dimension variable with a Bool endpoint throughout a type. — CType.path recurses into its CTerm endpoints via substDimBool. Key theorems: · Reduction lemmas (univ, pi, path) — proved by rfl. · substDimBool_eq_substDim — the wrapper unfolds correctly. · substDim_false_of_env / substDim_true_of_env — face connection: the Bool environment value at i selects which endpoint substitution applies. · substDim_idem — substituting twice at the same Bool is idempotent. Note: substDim_comm (disjoint dimensions commute) is deferred; it requires DimExpr.subst commutativity, which needs its own treatment. -/ import CubicalTransport.Syntax -- ── CTerm.substDimBool ──────────────────────────────────────────────────────── /-- Specialise CTerm.substDim to a Bool endpoint. false → substitute i with DimExpr.zero (the i=0 face) true → substitute i with DimExpr.one (the i=1 face) -/ def CTerm.substDimBool (i : DimVar) (b : Bool) (t : CTerm) : CTerm := t.substDim i (if b then .one else .zero) -- Unfolds to substDim by definition. theorem CTerm.substDimBool_eq_substDim (i : DimVar) (b : Bool) (t : CTerm) : t.substDimBool i b = t.substDim i (if b then .one else .zero) := rfl theorem CTerm.substDimBool_false (i : DimVar) (t : CTerm) : t.substDimBool i false = t.substDim i .zero := rfl theorem CTerm.substDimBool_true (i : DimVar) (t : CTerm) : t.substDimBool i true = t.substDim i .one := rfl -- ── CType.substDim ──────────────────────────────────────────────────────────── -- Substitute dimension variable i with Bool endpoint b throughout a type. -- Path type endpoints are terms, so we delegate to CTerm.substDimBool. -- -- `.ind S params` recurses pointwise through the parameter list via an -- explicit mutually-recursive helper (`CType.substDim.params`); this -- is the standard way to thread structural recursion through a -- `List CType` field of a CType constructor. 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) | .sigma A B => .sigma (A.substDim i b) (B.substDim i b) | .glue φ T f fInv sec ret coh A => .glue (φ.substDim i (if b then .one else .zero)) (T.substDim i b) (f.substDimBool i b) (fInv.substDimBool i b) (sec.substDimBool i b) (ret.substDimBool i b) (coh.substDimBool i b) (A.substDim i b) -- REL1: schema-defined inductive. Recurse into params; the schema -- itself is static (its boundary CTerms are the schema's data, not -- caller-substituted dim-bound terms). | .ind S params => .ind S (CType.substDim.params i b params) /-- Pointwise `substDim` through a list of CType parameters. -/ def CType.substDim.params (i : DimVar) (b : Bool) : List CType → List CType | [] => [] | A :: rest => A.substDim i b :: CType.substDim.params i b rest end -- ── CType.substDimExpr ──────────────────────────────────────────────────────── -- Substitute dimension variable `i` with an arbitrary `DimExpr r` throughout -- a type. Generalises `CType.substDim`, which fixes `r` to a Bool endpoint. -- -- Used for *line reversal* in transport: the reversed line is -- `A[i := inv i]`, which cannot be expressed as a Bool-endpoint -- substitution because `inv i` is an open DimExpr. mutual def CType.substDimExpr (i : DimVar) (r : DimExpr) : CType → CType | .univ => .univ | .pi A B => .pi (A.substDimExpr i r) (B.substDimExpr i r) | .path A a t => .path (A.substDimExpr i r) (a.substDim i r) (t.substDim i r) | .sigma A B => .sigma (A.substDimExpr i r) (B.substDimExpr i r) | .glue φ T f fInv sec ret coh A => .glue (φ.substDim i r) (T.substDimExpr i r) (f.substDim i r) (fInv.substDim i r) (sec.substDim i r) (ret.substDim i r) (coh.substDim i r) (A.substDimExpr i r) | .ind S params => .ind S (CType.substDimExpr.params i r params) /-- Pointwise `substDimExpr` through a list of CType parameters. -/ def CType.substDimExpr.params (i : DimVar) (r : DimExpr) : List CType → List CType | [] => [] | A :: rest => A.substDimExpr i r :: CType.substDimExpr.params i r rest end -- ── Reduction lemmas ────────────────────────────────────────────────────────── -- All proved by rfl: substDim is defined by pattern matching, so these -- hold definitionally. namespace CType theorem substDim_univ (i : DimVar) (b : Bool) : (univ).substDim i b = .univ := rfl theorem substDim_pi (i : DimVar) (b : Bool) (A B : CType) : (pi A B).substDim i b = .pi (A.substDim i b) (B.substDim i b) := rfl theorem substDim_path (i : DimVar) (b : Bool) (A : CType) (a t : CTerm) : (path A a t).substDim i b = .path (A.substDim i b) (a.substDimBool i b) (t.substDimBool i b) := rfl theorem substDim_sigma (i : DimVar) (b : Bool) (A B : CType) : (sigma A B).substDim i b = .sigma (A.substDim i b) (B.substDim i b) := rfl theorem substDim_glue (i : DimVar) (b : Bool) (φ : FaceFormula) (T : CType) (f fInv sec ret coh : CTerm) (A : CType) : (glue φ T f fInv sec ret coh A).substDim i b = .glue (φ.substDim i (if b then .one else .zero)) (T.substDim i b) (f.substDimBool i b) (fInv.substDimBool i b) (sec.substDimBool i b) (ret.substDimBool i b) (coh.substDimBool i b) (A.substDim i b) := rfl theorem substDim_ind (i : DimVar) (b : Bool) (S : CTypeSchema) (params : List CType) : (ind S params).substDim i b = .ind S (CType.substDim.params i b params) := rfl -- ── substDimExpr reduction lemmas ───────────────────────────────────────────── theorem substDimExpr_univ (i : DimVar) (r : DimExpr) : (univ).substDimExpr i r = .univ := rfl theorem substDimExpr_pi (i : DimVar) (r : DimExpr) (A B : CType) : (pi A B).substDimExpr i r = .pi (A.substDimExpr i r) (B.substDimExpr i r) := rfl theorem substDimExpr_path (i : DimVar) (r : DimExpr) (A : CType) (a t : CTerm) : (path A a t).substDimExpr i r = .path (A.substDimExpr i r) (a.substDim i r) (t.substDim i r) := rfl theorem substDimExpr_sigma (i : DimVar) (r : DimExpr) (A B : CType) : (sigma A B).substDimExpr i r = .sigma (A.substDimExpr i r) (B.substDimExpr i r) := rfl theorem substDimExpr_glue (i : DimVar) (r : DimExpr) (φ : FaceFormula) (T : CType) (f fInv sec ret coh : CTerm) (A : CType) : (glue φ T f fInv sec ret coh A).substDimExpr i r = .glue (φ.substDim i r) (T.substDimExpr i r) (f.substDim i r) (fInv.substDim i r) (sec.substDim i r) (ret.substDim i r) (coh.substDim i r) (A.substDimExpr i r) := rfl theorem substDimExpr_ind (i : DimVar) (r : DimExpr) (S : CTypeSchema) (params : List CType) : (ind S params).substDimExpr i r = .ind S (CType.substDimExpr.params i r params) := rfl -- The Bool-endpoint `substDim` is exactly `substDimExpr` at the canonical -- endpoint `DimExpr`. Proof is by pattern-matching `def` (rather than the -- `induction` tactic) because `CType` is mutually inductive with `CTerm`. -- `CTerm.substDimBool` is defined as `CTerm.substDim` at the same DimExpr, -- so the path case closes by unfolding both. -- -- `.ind` recurses into params via `substDim_eq_substDimExpr.params`, -- a structurally-recursive helper that establishes pointwise equality -- on the parameter list. mutual def substDim_eq_substDimExpr (i : DimVar) (b : Bool) : (A : CType) → A.substDim i b = A.substDimExpr i (if b then DimExpr.one else DimExpr.zero) | .univ => rfl | .pi A B => by show CType.pi (A.substDim i b) (B.substDim i b) = CType.pi (A.substDimExpr i _) (B.substDimExpr i _) rw [substDim_eq_substDimExpr i b A, substDim_eq_substDimExpr i b B] | .path A a t => by show CType.path (A.substDim i b) (a.substDimBool i b) (t.substDimBool i b) = CType.path (A.substDimExpr i _) (a.substDim i _) (t.substDim i _) rw [substDim_eq_substDimExpr i b A, CTerm.substDimBool_eq_substDim, CTerm.substDimBool_eq_substDim] | .sigma A B => by show CType.sigma (A.substDim i b) (B.substDim i b) = CType.sigma (A.substDimExpr i _) (B.substDimExpr i _) rw [substDim_eq_substDimExpr i b A, substDim_eq_substDimExpr i b B] | .glue φ T f fInv sec ret coh A => by show CType.glue (φ.substDim i (if b then DimExpr.one else DimExpr.zero)) (T.substDim i b) (f.substDimBool i b) (fInv.substDimBool i b) (sec.substDimBool i b) (ret.substDimBool i b) (coh.substDimBool i b) (A.substDim i b) = CType.glue (φ.substDim i _) (T.substDimExpr i _) (f.substDim i _) (fInv.substDim i _) (sec.substDim i _) (ret.substDim i _) (coh.substDim i _) (A.substDimExpr i _) rw [substDim_eq_substDimExpr i b T, substDim_eq_substDimExpr i b A, CTerm.substDimBool_eq_substDim, CTerm.substDimBool_eq_substDim, CTerm.substDimBool_eq_substDim, CTerm.substDimBool_eq_substDim, CTerm.substDimBool_eq_substDim] | .ind S params => by show CType.ind S (CType.substDim.params i b params) = CType.ind S (CType.substDimExpr.params i _ params) rw [substDim_eq_substDimExpr.params i b params] /-- Helper: pointwise equality between `substDim.params` and `substDimExpr.params` at the canonical endpoint DimExpr. -/ def substDim_eq_substDimExpr.params (i : DimVar) (b : Bool) : (params : List CType) → CType.substDim.params i b params = CType.substDimExpr.params i (if b then DimExpr.one else DimExpr.zero) params | [] => rfl | A :: rest => by show A.substDim i b :: CType.substDim.params i b rest = A.substDimExpr i _ :: CType.substDimExpr.params i _ rest rw [substDim_eq_substDimExpr i b A, substDim_eq_substDimExpr.params i b rest] end -- ── Face connection ─────────────────────────────────────────────────────────── -- These lemmas state the relationship between the Bool dimension environment -- and which endpoint substitution applies. -- -- Semantics: env i = false means we are at the i=0 face (eq0 i holds). -- env i = true means we are at the i=1 face (eq1 i holds). -- The correct substitution to apply is therefore substDim i (env i). /-- At the i=0 face (env i = false), substDim i (env i) is substDim i false. -/ theorem substDim_at_false (i : DimVar) (A : CType) (env : DimVar → Bool) (h : env i = false) : A.substDim i (env i) = A.substDim i false := by rw [h] /-- At the i=1 face (env i = true), substDim i (env i) is substDim i true. -/ theorem substDim_at_true (i : DimVar) (A : CType) (env : DimVar → Bool) (h : env i = true) : A.substDim i (env i) = A.substDim i true := by rw [h] -- ── Deferred: idempotence and commutativity ─────────────────────────────────── -- substDim_idem : (A.substDim i b).substDim i b = A.substDim i b -- substDim_comm : for i ≠ j, (A.substDim i b).substDim j c = (A.substDim j c).substDim i b -- -- Both require simultaneous induction over the CType/CTerm mutual inductive, -- which needs a `mutual` proof block or a size-indexed recursor. -- Deferred to a later pass after the DimLine and transport layers are in place. -- -- Correctness argument (informal): -- · After substDim i b, every DimExpr referencing i becomes zero or one -- (neither of which contains free variables), so a second substDim i b -- finds nothing left to substitute. Idempotence follows. -- · Substituting disjoint dimensions i ≠ j affects non-overlapping parts -- of every DimExpr (DimExpr.subst is capture-avoiding), so order is irrelevant. theorem substDim_comm_univ (i j : DimVar) (b c : Bool) : ((univ : CType).substDim i b).substDim j c = ((univ : CType).substDim j c).substDim i b := rfl end CType -- Note: dimAbsent, substDimBool_idem, and substDim_idem are proved in DimLine.lean, -- which is downstream in the import chain and has access to dimAbsent predicates.