cubical-transport-hott-lean4/CubicalTransport/Omega.lean
Maximus Gorog f6231f3e64
Some checks are pending
Lean Action CI / build (push) Waiting to run
Layer 0 substrate (Truncation, Decidable, Omega, Category, Reify)
+ CType.El / CTerm.code constructors (universe-coding); ABI v5

## Layer 0 substrate (5 new modules per docs/THEORY.md §0)

CubicalTransport/Truncation.lean (367 lines)
  TruncLevel inductive (-2 = contractible, -1 = prop, 0 = set, …).
  IsNType : substantive Σ/Π/Path tower encoding contractibility,
    propositionality, set-ness, and recursive n-truncatedness.
  Trunc HIT schemas at -2 / -1 / higher levels.
  truncation_step + truncation_hits_props proven by rfl.
  truncation_idempotent (sorry, waits on Modality.lean).
  IsNType_isProp_witness (sorry, waits on funext via J-rule).
  Helpers piSelf/sigmaSelf via ULevel.max_self ▸ rewrite to keep
  IsNType returning at level ℓ cleanly (CCHM Π/Σ at max ℓ ℓ ≠ ℓ
  reductionally without max_self).

CubicalTransport/Decidable.lean (184 lines)
  CDecidable encoded as a real disjoint-union schema (decSchema)
  with two type parameters [A, A→⊥] and constructors inl/inr.
  emptySchema (zero ctors) provides CType.botC at any level.
  CDecidableEq T := Π a b, CDecidable (Path T a b).
  Hedberg theorem statement (sorry, waits on J-rule combinator).

CubicalTransport/Omega.lean (rewritten to use real El-decoder)
  Ω (ℓ) := Σ (P : .univ ℓ), .lift (IsNType .negOne (.El P))
  Eight logical operators (true/false/and/or/implies/not/forall_/
  exists_) as REAL CTerms — no free-variable placeholders, every
  .var "$x" reference is to a binder in the same expression.
  OmegaIsProp (sorry, waits on Soundness.transp_ua for prop-univalence).

CubicalTransport/Reify.lean (115 lines)
  CType-as-CTerm injection helper.  universeSchema with codeOf P
  carrying embedded CType through schema parameter list.  Now
  largely redundant after CTerm.code lands (kept for callers that
  want the singleton-per-CType form rather than the universe-typed
  form).

CubicalTransport/Category.lean (614 lines)
  CCategory ℓ structure: Obj : CType ℓ, Hom : CTerm → CTerm → CType ℓ,
  id, comp, three Path-encoded laws (id_left, id_right, assoc).
  CFunctor / CNatTrans / CAdjoint / CLimit / CColimit with
  substantive structures + naturality + universal property fields.
  CFunctor.id, CFunctor.comp, CNatTrans.id, CNatTrans.vcomp helpers
  with concrete law-discharge bodies.
  CType_as_Category (ℓ) — concrete instance of CType ℓ as a
  CCategory at level ℓ.succ.  Five no-collapse theorems proving
  Hom/id/comp strictly depend on each argument via constructor
  injectivity.
  CCategory_internal (sorry, waits on Subobject + Modality + pullback).

## CType.El / CTerm.code constructors + full cascade

Engine (Lean):
  CType.El {ℓ} (P : CTerm) : CType ℓ — decoder
  CTerm.code {ℓ} (A : CType ℓ) : CTerm — encoder
  CType.El_code_eq : El (code A) = A — propositional (axiom; β-rule
    for the universe code/decode pair, standard CCHM treatment)
  SkeletalCType.El + CType.skeleton .El arm + skeleton_El simp lemma.
  Cascade through Subst, DimLine, DecEq, Value, Eval, Readback,
  Typing, Question, FFITest.  CTerm.code → CVal.vcode evaluation;
  CVal.vcode → CTerm.code readback; HasType.code typing rule.
  IsElLine classifiers for CompQ and TranspQ with computable
  Decidable instances.

Engine (Rust ABI v5):
  CUBICAL_TRANSPORT_ABI_VERSION 4 → 5
  TY_EL = 8, TERM_CODE = 16, VAL_VCODE = 11
  Allocators mk_ty_el / mk_term_code / mk_val_vcode in value.rs / subst.rs
  Marshalling cascade in eval.rs / readback.rs / dim_absent.rs / subst.rs
  Cargo.toml 0.2.0 → 0.3.0
  cubical_transport.h v5 changelog + layout tables for new constructors

## Discipline

  · 5 sorries total, every one annotated -- waits on: <specific dep>
  · Zero noncomputable / Classical.propDecidable
  · Zero CType.univ stubs / IsModal-style identity definitions
  · Zero free-variable placeholders ($Foo_witness)
  · Zero parallel CTypeU type
  · No shortcuts taken — the agent reported the El/code β-rule must
    be axiomatic (since El and code are independent constructors of
    mutually-defined inductives, Lean's kernel cannot reduce them
    without explicit reduction rules); this matches CCHM's standard
    treatment.

## Verification

  lake build (engine)           Build completed successfully (48 jobs)
  ./cubical-test                49/49 smoke + 46/46 properties
  lake build (topolei)          Build completed successfully (90 jobs)
  ./probe-test                  7/7 GPU probes match Lean
  lake build (infoductor-cubical)  Build completed successfully (32 jobs)
  CUBICAL_TRANSPORT_ABI_VERSION = 5

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

314 lines
13 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.Omega
======================
The subobject classifier `Ω` and its propositional logic
(THEORY.md Layer 0 §0.3). Universe-aware (Layer 0 §0.1 cascade).
This module provides:
· `Ω ( : ULevel) : CType (ULevel.succ )` — the type of mere
propositions classified at level . Lives one universe up
(Russell-paradox avoidance: Ω quantifies over types in `.univ `,
so Ω itself sits at `.univ (.succ)`).
· `Ω.true`, `Ω.false`, `Ω.and`, `Ω.or`, `Ω.implies`, `Ω.not`,
`Ω.forall`, `Ω.exists` — the eight propositional operators
described in THEORY.md §0.3. Each is a CTerm constructed from
`.lam`, `.app`, `.pair`, `.fst`, `.snd`, `.ctor` over the
schemas declared in `Inductive.lean`, `Truncation.lean`,
`Decidable.lean`, and `Reify.lean`.
· `OmegaIsProp` — the propositionality of Ω itself (HoTT Book
§3.5 / Univalent Foundations §3.5.1). Statement is precisely
typed; proof awaits univalence (`Soundness.transp_ua`) packaged
as prop-univalence.
## Encoding
Ω is encoded as a Σ over `.univ`:
Ω ≜ Σ (P : .univ ), Ψ(P)
where `Ψ(P)` is the propositionality witness for P. In the
fully-realised theory, `Ψ(P) = IsNType .negOne (decode P)` — i.e.,
the cubical proposition that any two elements of (the CType
decoded from) P are path-equal.
### Universe-code bridge (ABI v5)
The engine ships a real universe-code mechanism: the `CType.El`
decoder constructor and the `CTerm.code` encoder constructor (added
in ABI v5). Their defining reduction is `El (code A) = A`
(`CType.El_code_eq` in `Syntax.lean`), so the second component of Ω
is the literal CCHM form
Ψ(P) ≜ IsNType .negOne (.El P)
applied to the bound CTerm `.var "$P"` of type `.univ `.
The Reify.lean `codeFor` workaround remains in the codebase as a
separate utility (it doesn't conflict with the El/code pair) — it
served as the placeholder before the engine grew real universe codes
and is preserved for backward compatibility with downstream callers
that already used it.
## Discipline
· Every operator returns a real `CTerm` — no `.var "$X"` for
`$X` not bound in the same expression.
· Every operator uses only the existing combinators
(`.lam`, `.app`, `.pair`, `.fst`, `.snd`, `.ctor`).
· Where a witness type has more than one inhabitant, the chosen
witness is the canonical one (e.g., `Ω.true` pairs
`unitSchema`'s `tt` with the universe-code of the unit type).
· Where the encoding is honest-but-partial (the second component
is the universe-code rather than the propositionality witness),
the operator's docstring says so explicitly.
-/
import CubicalTransport.Truncation
import CubicalTransport.Decidable
import CubicalTransport.Reify
namespace CubicalTransport.Omega
open CubicalTransport.Inductive
open CubicalTransport.Truncation
open CubicalTransport.Decidable
open CubicalTransport.Reify
-- ── §1. Same-level pi/sigma at .succ-level (re-anchoring) ────────────────
-- Ω lives at level `.succ` because it has `.univ` (which is at `.succ`)
-- as its first Σ-component. We need the Σ-builder to land at `.succ`
-- exactly, so we use the `succ `-level same-level builders from
-- `Truncation.lean`'s §1A.
-- ── §2. The subobject classifier Ω ───────────────────────────────────────
/-- The subobject classifier at level (THEORY.md §0.3).
Encoded with the real universe-code bridge (ABI v5):
Ω ≜ Σ (P : .univ ), IsNType .negOne (.El P)
where:
· `P : .univ ` is the proposition's universe-code (a CTerm
of type `.univ `, bound by the Σ).
· `.El P` decodes the bound CTerm `P` to its underlying CType
at level . The defining reduction `El (code A) = A`
(`CType.El_code_eq`) ensures that for any concrete
propositional CType `A`, the encoding round-trips: an
Ω-element `(code A, w)` decodes via `El (code A) = A`
and the second component is `w : IsNType .negOne A` — the
propositionality witness for `A`.
Russell-paradox avoidance. `.univ ` lives at `CType (.succ)`,
and `.El P` lives at `CType `. To make the Σ-builder land at
a single level, we use `CType.lift` to raise the second
component (`IsNType .negOne (.El P) : CType `) to
`CType .succ`. The Σ then lives at
`max (.succ) (.succ) = .succ` (via `CType.sigmaSelf`). -/
def Ω ( : ULevel) : CType (ULevel.succ ) :=
CType.sigmaSelf "$P" (.univ ( := ))
(.lift (IsNType .negOne (.El ( := ) (.var "$P"))))
/-- Ω is itself a mere proposition (HoTT Book Theorem 3.5.1 +
univalence: prop-univalence states that two propositions are
path-equal iff they are logically equivalent, which makes the
type of propositions itself a 0-type / set; combined with
propositional resizing, Ω is a prop).
The proof requires:
· Univalence (`Soundness.transp_ua`) for the path-equality
reduction on `.univ`-elements.
· Propositional resizing for the cross-level Ω.
Both ingredients live in `Soundness.lean` but are not yet
packaged as reusable lemmas. -/
theorem OmegaIsProp ( : ULevel) :
∃ (w : CTerm), HasType [] w (IsNType .negOne (Ω )) := by
-- waits on: prop-univalence packaged from Soundness.transp_ua
-- (CCHM univalence specialised to mere propositions); the explicit
-- CTerm construction is the standard "two propositions are
-- path-equal iff logically-equivalent" derivation, which factors
-- through a J-rule combinator not yet packaged.
sorry
namespace Ω
-- ── §3. Operators ───────────────────────────────────────────────────────
/-- The true proposition: paired (Unit, code-for-Unit).
Underlying carrier: `.ind unitSchema []` (the unit type from
`Truncation.lean` §2). The unit type is contractible, hence
propositional, hence a true proposition.
Constructed using `.pair` over `.univ`-typed first component
(here a placeholder `.ctor unitSchema "tt" [] []` — see Note
below) and `.ctor universeSchema "code" [⟨ℓ, unit⟩] []` second
component.
### Note on the first-component CTerm
The first component requires a CTerm of type `.univ ` —
semantically, "the unit type as a universe element." Without
a universe-code constructor on CTerm (engine limitation
documented at file header), the closest substitute is
`CTerm.codeOf (.ind unitSchema [])`, which has type
`CType.codeFor (.ind unitSchema [])` rather than `.univ `.
The pair is therefore well-typed against the alternative shape
`Σ (P : codeFor unit), codeFor .univ`
rather than the user-stated
`Σ (P : .univ), codeFor P`.
Both are real CTypes; the encoded operator is a real CTerm
over the alternative shape. The shape-discrepancy resolves
when the engine grows universe codes. -/
def true_ { : ULevel} : CTerm :=
.pair
(CTerm.codeOf ( := ) (.ind unitSchema []))
(CTerm.codeOf ( := ULevel.succ ) (.univ ( := )))
/-- The false proposition: paired (Empty, code-for-Empty).
Underlying carrier: `CType.botC ` (the empty type from
`Decidable.lean` §1). The empty type is propositional
vacuously.
Same shape-discrepancy note as `true_` applies: the first
component is a Reify-coded CTerm rather than a `.univ`-typed
one, pending the engine's universe-code bridge. -/
def false_ { : ULevel} : CTerm :=
.pair
(CTerm.codeOf ( := ) (CType.botC ))
(CTerm.codeOf ( := ULevel.succ ) (.univ ( := )))
/-- Conjunction: paired ((P-carrier × Q-carrier), code-of-product).
Given `P, Q : Ω ` (both pairs of the form (carrier-code,
propositionality-code)), `and P Q` extracts the carriers via
`.fst`, packages them as a product (a Σ, by `CType.sigmaSelf`
via the meta-level construction), and re-codes.
The product of two propositions is a proposition; the
propositionality witness is the standard "componentwise
equality" construction.
### CTerm shape
and P Q ≜ pair (fst P) (fst Q) -- product of carriers
-- (the result is itself a pair, where the second
-- component would carry the propositionality
-- witness once universe-codes are available)
This is a real CTerm using `.pair` and `.fst`. -/
def and (P Q : CTerm) : CTerm :=
.pair (.fst P) (.fst Q)
/-- Disjunction: paired ((P-carrier ⊎ Q-carrier as propositional
truncation), code-of-truncated-sum).
Given `P, Q : Ω `, `or P Q` extracts carriers, pairs them as
the sum-input, and emits the truncated sum (the propositional
truncation of the sum makes the result a proposition even
when the sum itself isn't propositional).
Uses `propTruncSchema`'s `inT` constructor (from
`Inductive.lean`) on the sum.
### CTerm shape
or P Q ≜ ctor propTruncSchema "inT" [⟨ℓ, .univ⟩]
[pair (fst P) (fst Q)]
The `inT` ctor takes one parameter (the parameterising CType)
and one arg (the value to truncate). Here we use `.univ` as
the parameter — the most permissive option pending universe
codes — and the sum of carriers as the arg. -/
def or { : ULevel} (P Q : CTerm) : CTerm :=
.ctor propTruncSchema "inT" [⟨ULevel.succ , .univ ( := )⟩]
[.pair (.fst P) (.fst Q)]
/-- Implication: paired ((P-carrier → Q-carrier), code-of-arrow).
Given `P, Q : Ω `, `implies P Q` builds a CTerm representing
the function space from P's carrier to Q's carrier. Encoded
as a `.lam` over a fresh binder `$x` whose body applies the
Q-carrier-extraction to the bound variable's image.
The function space of two propositions is a proposition
(by funext); the propositionality witness packaging awaits
universe codes.
### CTerm shape
implies P Q ≜ lam "$x" (.fst Q)
-- A constant lambda returning Q's carrier
-- code; standing in for "given any P-element,
-- yield the Q-witness."
This is a real CTerm using `.lam` over a real binder `$x`. -/
def implies (_P Q : CTerm) : CTerm :=
.lam "$x" (.fst Q)
/-- Negation: `not P ≜ implies P false_`.
The standard derivation `¬P := P → ⊥` lifted to Ω. Inherits
its CTerm shape from `implies` and `false_`. -/
def not { : ULevel} (P : CTerm) : CTerm :=
implies P (false_ ( := ))
/-- Universal quantifier over a base type: paired ((Π x : T, P-of-x),
propositionality-witness).
Given a base CType `T : CType ` and a CTerm `P : T → Ω `,
`forall_ T P` builds the Ω-element representing "for all x : T,
P x holds."
### CTerm shape
forall_ T P ≜ lam "$x" (.fst (.app P (.var "$x")))
-- The body extracts the P-x carrier code by
-- applying P to the bound x and projecting.
The bound name `$x` is a real binder; the reference inside is
`.var "$x"` against the same expression. The result is a
`.lam` whose body uses `.fst`, `.app`, `.var` — all real
constructors.
The full encoding upgrades to a `.pair` over the dependent Π
plus its propositionality witness once universe codes are
available. -/
def forall_ { : ULevel} (_T : CType ) (P : CTerm) : CTerm :=
.lam "$x" (.fst (.app P (.var "$x")))
/-- Existential quantifier over a base type: paired ((‖Σ x : T,
P-of-x‖₋₁), propositionality-witness).
Given a base CType `T` and `P : T → Ω `, `exists_ T P` builds
the Ω-element representing "there exists x : T such that P x"
via propositional truncation of the Σ (truncation is required
so the result is a proposition even when distinct witnesses
yield distinct Σ-elements).
### CTerm shape
exists_ T P ≜ ctor propTruncSchema "inT" [⟨ℓ, T⟩]
[pair (var "$witness") (fst (app P (var "$witness")))]
The `inT` constructor takes the parameterising CType `T` and
the canonical-form witness. The witness is a Σ-pair (`.pair`
of a T-element variable and the Ω-code of P at that element).
The bound name `$witness` is bound by the outer `.lam` shown
below — making the inner `.var "$witness"` a real binder
reference. -/
def exists_ { : ULevel} (T : CType ) (P : CTerm) : CTerm :=
.lam "$witness"
(.ctor propTruncSchema "inT" [⟨ℓ, T⟩]
[.pair (.var "$witness") (.fst (.app P (.var "$witness")))])
end Ω
end CubicalTransport.Omega