Modal cascade Phase 1: Syntax + Lean engine cascade
Some checks are pending
Lean Action CI / build (push) Waiting to run

Per THEORY.md §3.1: cubical-native modal type formers as the engine
support layer for the cohesive modality triple (ʃ ⊣ ♭ ⊣ ♯).

CType (3 level-preserving formers):
  · CType.flat / .sharp / .shape : {ℓ} → CType ℓ → CType ℓ

CTerm (6 — three intros + three elims, modelled on .glueIn / .unglue):
  · CTerm.flatIntro / .sharpIntro / .shapeIntro  : CTerm → CTerm
  · CTerm.flatElim  / .sharpElim  / .shapeElim   : CTerm → CTerm → CTerm

Cascade: Syntax (constructors + SkeletalCType + skeleton + substDim);
DecEq (beq arms); Subst (substDim / substDimExpr + 6 rfl theorems);
DimLine (cascade through 8 dim-absent / dim-substitution lemma families);
Value (3 vIntro CVal + 3 nElim CNeu); Eval (β-reduction axioms +
stuck-neutral propagation, "marker neutral" idiom from vFst/vSnd
preserved); Readback (3 vIntro + 3 nElim arms with axioms); Typing
(6 HasType cases — bare recursion-principle shape; modal cohesion
dependent-motive form deferred to Phase 3); Reflect (3 reflectCType + 6
reflectCTerm + 3 reifyCType with level-coherence discharge + 6
reifyCTerm); Question (6 modal arms + 6 IsModalLine classifier
predicates with their Decidable instances); FFITest (cval/cterm
summary arms).

No Rust changes (Phase 2).  No Modal.lean module (Phase 3).  No
Crisp / CContext.crispVar / cohesive_triple theorems (Phase 3).

Build: lake build (48 jobs) + lake build CubicalTransport (42 jobs) PASS.
+664 lines across 11 files, 0 removed, 0 new sorries.

Honest deferrals documented:
  · Modal type-formers do not yet reduce under transport/comp; the
    match A blocks have wildcards so transp i (flat A) φ t produces a
    stuck ntransp neutral (correct under current axiom set; cohesion-
    driven reductions land in Phase 3).
  · HasType.flatElim et al carry the bare recursion-principle shape;
    the cohesive-HoTT-correct dependent-motive form requires the modal
    predicate lattice from Phase 3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maximus Gorog 2026-05-05 22:22:03 -06:00
parent 825d8af68d
commit b9ca1d8875
11 changed files with 664 additions and 0 deletions

View file

@ -61,6 +61,12 @@ partial def beqCTypeAny : (Σ : ULevel, CType ) → (Σ : ULevel, CTy
beqCTypeAny ⟨_, A⟩ ⟨_, A'⟩
| ⟨_, .El P⟩, ⟨_, .El Q⟩ =>
beqCTerm P Q
| ⟨_, .flat A⟩, ⟨_, .flat B⟩ =>
beqCTypeAny ⟨_, A⟩ ⟨_, B⟩
| ⟨_, .sharp A⟩, ⟨_, .sharp B⟩ =>
beqCTypeAny ⟨_, A⟩ ⟨_, B⟩
| ⟨_, .shape A⟩, ⟨_, .shape B⟩ =>
beqCTypeAny ⟨_, A⟩ ⟨_, B⟩
| _, _ => false
partial def beqCTerm : CTerm → CTerm → Bool
@ -94,6 +100,14 @@ partial def beqCTerm : CTerm → CTerm → Bool
-- A and B may live at different universe levels. Route through
-- the level-erased Σ-pair beq to compare them honestly.
beqCTypeAny ⟨_, A⟩ ⟨_, B⟩
-- Modal introductions: structural equality on the wrapped term.
| .flatIntro a, .flatIntro b => beqCTerm a b
| .sharpIntro a, .sharpIntro b => beqCTerm a b
| .shapeIntro a, .shapeIntro b => beqCTerm a b
-- Modal eliminations: structural equality on (eliminator, scrutinee).
| .flatElim f m, .flatElim f' m' => beqCTerm f f' && beqCTerm m m'
| .sharpElim f m, .sharpElim f' m' => beqCTerm f f' && beqCTerm m m'
| .shapeElim f m, .shapeElim f' m' => beqCTerm f f' && beqCTerm m m'
| _, _ => false
partial def beqCTypeArg : CTypeArg → CTypeArg → Bool

View file

@ -93,6 +93,14 @@ mutual
-- substDim approximation in Syntax.lean — the CType payload is
-- conservatively assumed to be dim-stable).
| .code _ => true
-- Modal introductions: dim-absence is preserved through the wrapper.
| .flatIntro a => a.dimAbsent i
| .sharpIntro a => a.dimAbsent i
| .shapeIntro a => a.dimAbsent i
-- Modal eliminations: check both the eliminator and the scrutinee.
| .flatElim f m => f.dimAbsent i && m.dimAbsent i
| .sharpElim f m => f.dimAbsent i && m.dimAbsent i
| .shapeElim f m => f.dimAbsent i && m.dimAbsent i
/-- Helper: check that `i` is absent from every clause in a system. -/
def CTerm.dimAbsent.clauses (i : DimVar) :
@ -129,6 +137,10 @@ mutual
| .interval => true -- REL2: 𝕀 carries no dim binders
| .lift A => A.dimAbsent i
| .El P => P.dimAbsent i
-- Modal type formers: dim-absence reduces to the inner type's.
| .flat A => A.dimAbsent i
| .sharp A => A.dimAbsent i
| .shape A => A.dimAbsent i
/-- Helper: check `i` absent from every CType in a level-heterogeneous
parameter list. -/
@ -260,6 +272,33 @@ mutual
CTerm.substDim.branches_of_absent i r branches hbr,
CTerm.substDim_absent_aux i r target htg]
| .code _, _ => rfl
| .flatIntro a, h => by
simp only [CTerm.dimAbsent] at h
simp only [CTerm.substDim]
rw [CTerm.substDim_absent_aux i r a h]
| .sharpIntro a, h => by
simp only [CTerm.dimAbsent] at h
simp only [CTerm.substDim]
rw [CTerm.substDim_absent_aux i r a h]
| .shapeIntro a, h => by
simp only [CTerm.dimAbsent] at h
simp only [CTerm.substDim]
rw [CTerm.substDim_absent_aux i r a h]
| .flatElim f m, h => by
simp only [CTerm.dimAbsent, Bool.and_eq_true] at h
simp only [CTerm.substDim]
rw [CTerm.substDim_absent_aux i r f h.1,
CTerm.substDim_absent_aux i r m h.2]
| .sharpElim f m, h => by
simp only [CTerm.dimAbsent, Bool.and_eq_true] at h
simp only [CTerm.substDim]
rw [CTerm.substDim_absent_aux i r f h.1,
CTerm.substDim_absent_aux i r m h.2]
| .shapeElim f m, h => by
simp only [CTerm.dimAbsent, Bool.and_eq_true] at h
simp only [CTerm.substDim]
rw [CTerm.substDim_absent_aux i r f h.1,
CTerm.substDim_absent_aux i r m h.2]
/-- Helper: `substDim.clauses` is identity on clause lists whose every
`(face, body)` pair has `i` absent. -/
@ -375,6 +414,21 @@ mutual
show CType.El (CTerm.substDimBool i b P) = CType.El P
congr 1
exact CTerm.substDimBool_of_absent i b P h
| .flat A, h => by
simp only [CType.dimAbsent] at h
show CType.flat (CType.substDim i b A) = CType.flat A
congr 1
exact CType.substDim_absent_aux i b A h
| .sharp A, h => by
simp only [CType.dimAbsent] at h
show CType.sharp (CType.substDim i b A) = CType.sharp A
congr 1
exact CType.substDim_absent_aux i b A h
| .shape A, h => by
simp only [CType.dimAbsent] at h
show CType.shape (CType.substDim i b A) = CType.shape A
congr 1
exact CType.substDim_absent_aux i b A h
/-- Helper: `CType.substDim.params i b` is identity on level-
heterogeneous parameter lists with `i` absent from every entry. -/
@ -454,6 +508,21 @@ mutual
show CType.El (CTerm.substDim i r P) = CType.El P
congr 1
exact CTerm.substDim_of_absent i r P h
| .flat A, h => by
simp only [CType.dimAbsent] at h
show CType.flat (A.substDimExpr i r) = CType.flat A
congr 1
exact CType.substDimExpr_absent_aux i r A h
| .sharp A, h => by
simp only [CType.dimAbsent] at h
show CType.sharp (A.substDimExpr i r) = CType.sharp A
congr 1
exact CType.substDimExpr_absent_aux i r A h
| .shape A, h => by
simp only [CType.dimAbsent] at h
show CType.shape (A.substDimExpr i r) = CType.shape A
congr 1
exact CType.substDimExpr_absent_aux i r A h
/-- Helper: `CType.substDimExpr.params i r` is identity on level-
heterogeneous parameter lists with `i` absent from every entry. -/
@ -605,6 +674,27 @@ mutual
CTerm.dimAbsent.branches_after_substDim i r hr branches,
CTerm.dimAbsent_after_substDim_aux i r hr target, Bool.and_self]
| .code _ => by simp [CTerm.substDim, CTerm.dimAbsent]
| .flatIntro a => by
simp only [CTerm.substDim, CTerm.dimAbsent,
CTerm.dimAbsent_after_substDim_aux i r hr a]
| .sharpIntro a => by
simp only [CTerm.substDim, CTerm.dimAbsent,
CTerm.dimAbsent_after_substDim_aux i r hr a]
| .shapeIntro a => by
simp only [CTerm.substDim, CTerm.dimAbsent,
CTerm.dimAbsent_after_substDim_aux i r hr a]
| .flatElim f m => by
simp only [CTerm.substDim, CTerm.dimAbsent,
CTerm.dimAbsent_after_substDim_aux i r hr f,
CTerm.dimAbsent_after_substDim_aux i r hr m, Bool.and_self]
| .sharpElim f m => by
simp only [CTerm.substDim, CTerm.dimAbsent,
CTerm.dimAbsent_after_substDim_aux i r hr f,
CTerm.dimAbsent_after_substDim_aux i r hr m, Bool.and_self]
| .shapeElim f m => by
simp only [CTerm.substDim, CTerm.dimAbsent,
CTerm.dimAbsent_after_substDim_aux i r hr f,
CTerm.dimAbsent_after_substDim_aux i r hr m, Bool.and_self]
/-- Helper: `i` is absent from every clause in the result of substituting
`i := r` in a clause list (provided `r` doesn't mention `i`). -/
@ -690,6 +780,15 @@ mutual
| .El P => by
simp only [CType.substDim, CType.dimAbsent]
exact CTerm.dimAbsent_after_substDimBool i b P
| .flat A => by
simp only [CType.substDim, CType.dimAbsent,
CType.dimAbsent_after_substDim_aux i b A]
| .sharp A => by
simp only [CType.substDim, CType.dimAbsent,
CType.dimAbsent_after_substDim_aux i b A]
| .shape A => by
simp only [CType.substDim, CType.dimAbsent,
CType.dimAbsent_after_substDim_aux i b A]
/-- Helper: `i` absent from every CType in `substDim.params i b ps`. -/
private def CType.dimAbsent.params_after_substDim (i : DimVar) (b : Bool) :
@ -851,6 +950,33 @@ mutual
· exact CTerm.substDim.branches_comm_aux i j r s hij hrj hsi branches
· exact CTerm.substDim_comm_aux i j r s hij hrj hsi target
| .code _ => rfl
| .flatIntro a => by
simp only [CTerm.substDim]
exact congrArg CTerm.flatIntro
(CTerm.substDim_comm_aux i j r s hij hrj hsi a)
| .sharpIntro a => by
simp only [CTerm.substDim]
exact congrArg CTerm.sharpIntro
(CTerm.substDim_comm_aux i j r s hij hrj hsi a)
| .shapeIntro a => by
simp only [CTerm.substDim]
exact congrArg CTerm.shapeIntro
(CTerm.substDim_comm_aux i j r s hij hrj hsi a)
| .flatElim f m => by
simp only [CTerm.substDim]
congr 1
· exact CTerm.substDim_comm_aux i j r s hij hrj hsi f
· exact CTerm.substDim_comm_aux i j r s hij hrj hsi m
| .sharpElim f m => by
simp only [CTerm.substDim]
congr 1
· exact CTerm.substDim_comm_aux i j r s hij hrj hsi f
· exact CTerm.substDim_comm_aux i j r s hij hrj hsi m
| .shapeElim f m => by
simp only [CTerm.substDim]
congr 1
· exact CTerm.substDim_comm_aux i j r s hij hrj hsi f
· exact CTerm.substDim_comm_aux i j r s hij hrj hsi m
/-- Helper: `substDim.clauses` commutes on disjoint dim variables. -/
private def CTerm.substDim.clauses_comm_aux
@ -950,6 +1076,18 @@ mutual
simp only [CType.substDim]
congr 1
exact CTerm.substDimBool_comm i j b c hij P
| .flat A => by
simp only [CType.substDim]
congr 1
exact CType.substDim_comm_aux i j b c hij A
| .sharp A => by
simp only [CType.substDim]
congr 1
exact CType.substDim_comm_aux i j b c hij A
| .shape A => by
simp only [CType.substDim]
congr 1
exact CType.substDim_comm_aux i j b c hij A
/-- Helper: `CType.substDim.params` commutes on disjoint dim variables.
Operates on level-heterogeneous parameter lists. -/

View file

@ -161,6 +161,28 @@ mutual
(branches.map (fun (nm, b) => (nm, eval env b))) n)
| _ =>
.vneu (.nvar "<indElim: target is not canonical>")
-- Modal introductions: structural lift to the corresponding value form.
| .flatIntro a => .vFlatIntro (eval env a)
| .sharpIntro a => .vSharpIntro (eval env a)
| .shapeIntro a => .vShapeIntro (eval env a)
-- Modal eliminations: β-reduce on the corresponding intro value form;
-- otherwise produce a stuck neutral that preserves the evaluated
-- eliminator function and the (necessarily-stuck) scrutinee neutral.
| .flatElim f m =>
match eval env m with
| .vFlatIntro a => vApp (eval env f) a
| .vneu n => .vneu (.nflatElim (eval env f) n)
| _ => .vneu (.nvar "<flatElim: scrutinee is not flat-canonical>")
| .sharpElim f m =>
match eval env m with
| .vSharpIntro a => vApp (eval env f) a
| .vneu n => .vneu (.nsharpElim (eval env f) n)
| _ => .vneu (.nvar "<sharpElim: scrutinee is not sharp-canonical>")
| .shapeElim f m =>
match eval env m with
| .vShapeIntro a => vApp (eval env f) a
| .vneu n => .vneu (.nshapeElim (eval env f) n)
| _ => .vneu (.nvar "<shapeElim: scrutinee is not shape-canonical>")
/-- First projection at the value level. β-reduces `vpair`; pushes a
stuck neutral into `nfst`. Projecting any other value shape is a
@ -221,6 +243,9 @@ mutual
| .vctor _ _ _ _, _ => .vneu (.nvar "<vApp: vctor applied as function>")
| .vdimExpr _, _ => .vneu (.nvar "<vApp: vdimExpr applied as function>")
| .vcode _, _ => .vneu (.nvar "<vApp: vcode applied as function>")
| .vFlatIntro _, _ => .vneu (.nvar "<vApp: vFlatIntro applied as function>")
| .vSharpIntro _, _ => .vneu (.nvar "<vApp: vSharpIntro applied as function>")
| .vShapeIntro _, _ => .vneu (.nvar "<vApp: vShapeIntro applied as function>")
/-- Apply a value to a dimension expression. β-reduces `vplam` closures
by substituting the dim in the body and re-evaluating; pushes stuck
@ -254,6 +279,9 @@ mutual
| .vctor _ _ _ _, _ => .vneu (.nvar "<vPApp: vctor applied as path>")
| .vdimExpr _, _ => .vneu (.nvar "<vPApp: vdimExpr applied as path>")
| .vcode _, _ => .vneu (.nvar "<vPApp: vcode applied as path>")
| .vFlatIntro _, _ => .vneu (.nvar "<vPApp: vFlatIntro applied as path>")
| .vSharpIntro _, _ => .vneu (.nvar "<vPApp: vSharpIntro applied as path>")
| .vShapeIntro _, _ => .vneu (.nvar "<vPApp: vShapeIntro applied as path>")
/-- Homogeneous composition at the value level. The type `A` is
*homogeneous* (doesn't vary along `i`); the tube and base are
@ -867,3 +895,59 @@ preserving the underlying CType. Mirrors `eval_dimExpr` (a similar
to the corresponding `vcode` value form, preserving `A`. -/
axiom eval_code { : ULevel} (env : CEnv) (A : CType ) :
eval env (.code A) = .vcode A
/-!
### `eval` on modal introductions / eliminations
For each modality M ∈ {flat, sharp, shape}:
· `M-Intro a` evaluates to `vM-Intro (eval env a)` (lift through the
constructor).
· `M-Elim f m` β-reduces when the scrutinee evaluates to a `vM-Intro`,
via `vApp` with the eliminator function; on a stuck neutral it
produces a `nM-Elim` neutral; on any other shape, a marker neutral.
The arms below mirror the partial-def cases verbatim. Engine-layer
axioms; modal-cohesion semantics (Crisp variables, `♭ ⊣ ♯ ⊣ ʃ`
adjunction laws) are Phase 3 and live in a separate `Modal.lean`.
-/
-- Modal introductions: structural lift to the corresponding value form.
axiom eval_flatIntro (env : CEnv) (a : CTerm) :
eval env (.flatIntro a) = .vFlatIntro (eval env a)
axiom eval_sharpIntro (env : CEnv) (a : CTerm) :
eval env (.sharpIntro a) = .vSharpIntro (eval env a)
axiom eval_shapeIntro (env : CEnv) (a : CTerm) :
eval env (.shapeIntro a) = .vShapeIntro (eval env a)
-- Modal eliminations: β on the corresponding intro; stuck on neutrals.
/-- β-rule: `flatElim f (flatIntro a)` reduces to `app f a` at the eval
level. The scrutinee evaluates to `vFlatIntro (eval env a)`; the
elim arm of `eval` then invokes `vApp` on the eliminator value. -/
axiom eval_flatElim_beta (env : CEnv) (f a : CTerm) :
eval env (.flatElim f (.flatIntro a)) = vApp (eval env f) (eval env a)
axiom eval_sharpElim_beta (env : CEnv) (f a : CTerm) :
eval env (.sharpElim f (.sharpIntro a)) = vApp (eval env f) (eval env a)
axiom eval_shapeElim_beta (env : CEnv) (f a : CTerm) :
eval env (.shapeElim f (.shapeIntro a)) = vApp (eval env f) (eval env a)
/-- Stuck case: `flatElim` whose scrutinee evaluates to a CNeu produces
a `nflatElim` neutral preserving the evaluated function and
scrutinee. The scrutinee must be `.vneu n` after eval; this is
encoded by the explicit hypothesis `eval env m = .vneu n`. -/
axiom eval_flatElim_stuck (env : CEnv) (f m : CTerm) (n : CNeu)
(h : eval env m = .vneu n) :
eval env (.flatElim f m) = .vneu (.nflatElim (eval env f) n)
axiom eval_sharpElim_stuck (env : CEnv) (f m : CTerm) (n : CNeu)
(h : eval env m = .vneu n) :
eval env (.sharpElim f m) = .vneu (.nsharpElim (eval env f) n)
axiom eval_shapeElim_stuck (env : CEnv) (f m : CTerm) (n : CNeu)
(h : eval env m = .vneu n) :
eval env (.shapeElim f m) = .vneu (.nshapeElim (eval env f) n)

View file

@ -46,6 +46,9 @@ def cvalSummary : CVal → String
| .vneu (.nfst _) => "vneu nfst"
| .vneu (.nsnd _) => "vneu nsnd"
| .vneu (.nIndElim _ _ _ _ _) => "vneu nIndElim"
| .vneu (.nflatElim _ _) => "vneu nflatElim"
| .vneu (.nsharpElim _ _) => "vneu nsharpElim"
| .vneu (.nshapeElim _ _) => "vneu nshapeElim"
| .vlam _ x _ => s!"vlam {x} ..."
| .vplam _ i _ => s!"vplam {i.name} ..."
| .vpair _ _ => "vpair ..."
@ -57,6 +60,9 @@ def cvalSummary : CVal → String
| .vctor _ c _ _ => s!"vctor {c} ..."
| .vdimExpr _ => "vdimExpr ..."
| .vcode _ => "vcode ..."
| .vFlatIntro _ => "vFlatIntro ..."
| .vSharpIntro _ => "vSharpIntro ..."
| .vShapeIntro _ => "vShapeIntro ..."
def ctermSummary : CTerm → String
| .var x => s!"var {x}"
@ -69,6 +75,12 @@ def ctermSummary : CTerm → String
| .dimExpr _ => "dimExpr ..."
| .ctor _ c _ _ => s!"ctor {c} ..."
| .indElim _ _ _ _ _ => "indElim ..."
| .flatIntro _ => "flatIntro ..."
| .sharpIntro _ => "sharpIntro ..."
| .shapeIntro _ => "shapeIntro ..."
| .flatElim _ _ => "flatElim ..."
| .sharpElim _ _ => "sharpElim ..."
| .shapeElim _ _ => "shapeElim ..."
| _ => "<other CTerm>"
-- ── Individual test definitions ────────────────────────────────────────────

View file

@ -160,6 +160,22 @@ def IsUnivLine (q : CompQ) : Prop :=
def IsElLine (q : CompQ) : Prop :=
q.body.skeleton = SkeletalCType.El
/-- The line is a `.flat` modality. Encoded via the level-erased
skeleton tag. -/
@[simp]
def IsFlatLine (q : CompQ) : Prop :=
q.body.skeleton = SkeletalCType.flat
/-- The line is a `.sharp` modality. -/
@[simp]
def IsSharpLine (q : CompQ) : Prop :=
q.body.skeleton = SkeletalCType.sharp
/-- The line is a `.shape` modality. -/
@[simp]
def IsShapeLine (q : CompQ) : Prop :=
q.body.skeleton = SkeletalCType.shape
-- ── Decidability for the core classifiers ───────────────────────────────────
-- All instances are computable. Body-shape predicates are skeleton-eq
-- forms, decidable via `DecidableEq SkeletalCType`.
@ -199,6 +215,9 @@ instance instDecidableIsPathLine (q : CompQ) : Decidable (IsPathLine q) := by
| interval => simp at hs
| lift A => simp at hs
| El P => simp at hs
| flat A => simp at hs
| sharp A => simp at hs
| shape A => simp at hs
· refine isFalse (fun ⟨_, _, _, hbody⟩ => hs ?_)
rw [hbody]; rfl
@ -217,6 +236,9 @@ instance instDecidableIsGlueLine (q : CompQ) : Decidable (IsGlueLine q) := by
| interval => simp at hs
| lift A => simp at hs
| El P => simp at hs
| flat A => simp at hs
| sharp A => simp at hs
| shape A => simp at hs
· refine isFalse (fun ⟨_, _, _, _, _, _, _, _, hbody⟩ => hs ?_)
rw [hbody]; rfl
@ -232,6 +254,15 @@ instance (q : CompQ) : Decidable (IsIndLine q) :=
instance instDecidableIsElLine (q : CompQ) : Decidable (IsElLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.El))
instance (q : CompQ) : Decidable (IsFlatLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.flat))
instance (q : CompQ) : Decidable (IsSharpLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.sharp))
instance (q : CompQ) : Decidable (IsShapeLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.shape))
-- ── Classifier-conditioned theorems ─────────────────────────────────────────
namespace CompQ
@ -334,6 +365,12 @@ def IsUnivLine (q : TranspQ) : Prop := q.body.skeleton = SkeletalCType.univ
@[simp]
def IsElLine (q : TranspQ) : Prop := q.body.skeleton = SkeletalCType.El
@[simp]
def IsFlatLine (q : TranspQ) : Prop := q.body.skeleton = SkeletalCType.flat
@[simp]
def IsSharpLine (q : TranspQ) : Prop := q.body.skeleton = SkeletalCType.sharp
@[simp]
def IsShapeLine (q : TranspQ) : Prop := q.body.skeleton = SkeletalCType.shape
instance (q : TranspQ) : Decidable (IsConstLine q) :=
inferInstanceAs (Decidable (q.body.dimAbsent q.binder = true))
@ -356,6 +393,13 @@ instance (q : TranspQ) : Decidable (IsIndLine q) :=
instance instDecidableTranspIsElLine (q : TranspQ) : Decidable (IsElLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.El))
instance (q : TranspQ) : Decidable (IsFlatLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.flat))
instance (q : TranspQ) : Decidable (IsSharpLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.sharp))
instance (q : TranspQ) : Decidable (IsShapeLine q) :=
inferInstanceAs (Decidable (q.body.skeleton = SkeletalCType.shape))
instance instDecidableTranspIsPathLine (q : TranspQ) : Decidable (IsPathLine q) := by
by_cases hs : q.body.skeleton = SkeletalCType.path
· obtain ⟨level, env, binder, body, φ, t⟩ := q
@ -370,6 +414,9 @@ instance instDecidableTranspIsPathLine (q : TranspQ) : Decidable (IsPathLine q)
| interval => simp at hs
| lift A => simp at hs
| El P => simp at hs
| flat A => simp at hs
| sharp A => simp at hs
| shape A => simp at hs
· refine isFalse (fun ⟨_, _, _, hbody⟩ => hs ?_)
rw [hbody]; rfl
@ -388,6 +435,9 @@ instance instDecidableTranspIsGlueLine (q : TranspQ) : Decidable (IsGlueLine q)
| interval => simp at hs
| lift A => simp at hs
| El P => simp at hs
| flat A => simp at hs
| sharp A => simp at hs
| shape A => simp at hs
· refine isFalse (fun ⟨_, _, _, _, _, _, _, _, hbody⟩ => hs ?_)
rw [hbody]; rfl

View file

@ -144,6 +144,10 @@ mutual
| .vdimExpr r => .dimExpr r
-- Universe-code value: read back as the encoder constructor.
| .vcode A => .code A
-- Modal-introduction values: structural readback of the wrapped value.
| .vFlatIntro a => .flatIntro (readback a)
| .vSharpIntro a => .sharpIntro (readback a)
| .vShapeIntro a => .shapeIntro (readback a)
/-- Readback a `CNeu` into a `CTerm`. Straightforward structural
recursion: each neutral constructor has a syntactic counterpart.
@ -172,6 +176,11 @@ mutual
.indElim S params (readback motive)
(branches.map (fun p => (p.1, readback p.2)))
(readbackNeu target)
-- Modal-elimination stuck forms: rebuild the elim term with the
-- read-back eliminator function and the read-back stuck scrutinee.
| .nflatElim f n => .flatElim (readback f) (readbackNeu n)
| .nsharpElim f n => .sharpElim (readback f) (readbackNeu n)
| .nshapeElim f n => .shapeElim (readback f) (readbackNeu n)
end
-- ── Convenience wrapper ─────────────────────────────────────────────────────
@ -296,6 +305,28 @@ axiom readback_vpair (a b : CVal) :
axiom readback_vcode { : ULevel} (A : CType ) :
readback (.vcode A) = .code A
-- Modal-introduction readback axioms.
axiom readback_vFlatIntro (a : CVal) :
readback (.vFlatIntro a) = .flatIntro (readback a)
axiom readback_vSharpIntro (a : CVal) :
readback (.vSharpIntro a) = .sharpIntro (readback a)
axiom readback_vShapeIntro (a : CVal) :
readback (.vShapeIntro a) = .shapeIntro (readback a)
-- Modal-elimination (stuck) readback axioms.
axiom readbackNeu_nflatElim (f : CVal) (n : CNeu) :
readbackNeu (.nflatElim f n) = .flatElim (readback f) (readbackNeu n)
axiom readbackNeu_nsharpElim (f : CVal) (n : CNeu) :
readbackNeu (.nsharpElim f n) = .sharpElim (readback f) (readbackNeu n)
axiom readbackNeu_nshapeElim (f : CVal) (n : CNeu) :
readbackNeu (.nshapeElim f n) = .shapeElim (readback f) (readbackNeu n)
axiom readbackNeu_nfst (n : CNeu) :
readbackNeu (.nfst n) = .fst (readbackNeu n)

View file

@ -233,6 +233,18 @@ mutual
let E ← reflectULevel
let PE ← reflectCTerm P
return mkAppN (mkConst ``CType.El) #[E, PE]
| .flat A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CType.flat) #[E, AE]
| .sharp A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CType.sharp) #[E, AE]
| .shape A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CType.shape) #[E, AE]
/-- Reflect a `CTerm` to a `Lean.Expr`. -/
partial def reflectCTerm : CTerm → MetaM Expr
@ -315,6 +327,27 @@ mutual
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CTerm.code) #[E, AE]
| .flatIntro a => do
let ae ← reflectCTerm a
return mkApp (mkConst ``CTerm.flatIntro) ae
| .sharpIntro a => do
let ae ← reflectCTerm a
return mkApp (mkConst ``CTerm.sharpIntro) ae
| .shapeIntro a => do
let ae ← reflectCTerm a
return mkApp (mkConst ``CTerm.shapeIntro) ae
| .flatElim f m => do
let fe ← reflectCTerm f
let me ← reflectCTerm m
return mkAppN (mkConst ``CTerm.flatElim) #[fe, me]
| .sharpElim f m => do
let fe ← reflectCTerm f
let me ← reflectCTerm m
return mkAppN (mkConst ``CTerm.sharpElim) #[fe, me]
| .shapeElim f m => do
let fe ← reflectCTerm f
let me ← reflectCTerm m
return mkAppN (mkConst ``CTerm.shapeElim) #[fe, me]
/-- Reflect a `List (Σ : ULevel, CType )`. The Σ pairs are
built via `mkSigmaULevelCType`; the list is `List.cons`-spine. -/
@ -764,6 +797,54 @@ mutual
| some P => return some ⟨ℓ, .El ( := ) P⟩
else
return none
| (``CType.flat, args) =>
-- args = [E, AE]; result level = (level-preserving modality)
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some ⟨ℓ, .flat A'⟩
else
return none
else
return none
| (``CType.sharp, args) =>
-- args = [E, AE]; result level =
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some ⟨ℓ, .sharp A'⟩
else
return none
else
return none
| (``CType.shape, args) =>
-- args = [E, AE]; result level =
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some ⟨ℓ, .shape A'⟩
else
return none
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `CTerm`. Inverts `reflectCTerm`
@ -1018,6 +1099,59 @@ mutual
return none
else
return none
| (``CTerm.flatIntro, args) =>
-- args = [ae]
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some a => return some (.flatIntro a)
else
return none
| (``CTerm.sharpIntro, args) =>
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some a => return some (.sharpIntro a)
else
return none
| (``CTerm.shapeIntro, args) =>
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some a => return some (.shapeIntro a)
else
return none
| (``CTerm.flatElim, args) =>
-- args = [fe, me]
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some m => return some (.flatElim f m)
else
return none
| (``CTerm.sharpElim, args) =>
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some m => return some (.sharpElim f m)
else
return none
| (``CTerm.shapeElim, args) =>
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some m => return some (.shapeElim f m)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `List (Σ : ULevel, CType )`.

View file

@ -90,6 +90,10 @@ mutual
| .interval => .interval
| .lift A => .lift (A.substDim i b)
| .El P => .El (P.substDimBool i b)
-- Modal type formers: descend into the inner type.
| .flat A => .flat (A.substDim i b)
| .sharp A => .sharp (A.substDim i b)
| .shape A => .shape (A.substDim i b)
/-- Pointwise `substDim` through a level-heterogeneous list of CType
parameters. Each entry's universe level is preserved. -/
@ -120,6 +124,10 @@ mutual
| .interval => .interval
| .lift A => .lift (A.substDimExpr i r)
| .El P => .El (P.substDim i r)
-- Modal type formers: descend into the inner type.
| .flat A => .flat (A.substDimExpr i r)
| .sharp A => .sharp (A.substDimExpr i r)
| .shape A => .shape (A.substDimExpr i r)
/-- Pointwise `substDimExpr` through a level-heterogeneous list of
CType parameters. -/
@ -173,6 +181,15 @@ theorem substDim_lift { : ULevel} (i : DimVar) (b : Bool) (A : CType ) :
@[simp] theorem substDim_El { : ULevel} (i : DimVar) (b : Bool) (P : CTerm) :
(CType.El ( := ) P).substDim i b = .El (P.substDimBool i b) := rfl
@[simp] theorem substDim_flat { : ULevel} (i : DimVar) (b : Bool) (A : CType ) :
(CType.flat A).substDim i b = .flat (A.substDim i b) := rfl
@[simp] theorem substDim_sharp { : ULevel} (i : DimVar) (b : Bool) (A : CType ) :
(CType.sharp A).substDim i b = .sharp (A.substDim i b) := rfl
@[simp] theorem substDim_shape { : ULevel} (i : DimVar) (b : Bool) (A : CType ) :
(CType.shape A).substDim i b = .shape (A.substDim i b) := rfl
-- ── Reduction lemmas (substDimExpr) ──────────────────────────────────────────
theorem substDimExpr_univ { : ULevel} (i : DimVar) (r : DimExpr) :
@ -217,6 +234,15 @@ theorem substDimExpr_lift { : ULevel} (i : DimVar) (r : DimExpr) (A : CType
@[simp] theorem substDimExpr_El { : ULevel} (i : DimVar) (r : DimExpr) (P : CTerm) :
(CType.El ( := ) P).substDimExpr i r = .El (P.substDim i r) := rfl
@[simp] theorem substDimExpr_flat { : ULevel} (i : DimVar) (r : DimExpr) (A : CType ) :
(CType.flat A).substDimExpr i r = .flat (A.substDimExpr i r) := rfl
@[simp] theorem substDimExpr_sharp { : ULevel} (i : DimVar) (r : DimExpr) (A : CType ) :
(CType.sharp A).substDimExpr i r = .sharp (A.substDimExpr i r) := rfl
@[simp] theorem substDimExpr_shape { : ULevel} (i : DimVar) (r : DimExpr) (A : CType ) :
(CType.shape A).substDimExpr i r = .shape (A.substDimExpr i r) := rfl
-- ── Bool endpoint = DimExpr at canonical endpoint ────────────────────────────
mutual
@ -270,6 +296,15 @@ mutual
show CType.El (CTerm.substDimBool i b P) =
CType.El (CTerm.substDim i (if b then DimExpr.one else DimExpr.zero) P)
rw [CTerm.substDimBool_eq_substDim]
| .flat A => by
show CType.flat (A.substDim i b) = CType.flat (A.substDimExpr i _)
rw [substDim_eq_substDimExpr i b A]
| .sharp A => by
show CType.sharp (A.substDim i b) = CType.sharp (A.substDimExpr i _)
rw [substDim_eq_substDimExpr i b A]
| .shape A => by
show CType.shape (A.substDim i b) = CType.shape (A.substDimExpr i _)
rw [substDim_eq_substDimExpr i b A]
/-- Helper: pointwise equality between `substDim.params` and
`substDimExpr.params` at the canonical endpoint DimExpr. -/

View file

@ -140,6 +140,32 @@ mutual
propositions and refer back to the underlying type. -/
| El { : ULevel} (P : CTerm)
: CType
/-- **Modal type former: flat (♭).** Given `A : CType `, the type
`flat A` lives at the same universe level ``. Together with
`sharp` and `shape`, these are the three modalities of the
cohesive triple `♭ ⊣ ♯ ⊣ ʃ` (Schreiber/Shulman cohesive HoTT).
At the engine layer we add the data constructor; the modal
cohesion content (Crisp variables, the `♭ ⊣ ♯` adjunction,
modal-shape commutation diagrams) is the Phase 3 module.
Per THEORY.md §3.1; mirrors `path` in level preservation. -/
| flat { : ULevel} (A : CType )
: CType
/-- **Modal type former: sharp (♯).** Given `A : CType `, the type
`sharp A` lives at the same universe level ``. Right adjoint
of `flat` in the cohesive triple `♭ ⊣ ♯ ⊣ ʃ`.
Per THEORY.md §3.1. -/
| sharp { : ULevel} (A : CType )
: CType
/-- **Modal type former: shape (ʃ).** Given `A : CType `, the type
`shape A` lives at the same universe level ``. Left adjoint
of `flat` in the cohesive triple `♭ ⊣ ♯ ⊣ ʃ`.
Per THEORY.md §3.1. -/
| shape { : ULevel} (A : CType )
: CType
/-- Terms in the cubical calculus. Un-indexed by universe level —
the level discipline lives in the typing judgment (`HasType`,
@ -198,6 +224,36 @@ mutual
`.univ ( := )`. Carries the underlying type as data. -/
| code { : ULevel} (A : CType )
: CTerm
/-- **Modal introduction: η_♭ (flat).** Given `a : A`, the term
`flatIntro a` inhabits `flat A`. Mirrors the `glueIn` shape:
a single argument carrying the wrapped value.
Reduction: `flatElim f (flatIntro a)` ↝ `app f a`. -/
| flatIntro (a : CTerm)
: CTerm
/-- **Modal introduction: η_♯ (sharp).** Given `a : A`, the term
`sharpIntro a` inhabits `sharp A`. -/
| sharpIntro (a : CTerm)
: CTerm
/-- **Modal introduction: η_ʃ (shape).** Given `a : A`, the term
`shapeIntro a` inhabits `shape A`. -/
| shapeIntro (a : CTerm)
: CTerm
/-- **Modal elimination: ♭.rec.** Given the elimination function
`f : A → C` and a scrutinee `m : flat A`, produce a term of
type `C`. Two CTerms: target then scrutinee — same shape as
`unglue` (modulo unglue's leading FaceFormula).
Reduction: `flatElim f (flatIntro a)` ↝ `app f a` (β-rule).
Otherwise: stuck `nflatElim` neutral. -/
| flatElim (f m : CTerm)
: CTerm
/-- **Modal elimination: ♯.rec.** Same shape as `flatElim`. -/
| sharpElim (f m : CTerm)
: CTerm
/-- **Modal elimination: ʃ.rec.** Same shape as `flatElim`. -/
| shapeElim (f m : CTerm)
: CTerm
/-- Argument shape for a schema constructor (REL1, §2.1). -/
inductive CTypeArg where
@ -268,6 +324,9 @@ inductive SkeletalCType : Type where
| interval
| lift
| El
| flat
| sharp
| shape
deriving Repr, DecidableEq
/-- Strip the universe index, preserving the head constructor as a tag.
@ -284,6 +343,9 @@ def CType.skeleton { : ULevel} : CType → SkeletalCType
| .interval => .interval
| .lift _ => .lift
| .El _ => .El
| .flat _ => .flat
| .sharp _ => .sharp
| .shape _ => .shape
-- ── Skeleton equations (rfl-provable) ────────────────────────────────────────
@ -353,6 +415,21 @@ theorem CType.skeleton_lift { : ULevel} (A : CType ) :
@[simp] theorem CType.skeleton_El { : ULevel} (P : CTerm) :
(CType.El ( := ) P).skeleton = SkeletalCType.El := rfl
/-- The skeleton of `.flat` is `.flat`. -/
@[simp]
theorem CType.skeleton_flat { : ULevel} (A : CType ) :
(CType.flat A).skeleton = SkeletalCType.flat := rfl
/-- The skeleton of `.sharp` is `.sharp`. -/
@[simp]
theorem CType.skeleton_sharp { : ULevel} (A : CType ) :
(CType.sharp A).skeleton = SkeletalCType.sharp := rfl
/-- The skeleton of `.shape` is `.shape`. -/
@[simp]
theorem CType.skeleton_shape { : ULevel} (A : CType ) :
(CType.shape A).skeleton = SkeletalCType.shape := rfl
-- ── Constructor disjointness via skeleton ────────────────────────────────────
/-- Skeletons of distinct constructors are distinct. This is the
@ -436,6 +513,15 @@ mutual
-- Universe-code constructor: `code A` carries a CType payload.
-- Same approximation as transp/comp: A is not recursed into.
| .code A => .code A
-- Modal introductions: structural recursion into the wrapped term.
| .flatIntro a => .flatIntro (a.substDim i r)
| .sharpIntro a => .sharpIntro (a.substDim i r)
| .shapeIntro a => .shapeIntro (a.substDim i r)
-- Modal eliminations: structural recursion into both subterms
-- (eliminator function and scrutinee).
| .flatElim f m => .flatElim (f.substDim i r) (m.substDim i r)
| .sharpElim f m => .sharpElim (f.substDim i r) (m.substDim i r)
| .shapeElim f m => .shapeElim (f.substDim i r) (m.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. -/

View file

@ -173,6 +173,53 @@ inductive HasType : Ctx → CTerm → ∀ { : ULevel}, CType → Prop whe
| code : ∀ {Γ : Ctx} { : ULevel} (A : CType ),
HasType Γ (.code A) (.univ ( := ))
/-- **Modal introduction (flat).** Given `a : A`, the term
`flatIntro a` inhabits `flat A`. Engine-layer rule —
modal-cohesion contextual restrictions (Crisp variables,
Π-modality interaction, etc.) land in Phase 3. -/
| flatIntro {Γ : Ctx} { : ULevel} {A : CType } {a : CTerm} :
HasType Γ a A →
HasType Γ (.flatIntro a) (.flat A)
/-- **Modal introduction (sharp).** -/
| sharpIntro {Γ : Ctx} { : ULevel} {A : CType } {a : CTerm} :
HasType Γ a A →
HasType Γ (.sharpIntro a) (.sharp A)
/-- **Modal introduction (shape).** -/
| shapeIntro {Γ : Ctx} { : ULevel} {A : CType } {a : CTerm} :
HasType Γ a A →
HasType Γ (.shapeIntro a) (.shape A)
/-- **Modal elimination (flat).** Given an eliminator `f : A → C`
and a scrutinee `m : flat A`, produce a term of type `C`.
Engine layer: this is the bare recursion-principle shape; the
modal-cohesion side-conditions (e.g. C must be flat-modal for
the elim to be well-formed in cohesive HoTT) are deferred to
Phase 3 (`Modal.lean`). At the engine layer the rule reflects
the recursion principle directly so that `eval` and `readback`
can dispatch on it. -/
| flatElim {Γ : Ctx} { ' : ULevel} {A : CType } {C : CType '}
{f m : CTerm} {var : String} :
HasType Γ f (.pi var A C) →
HasType Γ m (.flat A) →
HasType Γ (.flatElim f m) C
/-- **Modal elimination (sharp).** -/
| sharpElim {Γ : Ctx} { ' : ULevel} {A : CType } {C : CType '}
{f m : CTerm} {var : String} :
HasType Γ f (.pi var A C) →
HasType Γ m (.sharp A) →
HasType Γ (.sharpElim f m) C
/-- **Modal elimination (shape).** -/
| shapeElim {Γ : Ctx} { ' : ULevel} {A : CType } {C : CType '}
{f m : CTerm} {var : String} :
HasType Γ f (.pi var A C) →
HasType Γ m (.shape A) →
HasType Γ (.shapeElim f m) C
-- ── Structural rules ──────────────────────────────────────────────────────────
/-- Core: insert (x, B) into context Γ between a prefix Γ₁ and suffix Γ₂.
@ -227,6 +274,24 @@ private theorem HasType.weaken_core
intro _ _; exact HasType.dimExpr
| code A =>
intro _ _; exact HasType.code A
| flatIntro ha ih =>
intro Γ₁ hΓ; subst hΓ
exact HasType.flatIntro (ih Γ₁ rfl)
| sharpIntro ha ih =>
intro Γ₁ hΓ; subst hΓ
exact HasType.sharpIntro (ih Γ₁ rfl)
| shapeIntro ha ih =>
intro Γ₁ hΓ; subst hΓ
exact HasType.shapeIntro (ih Γ₁ rfl)
| flatElim hf hm ihf ihm =>
intro Γ₁ hΓ; subst hΓ
exact HasType.flatElim (ihf Γ₁ rfl) (ihm Γ₁ rfl)
| sharpElim hf hm ihf ihm =>
intro Γ₁ hΓ; subst hΓ
exact HasType.sharpElim (ihf Γ₁ rfl) (ihm Γ₁ rfl)
| shapeElim hf hm ihf ihm =>
intro Γ₁ hΓ; subst hΓ
exact HasType.shapeElim (ihf Γ₁ rfl) (ihm Γ₁ rfl)
theorem HasType.weaken (x : String) {B : ULevel} (B : CType B)
{Γ : Ctx} {t : CTerm} { : ULevel} {A : CType }

View file

@ -81,6 +81,13 @@ mutual
| vdimExpr : DimExpr → CVal
/-- Value form of `CTerm.code A`. Carries the encoded CType. -/
| vcode { : ULevel} : CType → CVal
/-- Value form of `CTerm.flatIntro a`: the η-introduction value
for the flat (♭) modality, carrying the wrapped value. -/
| vFlatIntro : CVal → CVal
/-- Value form of `CTerm.sharpIntro a`. -/
| vSharpIntro : CVal → CVal
/-- Value form of `CTerm.shapeIntro a`. -/
| vShapeIntro : CVal → CVal
/-- Neutral (stuck) terms. -/
inductive CNeu : Type where
@ -116,6 +123,14 @@ mutual
/-- A stuck inductive eliminator (REL1). `params` is level-heterogeneous. -/
| nIndElim : CTypeSchema → List (Σ : ULevel, CType ) → CVal →
List (String × CVal) → CNeu → CNeu
/-- A stuck flat-modality eliminator: `flatElim f m` where the
scrutinee `m` is a stuck CNeu (so β can't fire). Stores the
evaluated eliminator function and the stuck scrutinee. -/
| nflatElim : CVal → CNeu → CNeu
/-- A stuck sharp-modality eliminator. -/
| nsharpElim : CVal → CNeu → CNeu
/-- A stuck shape-modality eliminator. -/
| nshapeElim : CVal → CNeu → CNeu
end
-- Inhabited instances — needed so `partial def` evaluators can be elaborated