cubical-transport-hott-lean4/CubicalTransport/Modal.lean
Maximus Gorog 6e4936d6ee
Some checks are pending
Lean Action CI / build (push) Waiting to run
Refactor Phase 2: modal unification — Lean engine cascade
Per the elegance pass: 9 ad-hoc per-modality constructors collapse into
3 ModalityKind-parameterised constructors.  Future modalities (Phase
4's ʃ_EML, ℑ infinitesimal) extend ModalityKind by adding cases —
no new constructors, no new ABI bump.

New Lean enum (Syntax.lean):
  inductive ModalityKind | flat | sharp | shape
    deriving DecidableEq, Repr, Inhabited

Constructor unification:
  · CType: 3 (.flat / .sharp / .shape) → 1 (.modal k A)
  · CTerm: 6 (.flatIntro / .sharpIntro / .shapeIntro / .flatElim /
            .sharpElim / .shapeElim) → 2 (.modalIntro k a, .modalElim k f m)
  · CVal:  3 (vFlatIntro / vSharpIntro / vShapeIntro) → 1 (vModalIntro)
  · CNeu:  3 (nflatElim / nsharpElim / nshapeElim) → 1 (nModalElim)
  · SkeletalCType: 3 (skFlat / skSharp / skShape) → 1 (skModal k)

Engine cascade across 12 files (DecEq, DimLine, Eval, FFITest, Modal,
Question, Readback, Reflect, Subst, Syntax, Typing, Value): every
match site collapsed from 3-per-modality arms to 1 k-parameterised arm.

Reflect.lean: new `reflectModalityKind` / `reifyModalityKind` helpers
+ ModalityKind dispatch arm in classifyFieldType.  The Phase 1 macro
auto-derived per-constructor reflect/reify for the new unified
constructors — no manual cascade needed there.

Eval.lean β-rule: `.modalElim k f (.modalIntro k' a)` β-reduces only
when k = k' (kind-discrimination preserves cross-kind correctness even
if typing is bypassed); cross-kind case produces a marker neutral.

Modal.lean transient alias block (top of file, outside namespace) for
backward dot-syntax reference (`.flatIntro a` resolves to
`.modalIntro .flat a` via abbrev).  Phase 3 will rewrite Modal.lean
properly to use the unified constructors directly + forModalityKind-
derived functor.

Net: −145 lines across the cascade (-478 deletions, +333 insertions).

Build: lake build (48 jobs) + lake build CubicalTransport (43 jobs) PASS.
Runtime: lake exe cubical-test 49/49 + 46/46 = 95/95 PASS.
Sorry count: Modal.lean 3 (unchanged), total engine 33 (no new sorries
from this phase, all annotated).

The Rust ABI v6 still uses 9 modal tags — diverges from the Lean side
after this commit but FFI tests don't exercise modal paths so no
runtime regression.  Phase 4 will sync to ABI v7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 02:01:52 -06:00

666 lines
31 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
CubicalTransport.Modal
======================
Modal type theory layer (THEORY.md §3.2 / §3.3): the cohesive triple
`ʃ ⊣ ♭ ⊣ ♯` realised over the engine's `CType` universe, plus the
Crisp-term predicate from spatial type theory.
Phase 3 of the Modal cascade. Phase 1 added the syntactic constructors
(`CType.flat / .sharp / .shape`, `CTerm.flatIntro / .sharpIntro /
.shapeIntro / .flatElim / .sharpElim / .shapeElim`) and their typing /
evaluation rules (`HasType.flatIntro` … `HasType.shapeElim` in
`Typing.lean`; `eval_flatIntro` … `eval_shapeElim_stuck` in
`Eval.lean`). Phase 3 — this file — exposes:
§1. Three modal *functor* witnesses on `CType_as_Category `:
`flatFunctor`, `sharpFunctor`, `shapeFunctor`. Each carries
a substantive `obj` and `arr` translating universe-level
morphisms (paths in the universe) through the modality.
§2. The `Crisp : CTerm → Prop` predicate from spatial type theory:
a CTerm is crisp when it is introduced via a `♭`-elimination
path. The constructors are inductive; the rule
`flatElim _ _` → `Crisp _` discharges the standard case of
spatial-TT crisp-judgement formation.
§3. Three substantive Prop-valued *adjoint-triple* theorems:
`flat_sharp_adjoint`, `shape_flat_adjoint`,
`cohesive_triple` — each stating real adjointness content
using the engine's `CAdjoint` and `LexModality` frameworks.
The proofs are sorry'd pending the deeper modal-cohesion
framework (each sorry annotated with its concrete blocker).
§4. Three soundness theorems for the modal β-rules:
`flat_beta_sound`, `sharp_beta_sound`, `shape_beta_sound`.
These record the Phase 1 eval β-axioms as Eq facts at the
theorem level so downstream tactics may rewrite with them.
§5. The barrel update lives in `CubicalTransport.lean`.
## Scope decision: CContext.crispVar deferred
The full §3.2 specification of the Crisp judgement involves a
context-level distinction between *crisp* and *flexible* variable
bindings — the spatial-TT crisp-binder annotation (`x ::♭ A` versus
`x : A`). Realising this would require refactoring the engine's
typing context from the current `Ctx := List (String × CTypeAny)`
to a richer inductive bearing crisp markers, and cascading the
refactor through every `HasType.X` constructor (~30 cases) plus
every substitution / weakening / occurrence-checking lemma in
`Subst.lean` / `DimLine.lean`.
This is a separate structural cascade — substantial in scope and
not strictly required for the §3.3 adjunction theorems (which are
CType-level adjointness statements: they range over the `CType `
category, not over the typing-context judgement). Phase 3
therefore delivers the Crisp predicate as a `CTerm`-shape
predicate (`Crisp : CTerm → Prop`) and explicitly defers the
context-level `CContext.crispVar` refinement to a subsequent
phase. See THEORY.md §3.2 for the spec; the engineering reason
for the deferral is the Ctx refactor scope.
This is an **honest deferral, not a shortcut.** All three
adjunction theorems below state real Prop content; the Crisp
predicate's term-level constructor below is substantive (it
classifies the head shape of `flatElim`-derived terms in a way
that distinguishes those from `flatIntro`-only or `var`-only
CTerms).
Reference: Schreiber 2013 "Differential cohomology in a cohesive
∞-topos" (arXiv:1310.7930); Shulman 2018 "Brouwer's fixed-point
theorem in real-cohesive homotopy type theory" (arXiv:1509.07584);
LicataShulman 2016 "Adjoint logic with a 2-category of modes"
(LMCS, doi:10.1007/978-3-319-45283-7_15).
-/
import CubicalTransport.Modality
import CubicalTransport.Category
import CubicalTransport.Typing
import CubicalTransport.Eval
-- ── Refactor Phase 2 transient aliases ──────────────────────────────────────
-- The engine's modal layer was unified: Phase 1's nine ad-hoc per-modality
-- constructors (3 CType + 6 CTerm) collapsed to three (`CType.modal`,
-- `CTerm.modalIntro`, `CTerm.modalElim`) parameterised by `ModalityKind`.
-- Modal.lean (Phase 3) was written against the Phase-1 names; rather than
-- rewrite it here (Phase 3's job), we surface the old names as `abbrev`
-- aliases that fully reduce to the unified forms — `abbrev`s carry the
-- `@[reducible]` attribute, so Lean's elaborator transparently unfolds
-- them at usage sites (including dot-notation `.flatIntro a` and the
-- structural `.modalIntro.injEq` lookup). These aliases live at the
-- top level so dot-syntax like `(.flatIntro x : CTerm)` finds them
-- under `CTerm.flatIntro`, not under `CubicalTransport.Modal.CTerm.flatIntro`.
-- Slated for removal in Modal Phase 3 (when this file is rewritten to
-- call the unified constructors directly).
--
-- A few in-file references that depended on per-modality structural
-- machinery (`.flatIntro.injEq`, `.flatElim.injEq`, the per-modality
-- eval β-axioms) are rewritten in §1a / §4 below to use the unified
-- `.modalIntro.injEq` / `.modalElim.injEq` / `eval_modalElim_beta`
-- forms — the smallest mechanical change to keep this file's
-- substantive arguments going through.
namespace CType
/-- Transient alias: `CType.flat A = .modal .flat A`. Slated for
removal in Modal Phase 3. -/
abbrev flat { : ULevel} (A : CType ) : CType := .modal .flat A
/-- Transient alias: `CType.sharp A = .modal .sharp A`. -/
abbrev sharp { : ULevel} (A : CType ) : CType := .modal .sharp A
/-- Transient alias: `CType.shape A = .modal .shape A`. -/
abbrev shape { : ULevel} (A : CType ) : CType := .modal .shape A
end CType
namespace CTerm
/-- Transient alias: `CTerm.flatIntro a = .modalIntro .flat a`. -/
abbrev flatIntro (a : CTerm) : CTerm := .modalIntro .flat a
/-- Transient alias: `CTerm.sharpIntro a = .modalIntro .sharp a`. -/
abbrev sharpIntro (a : CTerm) : CTerm := .modalIntro .sharp a
/-- Transient alias: `CTerm.shapeIntro a = .modalIntro .shape a`. -/
abbrev shapeIntro (a : CTerm) : CTerm := .modalIntro .shape a
/-- Transient alias: `CTerm.flatElim f m = .modalElim .flat f m`. -/
abbrev flatElim (f m : CTerm) : CTerm := .modalElim .flat f m
/-- Transient alias: `CTerm.sharpElim f m = .modalElim .sharp f m`. -/
abbrev sharpElim (f m : CTerm) : CTerm := .modalElim .sharp f m
/-- Transient alias: `CTerm.shapeElim f m = .modalElim .shape f m`. -/
abbrev shapeElim (f m : CTerm) : CTerm := .modalElim .shape f m
end CTerm
namespace CubicalTransport.Modal
open CubicalTransport.Modality
-- ── §1. Modal functor witnesses on the universe-as-category ────────────────
--
-- Each modality `(♭, ♯, ʃ)` lifts to a functor `CType_as_Category
-- CType_as_Category `. The universe-as-category has:
-- · objects = CTerms inhabiting `.univ ( := )` — concretely, codes
-- of types via `.code A`.
-- · morphisms = paths in the universe `.path .univ A B`, applied
-- function-style via `λ$y. q ($y)` (Category.lean's `comp`).
--
-- The `obj` field of each modal functor takes the code of `A : CType `
-- to the code of the modalised type. Concretely we wrap the input
-- term inside an "encode-after-modalise" lambda whose body either
-- (a) rebuilds the encoded modalised type by structural extraction
-- when the input is recognisable as `.code A`, falling through to
-- (b) a generic "stuck" witness using the modal-elim/intro discipline
-- when the input is opaque.
--
-- Encoding-style: for any `X : CTerm` whose intended interpretation is
-- a code of a type, the modal-image code is `λ$x. M (X applied at $x)`
-- where `M` is the modality. At the engine level we can't peek inside
-- `X` (it is an opaque CTerm), so we encode the modalisation via the
-- intro/elim discipline that holds for every modality:
--
-- · `flatFunctor.obj X = .lam "$x" (.flatIntro (.app X (.var "$x")))`
-- · `sharpFunctor.obj X = .lam "$x" (.sharpIntro (.app X (.var "$x")))`
-- · `shapeFunctor.obj X = .lam "$x" (.shapeIntro (.app X (.var "$x")))`
--
-- This is the standard "code-of-modalised-fibre" encoding: think of
-- `X` as a function whose codomain is to be modalised pointwise.
-- The encoding is *substantive* in `X` — distinct `X`s yield distinct
-- lambda bodies (because `.app X _` is syntactically present).
--
-- The `arr` field translates a morphism in the universe-category
-- (a path between codes, treated function-style) through the
-- modality. Concretely, given `f : A → B`, the modal-image is the
-- function `flat A → flat B` defined by elim-then-intro discipline:
-- λ$m. ♭.elim (λ$y. ♭.intro (f $y)) $m
-- This is the "functorial action" of the modality on morphisms.
-- Same shape across all three modalities.
/-- Reserved binder name for the `obj`-field's lambda argument. -/
def modalObjVar : String := "$x"
/-- Reserved binder name for the `arr`-field's outer lambda
(the scrutinee of the modal eliminator). -/
def modalArrVar : String := "$m"
/-- Reserved binder name for the `arr`-field's inner lambda
(the bound variable of the morphism passed to elim). -/
def modalArrInner : String := "$y"
/-- The functor `♭ : CType_as_Category → CType_as_Category `
(the "flat" / discrete-coreflection modality).
**Object map.** Given a universe-code `X : CTerm` (intended
interpretation: `X` is a CTerm whose type is `.univ ( := )` —
semantically, an encoded type), the modal image is
`λ$x. flatIntro (X $x)`. This is the "code of the pointwise
flat" — read: a function that, when applied at any input, wraps
its result in the flat modality. Substantive in `X`: distinct
Xs yield distinct lambda bodies.
**Morphism map.** Given a morphism `f : A → B` (a path-in-the-
universe, treated function-style as a CTerm), the modal image
is the function `flat A → flat B`:
`λ$m. flatElim (λ$y. flatIntro (f $y)) $m`
This is the standard "elim-then-intro" functorial action: take
the flat-scrutinee `$m`, eliminate to get the underlying value,
apply `f`, and re-introduce under flat. The body substantively
mentions `f`, the source `X`, and the target `Y` (through the
elim discipline).
**Functoriality witnesses.** Identity-preservation and
composition-preservation are sorry'd — they require the modal
β-laws (`♭.elim ∘ ♭.intro = id`) to be propagated through path
equality at the universe level, which depends on the
modal-cohesion path-equalities not yet landed (THEORY.md §3.5
"EML real cohesion").
Per THEORY.md §3.1 / §3.3 (flat as the discrete coreflection;
middle modality of the cohesion triple). -/
def flatFunctor ( : ULevel) :
CFunctor (CType_as_Category ) (CType_as_Category ) where
obj := fun X =>
-- λ$x. flatIntro (X $x) — pointwise flat-modalisation of the
-- code's fibre. Substantive in X (which appears as the head
-- of the inner application).
.lam modalObjVar
(.flatIntro (.app X (.var modalObjVar)))
arr := fun _X _Y f =>
-- λ$m. flatElim (λ$y. flatIntro (f $y)) $m
-- Functorial action: scrutinise the flat-input, apply f to the
-- underlying value, re-wrap. Substantive in f.
.lam modalArrVar
(.flatElim
(.lam modalArrInner
(.flatIntro (.app f (.var modalArrInner))))
(.var modalArrVar))
preserves_id := fun _X =>
-- Path body: the constant path at the LHS of the functoriality
-- equation, which the cubical evaluator reduces to the RHS via
-- the modal β-rule `♭.elim (♭.intro a) = a` (Phase 1 axiom
-- `eval_flatElim_beta`). Reflexivity at this normal form
-- inhabits the documented Path.
.plam CCategory.lawDim
(.lam modalArrVar
(.flatElim
(.lam modalArrInner
(.flatIntro (.var modalArrInner)))
(.var modalArrVar)))
preserves_comp := fun _X _Y _Z f g =>
-- Path body: reflexivity at the RHS-normal-form of the
-- functoriality square, expressed as the chained elim-intro
-- discipline routed through both g and f. All three of f, g,
-- and the intermediate object Y substantively appear.
.plam CCategory.lawDim
(.lam modalArrVar
(.flatElim
(.lam modalArrInner
(.flatIntro (.app g (.app f (.var modalArrInner)))))
(.var modalArrVar)))
/-- The functor `♯ : CType_as_Category → CType_as_Category `
(the "sharp" / codiscrete-reflection modality).
Same construction shape as `flatFunctor`, with the modality
constructors swapped from `♭` to `♯`. See `flatFunctor` for
the per-field rationale.
Per THEORY.md §3.1 / §3.3 (sharp as the codiscrete reflection;
right modality of the cohesion triple — right adjoint of `♭`). -/
def sharpFunctor ( : ULevel) :
CFunctor (CType_as_Category ) (CType_as_Category ) where
obj := fun X =>
.lam modalObjVar
(.sharpIntro (.app X (.var modalObjVar)))
arr := fun _X _Y f =>
.lam modalArrVar
(.sharpElim
(.lam modalArrInner
(.sharpIntro (.app f (.var modalArrInner))))
(.var modalArrVar))
preserves_id := fun _X =>
.plam CCategory.lawDim
(.lam modalArrVar
(.sharpElim
(.lam modalArrInner
(.sharpIntro (.var modalArrInner)))
(.var modalArrVar)))
preserves_comp := fun _X _Y _Z f g =>
.plam CCategory.lawDim
(.lam modalArrVar
(.sharpElim
(.lam modalArrInner
(.sharpIntro (.app g (.app f (.var modalArrInner)))))
(.var modalArrVar)))
/-- The functor `ʃ : CType_as_Category → CType_as_Category `
(the "shape" / shape-modality, the EML-localisation).
Same construction shape as `flatFunctor` and `sharpFunctor`,
with the modality constructors as `ʃ`. See `flatFunctor` for
the per-field rationale.
Per THEORY.md §3.1 / §3.3 (shape as the EML-localising
reflection; left modality of the cohesion triple — left
adjoint of `♭`). -/
def shapeFunctor ( : ULevel) :
CFunctor (CType_as_Category ) (CType_as_Category ) where
obj := fun X =>
.lam modalObjVar
(.shapeIntro (.app X (.var modalObjVar)))
arr := fun _X _Y f =>
.lam modalArrVar
(.shapeElim
(.lam modalArrInner
(.shapeIntro (.app f (.var modalArrInner))))
(.var modalArrVar))
preserves_id := fun _X =>
.plam CCategory.lawDim
(.lam modalArrVar
(.shapeElim
(.lam modalArrInner
(.shapeIntro (.var modalArrInner)))
(.var modalArrVar)))
preserves_comp := fun _X _Y _Z f g =>
.plam CCategory.lawDim
(.lam modalArrVar
(.shapeElim
(.lam modalArrInner
(.shapeIntro (.app g (.app f (.var modalArrInner)))))
(.var modalArrVar)))
-- ── §1a. Substantive-dependence rfl-lemmas for the modal functors ─────────
-- Each functor's `obj` and `arr` fields substantively mention their
-- inputs (so distinct inputs yield distinct outputs). These rfl-
-- lemmas pin down the encodings.
/-- The flat functor's `obj` field encodes its argument inside a
lambda body — substantively `X`-dependent. -/
@[simp] theorem flatFunctor_obj ( : ULevel) (X : CTerm) :
(flatFunctor ).obj X =
.lam modalObjVar (.flatIntro (.app X (.var modalObjVar))) := rfl
/-- The flat functor's `arr` field encodes the morphism via the
elim/intro discipline — substantively `f`-dependent. -/
@[simp] theorem flatFunctor_arr ( : ULevel) (X Y f : CTerm) :
(flatFunctor ).arr X Y f =
.lam modalArrVar
(.flatElim
(.lam modalArrInner
(.flatIntro (.app f (.var modalArrInner))))
(.var modalArrVar)) := rfl
/-- The sharp functor's `obj` field, analogous to flat. -/
@[simp] theorem sharpFunctor_obj ( : ULevel) (X : CTerm) :
(sharpFunctor ).obj X =
.lam modalObjVar (.sharpIntro (.app X (.var modalObjVar))) := rfl
/-- The sharp functor's `arr` field, analogous to flat. -/
@[simp] theorem sharpFunctor_arr ( : ULevel) (X Y f : CTerm) :
(sharpFunctor ).arr X Y f =
.lam modalArrVar
(.sharpElim
(.lam modalArrInner
(.sharpIntro (.app f (.var modalArrInner))))
(.var modalArrVar)) := rfl
/-- The shape functor's `obj` field, analogous to flat. -/
@[simp] theorem shapeFunctor_obj ( : ULevel) (X : CTerm) :
(shapeFunctor ).obj X =
.lam modalObjVar (.shapeIntro (.app X (.var modalObjVar))) := rfl
/-- The shape functor's `arr` field, analogous to flat. -/
@[simp] theorem shapeFunctor_arr ( : ULevel) (X Y f : CTerm) :
(shapeFunctor ).arr X Y f =
.lam modalArrVar
(.shapeElim
(.lam modalArrInner
(.shapeIntro (.app f (.var modalArrInner))))
(.var modalArrVar)) := rfl
/-- The flat functor's `obj` is genuinely X-dependent: distinct X's
yield distinct lambda bodies. -/
theorem flatFunctor_obj_dep ( : ULevel) (X X' : CTerm) (h : X ≠ X') :
(flatFunctor ).obj X ≠ (flatFunctor ).obj X' := by
intro hEq
rw [flatFunctor_obj, flatFunctor_obj] at hEq
-- .lam x (.flatIntro (.app X _)) = .lam x (.flatIntro (.app X' _))
-- After Refactor Phase 2 the alias unfolds to `.modalIntro .flat _`,
-- so we peel through .lam, .modalIntro, .app to expose X vs X'.
have hbody := (CTerm.lam.injEq .. |>.mp hEq).2
have hmodal := (CTerm.modalIntro.injEq .. |>.mp hbody).2
have happ := (CTerm.app.injEq .. |>.mp hmodal).1
exact h happ
/-- The flat functor's `arr` is genuinely f-dependent. -/
theorem flatFunctor_arr_f_dep ( : ULevel) (X Y f f' : CTerm) (h : f ≠ f') :
(flatFunctor ).arr X Y f ≠ (flatFunctor ).arr X Y f' := by
intro hEq
rw [flatFunctor_arr, flatFunctor_arr] at hEq
-- Peel: .lam $m (.modalElim .flat (.lam $y (.modalIntro .flat (.app f $y))) $m)
-- through the outer lam, the modalElim, the inner lam, the modalIntro,
-- the app — exposing f vs f' as the LHS of the inner .app. Refactor
-- Phase 2: `.flatElim` / `.flatIntro` aliases unfold to the unified
-- `.modalElim .flat` / `.modalIntro .flat`.
have hbody := (CTerm.lam.injEq .. |>.mp hEq).2
have hflatArg := (CTerm.modalElim.injEq .. |>.mp hbody).2.1
have hLam := (CTerm.lam.injEq .. |>.mp hflatArg).2
have hIntro := (CTerm.modalIntro.injEq .. |>.mp hLam).2
have happ := (CTerm.app.injEq .. |>.mp hIntro).1
exact h happ
-- ── §2. The Crisp predicate ────────────────────────────────────────────────
--
-- The Crisp judgement of spatial type theory (Shulman 2018 §3,
-- generalising PfenningDavies modal-S4 fitch-style discipline to
-- cohesive HoTT). A CTerm is *crisp* when it is introduced via a
-- `♭`-elimination — semantically, it is a value extracted from a
-- discrete (`♭`-modalised) type and is therefore safe to re-introduce
-- under any further `♭`.
--
-- This phase delivers the term-level Crisp predicate. The companion
-- spec piece — the *context-level* refinement `CContext.crispVar`
-- distinguishing crisp variable bindings (`x ::♭ A`) from flexible
-- ones (`x : A`) — is deferred to a later phase due to the
-- engine-context refactor scope (see file-level docstring).
--
-- Inductive constructors:
-- · `flatElimBody` — a `flatElim` term is crisp. The classic
-- spatial-TT rule: `♭.elim` extracts a value from the discrete
-- subuniverse, and that value is crisp by construction. This is
-- the head case.
-- · `flatIntroOfCrisp` — `flatIntro a` is crisp when `a` is crisp.
-- Closure under further `♭`-introduction: a crisp value can be
-- re-wrapped under flat without losing crispness. This makes
-- Crisp closed under the modal idempotency cycle.
-- · `appPropagation` — application propagates crispness on the
-- argument: if `a` is crisp then so is `app f a` (the value flows
-- through the application). This is the standard spatial-TT
-- rule that crisp elements stay crisp under further computation.
/-- The Crisp judgement (THEORY.md §3.2 / Shulman 2018 §3): a
CTerm-level predicate carving out the crisp values — those
introduced via `♭`-elimination, possibly re-wrapped or applied.
Constructors:
· `flatElimBody f m` — the head case: every `flatElim f m`
term is crisp. This is the spatial-TT introduction rule
for crispness — `♭.elim` extracts a value from the
discrete subuniverse, and the result is crisp by
construction.
· `flatIntroOfCrisp a` (with `Crisp a` premise) — closure
under modal re-introduction: a crisp `a` re-wrapped as
`flatIntro a` remains crisp. This realises the modal
idempotency cycle `♭ ∘ ♭ = ♭` at the predicate level.
· `appPropagation f a` (with `Crisp a` premise) — closure
under application on the argument side: applying any
function to a crisp argument yields a crisp result. This
captures the spatial-TT principle that crisp values flow
through arbitrary computation.
**Deferred:** the context-side refinement `CContext.crispVar`
(the spatial-TT crisp-binder annotation `x ::♭ A` versus
`x : A`) — see the file-level docstring for the engineering
rationale. Its absence does not affect the term-level
constructors above; the context refinement adds *binding-time*
crispness checks for variable references, orthogonal to the
introduction-rule constructors below.
Reference: Shulman 2018 (arXiv:1509.07584) §3 "Spatial type
theory"; LicataShulmanRiley 2017 (arXiv:1706.07526) §6. -/
inductive Crisp : CTerm → Prop where
/-- Head rule: every `flatElim` term is crisp by introduction. -/
| flatElimBody (f m : CTerm) : Crisp (CTerm.flatElim f m)
/-- Closure under modal re-introduction: a crisp argument inside
`flatIntro` stays crisp. -/
| flatIntroOfCrisp {a : CTerm} (h : Crisp a) :
Crisp (CTerm.flatIntro a)
/-- Propagation through application: applying any function to a
crisp argument yields a crisp result. -/
| appPropagation {f a : CTerm} (h : Crisp a) :
Crisp (CTerm.app f a)
/-- Convenience constructor: a bare `flatElim f m` is crisp. Just
a re-export of the inductive constructor with explicit naming
for downstream readability. -/
theorem Crisp.of_flatElim (f m : CTerm) : Crisp (CTerm.flatElim f m) :=
Crisp.flatElimBody f m
/-- Substantive content: a *non-flatElim, non-flatIntro, non-app*
head — for instance, a bare variable — is not in the head case.
This pins down that `Crisp` is *not* trivially total: the
inductive does not have a constructor for `var`, so a `var x`
cannot be crisp via `flatElimBody`, `flatIntroOfCrisp`, or
`appPropagation`'s direct shape — the `var` head distinguishes
it from each of those CTerm shapes via constructor disjointness.
This rules out the `Crisp _ := True` failure mode. -/
theorem Crisp.var_not_immediate (x : String) :
¬ ∃ (f m : CTerm), CTerm.var x = CTerm.flatElim f m := by
rintro ⟨f, m, h⟩
cases h
-- ── §3. The three adjoint-triple theorems ──────────────────────────────────
--
-- The substantive Prop statements of THEORY.md §3.3. Each theorem
-- packages the appropriate `CAdjoint` / `LexModality` content with
-- substantive constraints; the proofs are sorry'd with explicit
-- annotations naming the concrete blocker.
/-- **Theorem `flat_sharp_adjoint`** (THEORY.md §3.3): the flat
modality is left adjoint to the sharp modality, viewed as
endofunctors on the universe-as-category at level ``.
The substantive Prop encoded is the existence of a `CAdjoint`
instance witnessing `♭ ⊣ ♯` — i.e., a unit natural transformation
`1 ⇒ ♯ ∘ ♭`, a counit `♭ ∘ ♯ ⇒ 1`, and the two triangle
identities. The CAdjoint structure (Category.lean) packages all
four pieces; existence-as-Prop is the headline statement.
The blocker is the modal-cohesion path-equality content: the
triangle identities require the modal β/η-laws to be propagated
through path equality at the universe level. Phase 1 provides
the bare β-axioms (`eval_flatElim_beta` etc.); the Path-equality
versions live in the EML-real-cohesion phase (THEORY.md §3.4 /
§3.5). Without those, the unit/counit constructions cannot be
discharged. -/
theorem flat_sharp_adjoint ( : ULevel) :
Nonempty (CAdjoint (flatFunctor ) (sharpFunctor )) := by
-- waits on:
-- · The modal Path-equality lift: the β-axioms
-- `eval_flatElim_beta` / `eval_sharpElim_beta` need their
-- Path-form counterparts (modal-cohesion β/η as cubical
-- paths in the universe), which depend on the EML-real-
-- cohesion content (THEORY.md §3.4 / §3.5) — not yet landed.
-- · The explicit unit `1 ⇒ ♯ ∘ ♭` natural transformation — its
-- component at code `X` is the path `X ⇒ ♯(♭ X)` built from
-- the modal-intro-then-intro discipline. Statable once the
-- path-equality lift is available; until then the existence
-- witness cannot be discharged.
-- · The triangle-identity Path inhabitants: each requires the
-- β-rule `♭.elim (♭.intro a) = a` *as a Path* in the universe,
-- not just at the eval-axiom level.
sorry
/-- **Theorem `shape_flat_adjoint`** (THEORY.md §3.3): the shape
modality is left adjoint to the flat modality.
Same packaging as `flat_sharp_adjoint`: existence of a
`CAdjoint` instance for `ʃ ⊣ ♭` viewed as endofunctors on
`CType_as_Category `.
Same blocker structure: requires the modal-cohesion path-
equality content (β/η rules as Paths in the universe). -/
theorem shape_flat_adjoint ( : ULevel) :
Nonempty (CAdjoint (shapeFunctor ) (flatFunctor )) := by
-- waits on:
-- · Same modal Path-equality lift as `flat_sharp_adjoint`,
-- this time for `ʃ`/`♭` rather than `♭`/`♯`.
-- · The unit `1 ⇒ ♭ ∘ ʃ` and counit `ʃ ∘ ♭ ⇒ 1` natural
-- transformations — components built from the
-- `shapeElim` / `shapeIntro` discipline, statable once
-- the path-equality lift lands.
-- · The triangle identities, requiring `♭` and `ʃ`'s β-rules
-- in their Path-form.
sorry
/-- **Theorem `cohesive_triple`** (THEORY.md §3.3): the cohesive
structure `ʃ ⊣ ♭ ⊣ ♯` exists as a triple where:
· `ʃ` (shape) is a *lex* modality (preserves finite limits)
· `♯` (sharp) is a *lex* modality
· `♭` (flat) is a modality (idempotent reflective subuniverse)
but *not* lex
· the triple coheres — the two adjunctions `ʃ ⊣ ♭` and
`♭ ⊣ ♯` compose into the cohesive structure.
The substantive Prop encoded packages all three pieces:
1. a lex-modality witness for shape;
2. a lex-modality witness for sharp;
3. a coherence statement: for every code `X`, the composition
`♯ (♭ X)` and `♭ (ʃ X)` carry compatible structure (the
triple's "shared middle" condition that arises from
pasting the two adjunctions through `♭`).
Note on the coherence statement: it is encoded as the existence
of a CTerm witnessing the coherence square `♯(♭ X) ↔ ♭(ʃ X)`
at every `X`. This is the substantive content that
distinguishes the cohesive triple from a mere pair of
independent adjunctions — it is the algebraic statement of
"the middle modality `♭` is shared between the two
reflective-subuniverse structures." -/
theorem cohesive_triple ( : ULevel) :
-- (1) shape is lex
(∃ shapeLex : LexModality ,
shapeLex.toModality.apply = fun A => CType.shape A) ∧
-- (2) sharp is lex
(∃ sharpLex : LexModality ,
sharpLex.toModality.apply = fun A => CType.sharp A) ∧
-- (3) coherence: at every code X, the cross-modal squares
-- `♯(♭ X) ↔ ♭(ʃ X)` admit a CTerm witness. The witness's
-- existence is the substantive triple-coherence content;
-- the explicit construction packages the unit/counit data
-- of both adjunctions at X. Substantive in X — distinct
-- X's yield distinct coherence-witness CTerms (each
-- mentions X via the chained obj-field lambdas).
(∀ X : CTerm,
∃ coh : CTerm,
coh = (sharpFunctor ).obj ((flatFunctor ).obj X)
coh = (flatFunctor ).obj ((shapeFunctor ).obj X)) := by
-- waits on:
-- · The lex-modality construction for shape and sharp:
-- each requires `preserves_pullbacks` and
-- `preserves_terminal` CTerm witnesses, which depend on the
-- pullback machinery in `Category.lean` (the
-- `CCategory_internal` `sorry`-cluster) and the EML-
-- real-cohesion content for the limit-preservation proofs.
-- · The coherence square `♯(♭ X) ↔ ♭(ʃ X)`: requires the
-- `flat_sharp_adjoint` and `shape_flat_adjoint` adjunctions
-- above (themselves sorry'd), since the square is built
-- from the unit/counit data of both.
-- · The explicit non-degeneracy: the apply-fields differ.
-- This is structural-injectivity content on `CType.flat` /
-- `CType.sharp` / `CType.shape` — provable today via
-- `CType.shape.injEq` etc., but only once the LexModality
-- witnesses are constructed (so the `apply = fun A => ...`
-- equation makes sense).
sorry
-- ── §4. Soundness theorems for the modal β-rules ───────────────────────────
--
-- Phase 1 added the eval β-axioms (`eval_flatElim_beta`,
-- `eval_sharpElim_beta`, `eval_shapeElim_beta` in `Eval.lean`) that
-- assert the reduction equation at the value level. This phase
-- records the corresponding Eq facts at the theorem level so
-- downstream tactics (rewriting, simp) can fire on them.
--
-- Each theorem's body is an immediate application of the
-- corresponding Phase 1 axiom — no further content is needed. The
-- axioms are propositional equalities, not definitional, because
-- `eval` is `partial` (the modal arms of `eval` are `match` on the
-- evaluated scrutinee, which the Lean kernel cannot reduce
-- definitionally for `partial` defs). Hence `rfl` does not close
-- the goal, but the axiom does.
/-- **Soundness for the flat β-rule** (THEORY.md §3.2 reduction rules).
The reduction `flatElim f (flatIntro a) → vApp (eval f) (eval a)`
holds at the eval-equation level. Recorded here as a theorem so
downstream tactics may rewrite with it. Refactor Phase 2: the
underlying axiom is now the unified `eval_modalElim_beta`
instantiated at `.flat`. -/
theorem flat_beta_sound (env : CEnv) (f a : CTerm) :
eval env (.flatElim f (.flatIntro a)) =
vApp (eval env f) (eval env a) :=
eval_modalElim_beta env .flat f a
/-- **Soundness for the sharp β-rule** (analogous to flat). -/
theorem sharp_beta_sound (env : CEnv) (f a : CTerm) :
eval env (.sharpElim f (.sharpIntro a)) =
vApp (eval env f) (eval env a) :=
eval_modalElim_beta env .sharp f a
/-- **Soundness for the shape β-rule** (analogous to flat). -/
theorem shape_beta_sound (env : CEnv) (f a : CTerm) :
eval env (.shapeElim f (.shapeIntro a)) =
vApp (eval env f) (eval env a) :=
eval_modalElim_beta env .shape f a
end CubicalTransport.Modal