cubical-transport-hott-lean4/Topolei/Trace.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

188 lines
7.5 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.Trace
=============
H5 of the foundation stack: the **trace map** (inverse projection),
in its polymorphic form.
## Polymorphic from day 1
A `Trace α` is a list of contributing items of type `α`. The
parameter `α` is what the trace is *about*:
- `Trace WCell` — workspace-tree-level traces (rendered → workspace cells)
- `Trace CTerm` — cubical-syntax-level traces (rendered → CTerm sub-terms)
- `Trace SourceLoc` — file/line provenance traces
- `Trace HandleId` — GPU resource provenance
All four are the same algebraic structure (a free monoid on `α`) with
the same theorems. Polymorphism captures the "consolidate
abstractions" principle: ONE Trace type, instantiated wherever
needed.
## Why this layer
H1+H2 (Selection) gave us *focus + history* — pointing at one cell
with a path back to the root. H3 (Subobject) gave us the *algebra
of scopes*. C2 (Obs.Ctx) gave us the typed peripheral category.
H5 closes the loop: every rendered element carries a typed pointer
back to the source items that contributed to producing it. This is
the **inverse projection**: given an output (a pixel, region, curve
on the screen), recover the items whose values projected to it.
## Geometry, sheaves, bundles, differential structure: ALL derived
Differential geometry is NOT a separate framework bolted onto cells.
It is a *property of trace coherence* — particular shapes of how
`Trace`s relate across the rendered space:
- Trace varies smoothly across adjacent rendered elements →
differential structure (Jacobian / connection / parallel transport).
- Trace shares open sets in coherent overlaps → sheaf structure.
- Multiple sources project to one rendered point → fiber bundle's
preimage at that point.
The same `Trace α` carries all three; the geometry is in the
*predicates* / *projections* over traces, not in the type itself.
## What this file does NOT contain
- **The cubical-trace function** `CTerm → Trace CTerm`. That's a
sibling file `Topolei.Cubical.Trace`, which uses *this* `Trace`.
- **DecidableEq-dependent operations** (diff, intersect). Add when
needed; they require `DecidableEq α`.
## Reference
Cells-spec §1.5 ("Rendering Context as a Cell"), §17.1
("Vulnerabilities as Topological Failures": side channels are
unwanted traces — same abstraction, security layer).
-/
namespace Topolei.Trace
-- ── The Trace structure ───────────────────────────────────────────────────
/-- A trace: the typed list of items that contributed to producing a
rendered element. Polymorphic in the item type — instantiate
with `WCell` for workspace-tree traces, `CTerm` for cubical-
syntax traces, etc. Plural because at singularities, multiple
sources project to one rendered point — and even at non-singular
points the trace can include intermediate items (the sub-things
visited en route to the final output).
The list order records *contribution order*: the first item is
the deepest contributor, the last is the most recently seen. This
order matters when stacking traces during rendering. -/
structure Trace (α : Type) where
items : List α
deriving Repr, Inhabited
namespace Trace
/-- The empty trace — no items contributed. Identity element for
`union`, witness that some rendered element has no source-item
provenance (e.g., a clear-color background pixel). -/
def empty {α : Type} : Trace α := { items := [] }
/-- The single-item trace — exactly one source-item contributed.
Used when lifting a primitive into a traced render. -/
def single {α : Type} (a : α) : Trace α := { items := [a] }
/-- Combine two traces by concatenating their item lists. Order is
preserved: the second trace's items append after the first's.
This is *not* deduplicating — if an item appears in both traces
we keep both occurrences (the list is multi-set-like).
Deduplication is a separate operation that requires `DecidableEq`. -/
def union {α : Type} (t₁ t₂ : Trace α) : Trace α :=
{ items := t₁.items ++ t₂.items }
-- ── Monoid laws (empty is unit, union is associative) ────────────────────
@[simp] theorem empty_union {α : Type} (t : Trace α) :
Trace.empty.union t = t := by
cases t; simp [union, empty]
@[simp] theorem union_empty {α : Type} (t : Trace α) :
t.union Trace.empty = t := by
cases t; simp [union, empty]
theorem union_assoc {α : Type} (t₁ t₂ t₃ : Trace α) :
(t₁.union t₂).union t₃ = t₁.union (t₂.union t₃) := by
cases t₁; cases t₂; cases t₃
simp [union, List.append_assoc]
end Trace
-- ── TracedRender: rendered element + its trace ────────────────────────────
/-- A `TracedRender R α` is a rendered element of type `R` paired
with its `Trace α`. Every rendered output carries its provenance.
`R` is the rendered-element type (e.g. `PixelColor`, a region
label, a frame). `α` is the trace-item type (e.g. `WCell`,
`CTerm`, …). Polymorphism lets the same abstraction work for
every rendering granularity and every provenance shape. -/
structure TracedRender (R α : Type) where
render : R
trace : Trace α
deriving Repr, Inhabited
namespace TracedRender
/-- Lift a rendered value with a single-item trace. -/
def lift {R α : Type} (r : R) (a : α) : TracedRender R α :=
{ render := r, trace := Trace.single a }
/-- Lift a rendered value with no trace — for outputs without source-
item provenance (clear color, vertex-stage outputs, sealed-cell
rasterizer products). -/
def liftEmpty {R α : Type} (r : R) : TracedRender R α :=
{ render := r, trace := Trace.empty }
/-- Combine two traced renders by combining their traces (left-biased
on the rendered value). -/
def merge {R α : Type} (a b : TracedRender R α) : TracedRender R α :=
{ render := a.render, trace := a.trace.union b.trace }
@[simp] theorem merge_liftEmpty {R α : Type} (a : TracedRender R α) (r' : R) :
a.merge (liftEmpty r') = a := by
cases a; simp [merge, liftEmpty, Trace.union_empty]
@[simp] theorem liftEmpty_merge {R α : Type} (r : R) (b : TracedRender R α) :
(liftEmpty r).merge b = { render := r, trace := b.trace } := by
simp [merge, liftEmpty, Trace.empty_union]
end TracedRender
-- ── Operational sanity (polymorphic on `String` items as the simplest demo) ─
/-- Demo trace over `String` items. -/
def demoTrace : Trace String :=
(Trace.single "alpha").union (Trace.single "beta")
#eval demoTrace.items.length -- expected: 2
#eval demoTrace.items -- expected: ["alpha", "beta"]
/-- Empty-union round-trip. -/
example : (Trace.empty : Trace String).union demoTrace = demoTrace :=
Trace.empty_union _
/-- Union associativity exercised on three traces. -/
example :
let t₁ := (Trace.single "a" : Trace String)
let t₂ := Trace.single "b"
let t₃ := Trace.empty
(t₁.union t₂).union t₃ = t₁.union (t₂.union t₃) :=
Trace.union_assoc _ _ _
/-- `TracedRender` lift carries the trace it's given. -/
example : (TracedRender.lift (5 : Nat) "src").trace = Trace.single "src" := rfl
/-- Merging into a no-trace render leaves the trace alone. -/
example :
let a : TracedRender Nat String := TracedRender.lift 5 "src"
a.merge (TracedRender.liftEmpty 7) = a :=
TracedRender.merge_liftEmpty _ _
end Topolei.Trace