Some checks are pending
Lean Action CI / build (push) Waiting to run
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>
198 lines
7.9 KiB
Text
198 lines
7.9 KiB
Text
/-
|
||
Topolei.Obs.Ctx
|
||
===============
|
||
C2 of the categories-from-the-interface stack:
|
||
**the observation category for peripherals.**
|
||
|
||
Observations are typed peripheral configurations — they describe
|
||
*what surface the rendering lands on*, not the rendering itself.
|
||
Window dimensions, pixel format, eventually GPU adapter / mouse
|
||
position / clock tick. None of these are transports in the
|
||
cubical sense (cells-spec §1.7 calls them "sealed cells whose
|
||
interior cannot be deformed from above"); but they do organise
|
||
themselves into a category, and that category is what every
|
||
transport in the cell calculus eventually has to live over.
|
||
|
||
## What this file proves
|
||
|
||
We define `Ctx` as a record (the typed peripheral) and `resize` /
|
||
`reformat` as the basic ops. We prove the *laws* that say these
|
||
ops compose like morphisms in a category:
|
||
|
||
- **Identity**: `c.resize c.width c.height = c`,
|
||
`c.reformat c.pixelFmt = c`
|
||
- **Idempotence on overwrite**:
|
||
`(c.resize w₁ h₁).resize w₂ h₂ = c.resize w₂ h₂`
|
||
(the second resize wins; the first is forgotten)
|
||
- **Commutativity** of independent ops:
|
||
`(c.resize w h).reformat fmt = (c.reformat fmt).resize w h`
|
||
|
||
These laws *make `Ctx` a category* — objects are values of `Ctx`,
|
||
morphisms are equivalence classes of resize/reformat sequences,
|
||
and the laws above quotient the free monoid down to the right
|
||
thing. We don't materialise the category as a Lean structure
|
||
here because the laws-as-`@[simp]`-rewrites are enough for the
|
||
reasoning we'll need; if H4 (horizontal lifts of transports
|
||
along observation arrows) needs the explicit category, we add it
|
||
then.
|
||
|
||
## What this file does NOT do
|
||
|
||
- It does not define **the fibration** `p : Cells → Obs` that
|
||
the cells-spec promises. That's C5, derived from C2 + C3.
|
||
Once `Ctx` is in place, we lift `compileEMLPath` to take a
|
||
`Ctx` explicitly instead of having `width`/`height`/format
|
||
floating as bare arguments.
|
||
|
||
- It does not define **arrows as a typed inductive** (the
|
||
`Arrow : Ctx → Ctx → Type` form I sketched earlier). That
|
||
would force us to either prove laws *up to a quotient* or
|
||
use a higher-inductive type — overhead that buys nothing
|
||
new at this layer. Instead, we use the *equational
|
||
presentation*: ops + laws. When H4 needs to talk about
|
||
"an arrow `f : c → c'`" abstractly, we'll add the typed
|
||
inductive then.
|
||
|
||
- It does not yet bridge to `Topolei.Selection.Selection`. A
|
||
`WiredSelection` would pair `(c : Ctx) (s : Selection)` with
|
||
a compatibility predicate; deferred until we know which
|
||
compatibility actually matters for rendering.
|
||
|
||
## Reference
|
||
|
||
Cells-spec §1.5 ("Rendering Context as a Cell"), §15.2
|
||
("Presheaf of Potential Cells").
|
||
-/
|
||
|
||
namespace Topolei.Obs
|
||
|
||
-- ── Pixel format ──────────────────────────────────────────────────────────
|
||
--
|
||
-- The "type" of a framebuffer. Sealed-cell — its IEEE / sRGB /
|
||
-- linear-RGB semantics are determined by the GPU's hardware spec,
|
||
-- not by our calculus. We only carry it as a typed tag so
|
||
-- rendering pipelines can refuse to bind into a context whose
|
||
-- format they don't support.
|
||
|
||
inductive PixelFormat where
|
||
/-- 32-bit float per channel; no display clamp. Used by the
|
||
`render_faithful` probe so CPU/GPU agreement isn't
|
||
dominated by quantisation. -/
|
||
| rgbaF32 : PixelFormat
|
||
/-- 8-bit per channel sRGB. Display surface; values clamp
|
||
to [0, 1] and gamma-encode. Standard for live windows. -/
|
||
| rgbaSrgb : PixelFormat
|
||
deriving Repr, DecidableEq, Inhabited
|
||
|
||
-- ── Observation context ───────────────────────────────────────────────────
|
||
|
||
/-- An observation context: the typed peripheral configuration
|
||
a render lands on. Objects of the observation category. -/
|
||
structure Ctx where
|
||
width : Nat
|
||
height : Nat
|
||
pixelFmt : PixelFormat
|
||
deriving Repr, DecidableEq, Inhabited
|
||
|
||
namespace Ctx
|
||
|
||
-- ── Operations (morphisms in the implicit category) ──────────────────────
|
||
|
||
/-- Resize the observation surface. Width × height update. -/
|
||
def resize (c : Ctx) (w h : Nat) : Ctx :=
|
||
{ c with width := w, height := h }
|
||
|
||
/-- Change the pixel format. -/
|
||
def reformat (c : Ctx) (fmt : PixelFormat) : Ctx :=
|
||
{ c with pixelFmt := fmt }
|
||
|
||
-- ── Identity laws: ops with the current value are no-ops ─────────────────
|
||
|
||
/-- Resizing a context to its current dimensions is the identity. -/
|
||
@[simp] theorem resize_self (c : Ctx) :
|
||
c.resize c.width c.height = c := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
/-- Reformatting a context to its current format is the identity. -/
|
||
@[simp] theorem reformat_self (c : Ctx) :
|
||
c.reformat c.pixelFmt = c := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
-- ── Idempotence on overwrite: the last value wins ────────────────────────
|
||
|
||
/-- Composed resizes collapse: only the outer dimensions matter. -/
|
||
@[simp] theorem resize_resize (c : Ctx) (w₁ h₁ w₂ h₂ : Nat) :
|
||
(c.resize w₁ h₁).resize w₂ h₂ = c.resize w₂ h₂ := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
/-- Composed reformats collapse: only the outer format matters. -/
|
||
@[simp] theorem reformat_reformat (c : Ctx) (f₁ f₂ : PixelFormat) :
|
||
(c.reformat f₁).reformat f₂ = c.reformat f₂ := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
-- ── Commutativity of independent ops ─────────────────────────────────────
|
||
|
||
/-- Resize and reformat commute — they touch independent fields, so
|
||
order doesn't matter. -/
|
||
@[simp] theorem resize_reformat (c : Ctx) (w h : Nat) (fmt : PixelFormat) :
|
||
(c.resize w h).reformat fmt = (c.reformat fmt).resize w h := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
/-- Symmetric form: reformat-then-resize = resize-then-reformat. -/
|
||
theorem reformat_resize (c : Ctx) (fmt : PixelFormat) (w h : Nat) :
|
||
(c.reformat fmt).resize w h = (c.resize w h).reformat fmt :=
|
||
(Ctx.resize_reformat c w h fmt).symm
|
||
|
||
-- ── Read-back of the field updates ───────────────────────────────────────
|
||
-- These are field-update lemmas that downstream proofs will lean on.
|
||
|
||
@[simp] theorem resize_width (c : Ctx) (w h : Nat) :
|
||
(c.resize w h).width = w := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
@[simp] theorem resize_height (c : Ctx) (w h : Nat) :
|
||
(c.resize w h).height = h := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
@[simp] theorem resize_pixelFmt (c : Ctx) (w h : Nat) :
|
||
(c.resize w h).pixelFmt = c.pixelFmt := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
@[simp] theorem reformat_width (c : Ctx) (fmt : PixelFormat) :
|
||
(c.reformat fmt).width = c.width := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
@[simp] theorem reformat_height (c : Ctx) (fmt : PixelFormat) :
|
||
(c.reformat fmt).height = c.height := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
@[simp] theorem reformat_pixelFmt (c : Ctx) (fmt : PixelFormat) :
|
||
(c.reformat fmt).pixelFmt = fmt := by
|
||
rcases c with ⟨_, _, _⟩
|
||
rfl
|
||
|
||
end Ctx
|
||
|
||
-- ── Concrete demo (operational sanity check via `#eval`) ──────────────────
|
||
|
||
/-- Default rendering context: 800×600, sRGB. -/
|
||
def defaultCtx : Ctx :=
|
||
{ width := 800, height := 600, pixelFmt := PixelFormat.rgbaSrgb }
|
||
|
||
#eval defaultCtx.width -- expected: 800
|
||
#eval defaultCtx.resize 1024 768 |>.width -- expected: 1024
|
||
#eval (defaultCtx.resize 1024 768).reformat PixelFormat.rgbaF32 |>.pixelFmt
|
||
-- expected: PixelFormat.rgbaF32
|
||
#eval ((defaultCtx.resize 100 100).resize 200 200).width -- expected: 200
|
||
|
||
end Topolei.Obs
|