cubical-transport-hott-lean4/Topolei/Subobject.lean
Maximus Gorog c2e3ecb3e3
Some checks are pending
Lean Action CI / build (push) Waiting to run
Initial commit: topolei — cubical-transport HoTT in Lean 4 + Rust FFI
Implements the cells-spec vision: a computation space that preserves
auditability, correctness, interactivity. Phase 1 (Lean kernel +
naga-IR Rust backend) is closed; foundation hypothesis stack
(Selection H1+H2, Subobject H3, Trace H5, Obs.Ctx C2, Cubical.Trace)
landed.

Highlights:
- Cubical-HoTT syntax + value/eval/readback in Lean
- naga-IR pipeline (no GLSL string crosses FFI; 17/17 probes pass)
- Honesty audit: every non-transport (sealed cells, vertex shader,
  Y-flip, presentation conventions) is documented as such
- Polymorphic Trace α as free monoid; Cubical.Trace gives
  CTerm → Trace CTerm by structural fold (homomorphism = definition)
- Selection as Huet zipper; Subobject as Boolean algebra over WCell
- All theorems proven; the proof IS the implementation

See STATUS.md for the resume guide.

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

258 lines
11 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.

/-
Topolei.Subobject
=================
H3 of the selection-foundation stack.
## What this file is
A `Subobject` of `WCell` is a *characteristic function*:
`σ : WCell → Bool`, identifying which cells are "in" the
subobject. Subobjects form a **Boolean algebra** under ∩, , ¬
with units , ⊥ — every law follows from `Bool`'s algebra by
pointwise reasoning, so the file is mostly `funext + simp + Bool`.
## Why this layer
H1+H2 gave us *focused* selections — one cell, with a path
back to the root. H3 gives us *scoped* selections — a
*family* of candidate cells, with a focus picked from inside.
The Boolean algebra then lets us:
- intersect two scopes (∩) — "things in both selections";
- union two scopes () — "things in either";
- complement (¬) — "things outside this selection".
These operations are what peripheral observations need in
order to *combine* or *refine* the cells they're looking at,
without descending to ad-hoc selection tools per peripheral
type (the VFX problem the user named: "their transports are
forgetful, so they have many selector tools"). Here, ONE
abstraction (Subobject + Boolean algebra) covers all of it.
## What this file does NOT contain
- The *focused-subobject* combination (Selection × Subobject).
That goes in `Topolei.Selection` once H1+H2's focus type
is extended with a scope field.
- The *action* of cell-endomorphisms on Subobjects. That's
`Subobject.preimage` below — actually, it IS in this file.
The thing NOT here is the action on `Selection` (which
requires the focused-subobject layer to be in place).
- **Heyting / intuitionistic refinement** to `WCell → Type` for
proof-relevant subobjects (where membership tracks *why* a
cell is in scope). That's a future H7 — when H5 (the trace
map) needs provenance, we lift `σ`'s codomain from `Bool` to
`Type`. For now, classical Boolean is enough.
## Reference
- Cells-spec §15.4 ("Lawvere-Tierney topology") — Subobjects
are exactly the level-0 instance of the LT-topology hierarchy
the cells-spec uses for accessibility / security.
- Cells-spec §1.5 ("Rendering Context as a Cell") — peripheral
observations as fiber selectors.
-/
namespace Topolei.Subobject
-- We don't import `Topolei.Selection` to keep this file independent;
-- both `Subobject` and `Selection` are foundational, neither
-- depends on the other. The bridge between them lives in a
-- third file.
private inductive WCell where
| mk : String → List WCell → WCell
namespace WCell
def data : WCell → String | .mk d _ => d
def children : WCell → List WCell | .mk _ c => c
end WCell
-- ── The Subobject type ────────────────────────────────────────────────────
/-- A subobject of `WCell`: a Boolean-valued characteristic function
saying which cells are "in" the subobject. Equivalence between
subobjects is pointwise (function-extensional). -/
structure Subobject where
σ : WCell → Bool
deriving Inhabited
namespace Subobject
/-- Two subobjects are equal iff their characteristic functions
are pointwise equal. Function extensionality is `funext`. -/
@[ext] theorem ext {a b : Subobject} (h : ∀ c, a.σ c = b.σ c) : a = b := by
cases a; cases b
congr 1
funext c
exact h c
-- ── Constants: (everywhere) and ⊥ (nowhere) ────────────────────────────
/-- The total subobject — every cell is in it. -/
def top : Subobject := { σ := fun _ => true }
/-- The empty subobject — no cell is in it. -/
def bot : Subobject := { σ := fun _ => false }
-- ── Pointwise operations ─────────────────────────────────────────────────
/-- Intersection (AND of characteristic functions). -/
def inter (a b : Subobject) : Subobject := { σ := fun c => a.σ c && b.σ c }
/-- Union (OR of characteristic functions). -/
def union (a b : Subobject) : Subobject := { σ := fun c => a.σ c || b.σ c }
/-- Complement (NOT of characteristic function). -/
def compl (a : Subobject) : Subobject := { σ := fun c => !(a.σ c) }
-- ── Boolean algebra laws (every one follows from `Bool` algebra) ──────────
-- The pattern: `ext c; simp [Subobject.inter, Subobject.union, Subobject.compl,
-- Subobject.top, Subobject.bot, Bool.<lemma>]`.
-- ── Commutativity ─────────────────────────────────────────────────────────
@[simp] theorem inter_comm (a b : Subobject) : a.inter b = b.inter a := by
ext c; simp [inter, Bool.and_comm]
@[simp] theorem union_comm (a b : Subobject) : a.union b = b.union a := by
ext c; simp [union, Bool.or_comm]
-- ── Associativity ─────────────────────────────────────────────────────────
theorem inter_assoc (a b c : Subobject) :
(a.inter b).inter c = a.inter (b.inter c) := by
ext x; simp [inter, Bool.and_assoc]
theorem union_assoc (a b c : Subobject) :
(a.union b).union c = a.union (b.union c) := by
ext x; simp [union, Bool.or_assoc]
-- ── Idempotence ───────────────────────────────────────────────────────────
@[simp] theorem inter_self (a : Subobject) : a.inter a = a := by
ext c; simp [inter]
@[simp] theorem union_self (a : Subobject) : a.union a = a := by
ext c; simp [union]
-- ── Identity laws (top is unit of ∩, bot is unit of ) ───────────────────
@[simp] theorem inter_top (a : Subobject) : a.inter top = a := by
ext c; simp [inter, top]
@[simp] theorem top_inter (a : Subobject) : top.inter a = a := by
ext c; simp [inter, top]
@[simp] theorem union_bot (a : Subobject) : a.union bot = a := by
ext c; simp [union, bot]
@[simp] theorem bot_union (a : Subobject) : bot.union a = a := by
ext c; simp [union, bot]
-- ── Annihilation (top is absorber of , bot of ∩) ────────────────────────
@[simp] theorem inter_bot (a : Subobject) : a.inter bot = bot := by
ext c; simp [inter, bot]
@[simp] theorem bot_inter (a : Subobject) : bot.inter a = bot := by
ext c; simp [inter, bot]
@[simp] theorem union_top (a : Subobject) : a.union top = top := by
ext c; simp [union, top]
@[simp] theorem top_union (a : Subobject) : top.union a = top := by
ext c; simp [union, top]
-- ── Distributivity ───────────────────────────────────────────────────────
theorem inter_distrib_union (a b c : Subobject) :
a.inter (b.union c) = (a.inter b).union (a.inter c) := by
ext x; simp [inter, union, Bool.and_or_distrib_left]
theorem union_distrib_inter (a b c : Subobject) :
a.union (b.inter c) = (a.union b).inter (a.union c) := by
ext x; simp [union, inter, Bool.or_and_distrib_left]
-- ── Complement laws ──────────────────────────────────────────────────────
@[simp] theorem compl_compl (a : Subobject) : a.compl.compl = a := by
ext c; simp [compl]
@[simp] theorem inter_compl_self (a : Subobject) : a.inter a.compl = bot := by
ext c; simp [inter, compl, bot]
@[simp] theorem union_compl_self (a : Subobject) : a.union a.compl = top := by
ext c; simp [union, compl, top]
@[simp] theorem compl_top : (top : Subobject).compl = bot := by
ext c; simp [compl, top, bot]
@[simp] theorem compl_bot : (bot : Subobject).compl = top := by
ext c; simp [compl, top, bot]
-- ── De Morgan ────────────────────────────────────────────────────────────
theorem compl_inter (a b : Subobject) :
(a.inter b).compl = a.compl.union b.compl := by
ext c; simp [inter, union, compl, Bool.not_and]
theorem compl_union (a b : Subobject) :
(a.union b).compl = a.compl.inter b.compl := by
ext c; simp [union, inter, compl, Bool.not_or]
-- ── Absorption ───────────────────────────────────────────────────────────
@[simp] theorem inter_union_self (a b : Subobject) :
a.inter (a.union b) = a := by
ext c; cases h : a.σ c <;> simp [inter, union, h]
@[simp] theorem union_inter_self (a b : Subobject) :
a.union (a.inter b) = a := by
ext c; cases h : a.σ c <;> simp [inter, union, h]
-- ── Bridge to construction: scope-preserving endomorphisms ───────────────
--
-- A peripheral observation produces a `Subobject` (the cells the
-- user is "looking at"). A constructor — i.e. an endomorphism of
-- WCell — should respect the scope: cells inside the selection
-- map to cells inside the selection. This is the type-level
-- guarantee that "applying a tool to a selection produces a new
-- valid selection".
--
-- Note: this is a *property* of an endomorphism, not a structure
-- on Subobjects. The action on Selections — `applyEndo` — uses
-- this property as a precondition; it lives in
-- `Topolei.Selection.Scoped` (next module to land).
/-- `f` preserves the subobject `a`: every cell in `a` maps to a
cell in `a`. This is the scope-preservation precondition
for actions on focused-subobject selections. -/
def Preserves (a : Subobject) (f : WCell → WCell) : Prop :=
∀ c, a.σ c = true → a.σ (f c) = true
/-- The identity always preserves any subobject. -/
theorem Preserves.id (a : Subobject) : Preserves a (fun c => c) := fun _ h => h
/-- Composition of preserving endomorphisms is preserving. -/
theorem Preserves.comp {a : Subobject} {f g : WCell → WCell}
(hf : Preserves a f) (hg : Preserves a g) :
Preserves a (fun c => f (g c)) := fun c hc => hf (g c) (hg c hc)
end Subobject
-- ── Operational sanity check ──────────────────────────────────────────────
/-- A demo subobject: cells whose data starts with `"leaf"`. -/
def demoLeaves : Subobject := { σ := fun c => c.data.startsWith "leaf" }
#eval demoLeaves.σ (WCell.mk "leaf-A" []) -- expected: true
#eval demoLeaves.σ (WCell.mk "root" []) -- expected: false
#eval (demoLeaves.inter demoLeaves).σ (WCell.mk "leaf-A" []) -- expected: true
#eval (demoLeaves.compl).σ (WCell.mk "root" []) -- expected: true
#eval (Subobject.top : Subobject).σ (WCell.mk "anything" []) -- expected: true
#eval (Subobject.bot : Subobject).σ (WCell.mk "anything" []) -- expected: false
end Topolei.Subobject