From 88251423d6c658369ac58412f32040f1ff5bfee3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 10:57:45 +0000 Subject: [PATCH 1/4] contract: lane layout per class, chosen at compile time; probe resolves it lane_codec: EpiLaneSpec (width, code space, never-touched code, value and presence offsets) declared by the consumer as EpiLaneClass::SPEC, built with checked() so an invalid layout fails to compile. ONNX/TFLite annotations map through CodeSpace::from_zero_point. ClassView::epi_lanes names the same constant for a classid; None = undeclared, and a writer refuses. thought_layers_probe: write_epi is generic over the class layout and refuses when the ClassView declares none or another one. 9-bit lanes still use ndarray codec9's never_touched; a test pins that the contract rule and the codec agree on all 512 codes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XAqKMPWTwovjYJEUMuGPb4 --- .../examples/thought_layers_probe.rs | 462 +++++++++++------- crates/lance-graph-contract/src/class_view.rs | 14 + crates/lance-graph-contract/src/lane_codec.rs | 437 +++++++++++++++++ crates/lance-graph-contract/src/lib.rs | 1 + 4 files changed, 729 insertions(+), 185 deletions(-) create mode 100644 crates/lance-graph-contract/src/lane_codec.rs diff --git a/crates/cognitive-shader-driver/examples/thought_layers_probe.rs b/crates/cognitive-shader-driver/examples/thought_layers_probe.rs index d42221286..4e7508a4c 100644 --- a/crates/cognitive-shader-driver/examples/thought_layers_probe.rs +++ b/crates/cognitive-shader-driver/examples/thought_layers_probe.rs @@ -31,6 +31,8 @@ use std::collections::HashMap; use lance_graph_contract::alpha::{AlphaAddr, AlphaAllocation, AlphaMask, AlphaOverlay}; use lance_graph_contract::canonical_node::{EdgeBlock, NodeGuid, NodeRow, TailVariant}; +use lance_graph_contract::class_view::{ClassId, ClassView}; +use lance_graph_contract::lane_codec::{EpiLaneClass, EpiLaneSpec, LaneWidth}; use ndarray::hpc::codec9::EpiLane9; /// One thought's writes for [`ThoughtTables::write_parallel`]. @@ -89,6 +91,9 @@ pub enum Refusal { KeyChanged, /// A slot-placed thought changed bytes outside its slot. OutsideSlot, + /// The class declares no lane layout, or a different one than the write + /// was compiled for. + LaneLayout, } /// One row's change against the base: the slots that differ and their XOR. @@ -185,85 +190,35 @@ pub struct Table { deltas: HashMap, } -/// Epistemic lanes per layout: one presence bit and one byte each. -pub const EPI_LANES: usize = 16; - -/// The width of a row's epistemic lanes. -/// -/// Both widths read "never touched" (NaN, `$null`, UNKNOWN) as presence 0 -/// and value 0. At U9 the presence bit is also the sign, so presence 0 with -/// a nonzero magnitude is a negative number (DR512, `ndarray::hpc::codec9`). -/// At U8 presence 0 with a nonzero value cannot be produced: it would mean -/// U9 bytes read through a U8 layout, which the layout type rules out at -/// compile time, so it is not checked per lane. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LaneWidth { - U8, - U9, -} - -/// Where a row's epistemic lanes sit: [`EPI_LANES`] value bytes from -/// `values` and their presence bits, little-endian, in the two bytes at -/// `presence`. Lab layout: production reads it from the class's ClassView. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct EpiLanes { - width: LaneWidth, - values: usize, - presence: usize, -} - -impl EpiLanes { - /// A layout outside the key slot whose value bytes and presence word do - /// not overlap; `None` otherwise. - #[must_use] - pub const fn new(width: LaneWidth, values: usize, presence: usize) -> Option { - let disjoint = values + EPI_LANES <= presence || presence + 2 <= values; - if values < SLOT - || presence < SLOT - || values + EPI_LANES > 512 - || presence + 2 > 512 - || !disjoint - { - return None; - } - Some(Self { - width, - values, - presence, - }) - } - - fn present(&self, row: &[u8; 512], lane: usize) -> bool { - let word = u16::from_le_bytes([row[self.presence], row[self.presence + 1]]); - (word >> lane) & 1 == 1 +/// Whether a lane of `row` was never touched under `spec`. A 9-bit lane is +/// read through `ndarray`'s DR512 codeword, so the probe and the codec share +/// one definition. +fn never_touched(spec: &EpiLaneSpec, row: &[u8; 512], lane: usize) -> bool { + let (p, m) = (spec.present(row, lane), spec.value(row, lane)); + match spec.width { + LaneWidth::Bits9 => EpiLane9::from_codeword(u16::from(m) | (u16::from(p) << 8)) + .is_some_and(EpiLane9::never_touched), + LaneWidth::Bits8 => spec.never_touched(m, p), } +} - /// Presence 0 and value 0: the lane holds no value. - fn never_touched(&self, row: &[u8; 512], lane: usize) -> bool { - let (p, m) = (self.present(row, lane), row[self.values + lane]); - match self.width { - LaneWidth::U9 => EpiLane9::from_codeword(u16::from(m) | (u16::from(p) << 8)) - .is_some_and(EpiLane9::never_touched), - LaneWidth::U8 => !p && m == 0, +/// Every never-touched lane of `new` takes the lane of `prior`: its value +/// byte and, where the class has one, its presence bit. Returns the lanes kept. +fn keep_unknown(spec: &EpiLaneSpec, prior: &[u8; 512], new: &mut [u8; 512]) -> u64 { + let mut kept = 0u64; + for lane in 0..usize::from(spec.lanes) { + if never_touched(spec, new, lane) { + new[usize::from(spec.values) + lane] = prior[usize::from(spec.values) + lane]; + kept |= 1 << lane; } } - - /// Every never-touched lane of `new` takes the lane of `prior`, value - /// and presence bit together. Returns the lanes it kept. - fn keep_unknown(&self, prior: &[u8; 512], new: &mut [u8; 512]) -> u16 { - let mut kept = 0u16; - for lane in 0..EPI_LANES { - if self.never_touched(new, lane) { - new[self.values + lane] = prior[self.values + lane]; - kept |= 1 << lane; - } + if let Some(p) = spec.presence { + for lane in (0..usize::from(spec.lanes)).filter(|l| kept >> l & 1 == 1) { + let (byte, bit) = (usize::from(p) + lane / 8, 1u8 << (lane % 8)); + new[byte] = (new[byte] & !bit) | (prior[byte] & bit); } - let word = u16::from_le_bytes([new[self.presence], new[self.presence + 1]]); - let from = u16::from_le_bytes([prior[self.presence], prior[self.presence + 1]]); - let merged = (word & !kept) | (from & kept); - new[self.presence..self.presence + 2].copy_from_slice(&merged.to_le_bytes()); - kept } + kept } /// What a write did. @@ -443,27 +398,35 @@ impl<'a> ThoughtTables<'a> { }) } - /// A sparse write of epistemic lanes. A lane the thought leaves never - /// touched (presence 0, value 0) is not written: it keeps what the - /// thought read there before, so UNKNOWN never overwrites a known value - /// and the merge on read returns the earlier value. Every other lane, - /// including a U9 negative (presence 0, magnitude > 0) and +0, is - /// written as given. Bytes outside the lanes are written as by - /// [`write`](Self::write). + /// A sparse write of epistemic lanes laid out as `L` declares. A lane the + /// thought leaves never touched is not written: it keeps what the thought + /// read there before, so UNKNOWN never overwrites a known value and the + /// merge on read returns the earlier value. Every other lane, including a + /// 9-bit negative (presence 0, magnitude > 0) and +0, is written as given. + /// Bytes outside the lanes are written as by [`write`](Self::write). + /// + /// `L` is fixed at compile time; `view` must declare the same layout for + /// `class`, or the write is refused. /// /// # Errors - /// As [`write`](Self::write). - pub fn write_epi( + /// [`Refusal::LaneLayout`] when `view` declares no layout or another one + /// for `class` (nothing is stored and no look recorded); otherwise as + /// [`write`](Self::write). + pub fn write_epi( &mut self, + view: &impl ClassView, + class: ClassId, thought: ThoughtId, addr: AlphaAddr, rung: u8, row: &[u8; 512], - lanes: &EpiLanes, ) -> Result { + if view.epi_lanes(class) != Some(L::SPEC) { + return Err(Refusal::LaneLayout); + } let prior = self.read(thought, addr)?; let mut new = *row; - lanes.keep_unknown(&prior, &mut new); + keep_unknown(&L::SPEC, &prior, &mut new); self.write(thought, addr, rung, &new) } @@ -889,125 +852,215 @@ mod tests { } // ── Epistemic lanes: NaN is not written, merge on read keeps the prior ── + // + // The layout of each class is a compile-time constant (`EpiLaneClass`); + // the ClassView names the same constant for the classid. + + use lance_graph_contract::lane_codec::{checked, CodeSpace, NanCode}; + use lance_graph_contract::ontology::{DisplayTemplate, FieldRef}; + + const VALUES: u16 = 2 * SLOT as u16; + const PRESENCE: u16 = 3 * SLOT as u16; + const CLASS: ClassId = 7; + + /// DR512: 9-bit sign-magnitude, presence bit = sign. + struct Dr512; + impl EpiLaneClass for Dr512 { + const SPEC: EpiLaneSpec = checked(EpiLaneSpec { + width: LaneWidth::Bits9, + space: CodeSpace::Sym, + nan: NanCode::PresenceZero, + values: VALUES, + presence: Some(PRESENCE), + lanes: 16, + }); + } - const VALUES: usize = 2 * SLOT; - const PRESENCE: usize = 3 * SLOT; + /// ONNX `QuantizeLinear` uint8 with zero point 128, plus a presence plane. + struct OnnxU8; + impl EpiLaneClass for OnnxU8 { + const SPEC: EpiLaneSpec = checked(EpiLaneSpec { + width: LaneWidth::Bits8, + space: CodeSpace::from_zero_point(128), + nan: NanCode::PresenceZero, + values: VALUES, + presence: Some(PRESENCE), + lanes: 16, + }); + } + + /// TFLite narrow symmetric int8 weights, code -128 reserved as NaN. + struct TfliteSym; + impl EpiLaneClass for TfliteSym { + const SPEC: EpiLaneSpec = checked(EpiLaneSpec { + width: LaneWidth::Bits8, + space: CodeSpace::from_zero_point(0), + nan: NanCode::SymMin, + values: VALUES, + presence: None, + lanes: 16, + }); + } + + /// A ClassView that declares one layout (or none) for every class. + struct View(Option); + impl ClassView for View { + fn fields(&self, _class: ClassId) -> &[FieldRef] { + &[] + } + fn template(&self, _class: ClassId) -> DisplayTemplate { + DisplayTemplate::Card + } + fn dolce_category_id(&self, _class: ClassId) -> u8 { + 0 + } + fn epi_lanes(&self, _class: ClassId) -> Option { + self.0 + } + } - fn lanes(width: LaneWidth) -> EpiLanes { - EpiLanes::new(width, VALUES, PRESENCE).expect("lab layout") + fn view() -> View { + View(Some(L::SPEC)) } - /// Base rows whose lanes all hold +(5 + lane): presence 1, value set. + /// Base rows whose lanes all hold value 5 + lane with presence 1. fn epi_rows() -> Vec { + let (v, p) = (usize::from(VALUES) - 32, usize::from(PRESENCE) - 32); let mut rows = base(8); for r in &mut rows { - for lane in 0..EPI_LANES { - r.value[VALUES - 32 + lane] = 5 + lane as u8; + for lane in 0..16 { + r.value[v + lane] = 5 + lane as u8; } - r.value[PRESENCE - 32..PRESENCE - 32 + 2].copy_from_slice(&u16::MAX.to_le_bytes()); + r.value[p..p + 2].copy_from_slice(&u16::MAX.to_le_bytes()); } rows } fn set_lane(row: &mut [u8; 512], lane: usize, present: bool, value: u8) { - row[VALUES + lane] = value; - let mut w = u16::from_le_bytes([row[PRESENCE], row[PRESENCE + 1]]); + let (v, p) = (usize::from(VALUES), usize::from(PRESENCE)); + row[v + lane] = value; + let mut w = u16::from_le_bytes([row[p], row[p + 1]]); w = (w & !(1 << lane)) | (u16::from(present) << lane); - row[PRESENCE..PRESENCE + 2].copy_from_slice(&w.to_le_bytes()); + row[p..p + 2].copy_from_slice(&w.to_le_bytes()); } fn lane(row: &[u8; 512], lane: usize) -> (bool, u8) { - let w = u16::from_le_bytes([row[PRESENCE], row[PRESENCE + 1]]); - ((w >> lane) & 1 == 1, row[VALUES + lane]) + let (v, p) = (usize::from(VALUES), usize::from(PRESENCE)); + let w = u16::from_le_bytes([row[p], row[p + 1]]); + ((w >> lane) & 1 == 1, row[v + lane]) + } + + fn one_thought(rows: &[NodeRow]) -> (AlphaAllocation<'_>, ThoughtId) { + (AlphaAllocation::over(rows), ThoughtId(1)) + } + + fn placed<'a>(alloc: &'a AlphaAllocation<'a>) -> ThoughtTables<'a> { + let mut tt = ThoughtTables::over(alloc, 1); + let t = tt.open_table().unwrap(); + tt.place(ThoughtId(1), Placement::Table(t)).unwrap(); + tt } + /// The contract's never-touched rule and ndarray's DR512 codeword agree on + /// all 512 codes. #[test] - fn layouts_over_the_key_or_overlapping_are_refused() { - assert!( - EpiLanes::new(LaneWidth::U9, 0, PRESENCE).is_none(), - "key slot" - ); - assert!( - EpiLanes::new(LaneWidth::U9, VALUES, VALUES + 8).is_none(), - "overlap" - ); - assert!( - EpiLanes::new(LaneWidth::U9, 500, PRESENCE).is_none(), - "past the row" + fn contract_and_codec9_agree_on_never_touched() { + for code in 0u16..512 { + let e = EpiLane9::from_codeword(code).unwrap(); + assert_eq!( + Dr512::SPEC.never_touched(e.magnitude(), e.presence()), + e.never_touched(), + "code {code:#x}" + ); + } + } + + /// No declared layout, or a different one, refuses: nothing stored, no + /// look recorded. + #[test] + fn an_undeclared_or_different_layout_is_refused() { + let rows = epi_rows(); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); + let mut row = row_bytes(&rows[2]); + set_lane(&mut row, 4, true, 99); + for v in [View(None), view::()] { + let r = tt.write_epi::(&v, CLASS, th, rows[2].key, 1, &row); + assert_eq!(r, Err(Refusal::LaneLayout)); + } + assert_eq!(tt.stored_bytes(), 0); + assert!(!tt.looked(th).unwrap().contains(2), "no look recorded"); + let ok = tt.write_epi::(&view::(), CLASS, th, rows[2].key, 1, &row); + assert!(matches!(ok, Ok(Written::Stored { .. })), "positive control"); + } + + fn nan_over_known() { + let rows = epi_rows(); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); + let mut row = row_bytes(&rows[2]); + set_lane(&mut row, 4, false, 0); + let w = tt + .write_epi::(&view::(), CLASS, th, rows[2].key, 1, &row) + .unwrap(); + assert_eq!(w, Written::NoChange); + assert_eq!(tt.stored_bytes(), 0); + assert_eq!( + lane(&tt.read(th, rows[2].key).unwrap(), 4), + (true, 9), + "base kept" ); - assert!(EpiLanes::new(LaneWidth::U8, VALUES, PRESENCE).is_some()); + assert!(tt.looked(th).unwrap().contains(2), "the look is recorded"); } - /// NaN over a known base value: the read returns the base value and - /// nothing is stored. Both widths. + /// NaN over a known base value: nothing stored, the base value is read. #[test] fn nan_over_a_known_value_is_not_written() { - for width in [LaneWidth::U8, LaneWidth::U9] { - let rows = epi_rows(); - let alloc = AlphaAllocation::over(&rows); - let mut tt = ThoughtTables::over(&alloc, 1); - let t = tt.open_table().unwrap(); - tt.place(ThoughtId(1), Placement::Table(t)).unwrap(); - let mut row = row_bytes(&rows[2]); - set_lane(&mut row, 4, false, 0); - let w = tt - .write_epi(ThoughtId(1), rows[2].key, 1, &row, &lanes(width)) - .unwrap(); - assert_eq!(w, Written::NoChange, "{width:?}"); - assert_eq!(tt.stored_bytes(), 0, "{width:?}"); - let read = tt.read(ThoughtId(1), rows[2].key).unwrap(); - assert_eq!(lane(&read, 4), (true, 9), "{width:?}: base value kept"); - assert!( - tt.looked(ThoughtId(1)).unwrap().contains(2), - "the look is recorded" - ); - } + nan_over_known::(); + nan_over_known::(); } - /// NaN after the thought's own write keeps what the thought wrote, not - /// the base: the merge on read returns the earlier value. + /// NaN after the thought's own write keeps what the thought wrote. #[test] fn nan_after_an_own_write_keeps_the_own_value() { let rows = epi_rows(); - let alloc = AlphaAllocation::over(&rows); - let mut tt = ThoughtTables::over(&alloc, 1); - let t = tt.open_table().unwrap(); - tt.place(ThoughtId(1), Placement::Table(t)).unwrap(); - let l = lanes(LaneWidth::U9); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); + let v = view::(); let mut row = row_bytes(&rows[1]); set_lane(&mut row, 3, true, 40); - tt.write_epi(ThoughtId(1), rows[1].key, 1, &row, &l) + tt.write_epi::(&v, CLASS, th, rows[1].key, 1, &row) .unwrap(); set_lane(&mut row, 3, false, 0); let w = tt - .write_epi(ThoughtId(1), rows[1].key, 1, &row, &l) + .write_epi::(&v, CLASS, th, rows[1].key, 1, &row) .unwrap(); assert_eq!(w, Written::NoChange); - let read = tt.read(ThoughtId(1), rows[1].key).unwrap(); - assert_eq!(lane(&read, 3), (true, 40), "own write kept, not the base 8"); + assert_eq!( + lane(&tt.read(th, rows[1].key).unwrap(), 3), + (true, 40), + "not the base 8" + ); } - /// U9: presence 0 with magnitude 5 is −5, written and read back. + /// 9-bit: presence 0 with magnitude 5 is -5, written and read back. #[test] - fn a_u9_negative_is_written() { + fn a_nine_bit_negative_is_written() { let rows = epi_rows(); - let alloc = AlphaAllocation::over(&rows); - let mut tt = ThoughtTables::over(&alloc, 1); - let t = tt.open_table().unwrap(); - tt.place(ThoughtId(1), Placement::Table(t)).unwrap(); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); let mut row = row_bytes(&rows[0]); set_lane(&mut row, 6, false, 5); let w = tt - .write_epi(ThoughtId(1), rows[0].key, 1, &row, &lanes(LaneWidth::U9)) + .write_epi::(&view::(), CLASS, th, rows[0].key, 1, &row) .unwrap(); assert!(matches!(w, Written::Stored { .. })); - let (p, m) = lane(&tt.read(ThoughtId(1), rows[0].key).unwrap(), 6); - let v = EpiLane9::from_codeword(u16::from(m) | (u16::from(p) << 8)).unwrap(); - assert_eq!(v.value(), Some(-5)); + let (p, m) = lane(&tt.read(th, rows[0].key).unwrap(), 6); + let e = EpiLane9::from_codeword(u16::from(m) | (u16::from(p) << 8)).unwrap(); + assert_eq!(e.value(), Some(-5)); } - /// A computed −0.499 is encoded as +0 in the same step and is written: - /// +0 is a value, never NaN. + /// A computed -0.499 is encoded as +0 in the same step and is written. #[test] fn a_computed_negative_zero_is_written_as_plus_zero() { use ndarray::hpc::codec8::{Calibration, TiesEven}; @@ -1020,47 +1073,86 @@ mod tests { let code = Codec9::::encode_touched(-0.499).unwrap(); assert_eq!((code.presence(), code.magnitude()), (true, 0)); let rows = epi_rows(); - let alloc = AlphaAllocation::over(&rows); - let mut tt = ThoughtTables::over(&alloc, 1); - let t = tt.open_table().unwrap(); - tt.place(ThoughtId(1), Placement::Table(t)).unwrap(); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); let mut row = row_bytes(&rows[5]); set_lane(&mut row, 0, code.presence(), code.magnitude()); let w = tt - .write_epi(ThoughtId(1), rows[5].key, 1, &row, &lanes(LaneWidth::U9)) + .write_epi::(&view::(), CLASS, th, rows[5].key, 1, &row) .unwrap(); assert!( matches!(w, Written::Stored { .. }), "+0 replaces the base 5" ); - let read = tt.read(ThoughtId(1), rows[5].key).unwrap(); - assert_eq!(lane(&read, 0), (true, 0)); + assert_eq!(lane(&tt.read(th, rows[5].key).unwrap(), 0), (true, 0)); + } + + fn nan_beside_change() { + let rows = epi_rows(); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); + let mut row = row_bytes(&rows[4]); + set_lane(&mut row, 1, false, 0); + set_lane(&mut row, 2, true, 99); + let w = tt + .write_epi::(&view::(), CLASS, th, rows[4].key, 1, &row) + .unwrap(); + assert_eq!(w, Written::Stored { slots: 1 << 2 }, "value slot only"); + let read = tt.read(th, rows[4].key).unwrap(); + assert_eq!(lane(&read, 1), (true, 6)); + assert_eq!(lane(&read, 2), (true, 99)); } - /// A NaN lane next to a changed lane: only the changed lane is stored, - /// and the NaN lane reads its prior value. + /// A NaN lane next to a changed lane: only the change is stored. #[test] fn nan_beside_a_change_stores_only_the_change() { - for width in [LaneWidth::U8, LaneWidth::U9] { - let rows = epi_rows(); - let alloc = AlphaAllocation::over(&rows); - let mut tt = ThoughtTables::over(&alloc, 1); - let t = tt.open_table().unwrap(); - tt.place(ThoughtId(1), Placement::Table(t)).unwrap(); - let mut row = row_bytes(&rows[4]); - set_lane(&mut row, 1, false, 0); - set_lane(&mut row, 2, true, 99); - let w = tt - .write_epi(ThoughtId(1), rows[4].key, 1, &row, &lanes(width)) - .unwrap(); - assert_eq!( - w, - Written::Stored { slots: 1 << 2 }, - "{width:?}: value slot only" - ); - let read = tt.read(ThoughtId(1), rows[4].key).unwrap(); - assert_eq!(lane(&read, 1), (true, 6), "{width:?}"); - assert_eq!(lane(&read, 2), (true, 99), "{width:?}"); - } + nan_beside_change::(); + nan_beside_change::(); + } + + /// Asymmetric 8-bit with a presence plane: value 0 with presence 1 is a + /// code like any other and is written. + #[test] + fn an_asym_zero_code_is_written() { + let rows = epi_rows(); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); + let mut row = row_bytes(&rows[3]); + set_lane(&mut row, 5, true, 0); + let w = tt + .write_epi::(&view::(), CLASS, th, rows[3].key, 1, &row) + .unwrap(); + assert!(matches!(w, Written::Stored { .. })); + assert_eq!(lane(&tt.read(th, rows[3].key).unwrap(), 5), (true, 0)); + } + + /// TFLite narrow symmetric: code -128 is not written; code 0 is a value + /// and is. There is no presence plane, so its bytes are never touched. + #[test] + fn a_tflite_min_code_is_not_written_and_zero_is() { + let rows = epi_rows(); + let (alloc, th) = one_thought(&rows); + let mut tt = placed(&alloc); + let v = view::(); + let mut row = row_bytes(&rows[6]); + row[usize::from(VALUES) + 7] = 0x80; + let w = tt + .write_epi::(&v, CLASS, th, rows[6].key, 1, &row) + .unwrap(); + assert_eq!(w, Written::NoChange); + assert_eq!( + tt.read(th, rows[6].key).unwrap()[usize::from(VALUES) + 7], + 12, + "base kept" + ); + row[usize::from(VALUES) + 7] = 0; + let w = tt + .write_epi::(&v, CLASS, th, rows[6].key, 1, &row) + .unwrap(); + assert!(matches!(w, Written::Stored { .. })); + assert_eq!( + tt.read(th, rows[6].key).unwrap()[usize::from(VALUES) + 7], + 0 + ); } } diff --git a/crates/lance-graph-contract/src/class_view.rs b/crates/lance-graph-contract/src/class_view.rs index 3674691e4..9d593009f 100644 --- a/crates/lance-graph-contract/src/class_view.rs +++ b/crates/lance-graph-contract/src/class_view.rs @@ -1358,6 +1358,20 @@ pub trait ClassView { None } + /// The epistemic lane layout this class declares + /// ([`lane_codec`](crate::lane_codec)): lane width, code space, which code + /// means never touched, and where the value and presence bytes sit. The + /// consumer fixes it at compile time as an + /// [`EpiLaneClass::SPEC`](crate::lane_codec::EpiLaneClass::SPEC); this + /// lookup names that constant for a classid. `None` = undeclared, and a + /// writer REFUSES: a lane read under a guessed layout could take a + /// negative 9-bit value for "never touched". Selection only; never changes + /// stored bytes. + #[inline] + fn epi_lanes(&self, _class: ClassId) -> Option { + None + } + /// Which value-slab schema preset this class materialises in /// [`NodeRow::value`](crate::canonical_node::NodeRow::value). /// diff --git a/crates/lance-graph-contract/src/lane_codec.rs b/crates/lance-graph-contract/src/lane_codec.rs new file mode 100644 index 000000000..b211e8c8a --- /dev/null +++ b/crates/lance-graph-contract/src/lane_codec.rs @@ -0,0 +1,437 @@ +//! Epistemic lane layout of a class, chosen by the consumer at compile time. +//! +//! A class that carries quantized values in its row declares, once, how its +//! lanes are stored: their width, the code space, which code means "never +//! touched" (NaN, `$null`, UNKNOWN) and where the value bytes and the presence +//! bits sit. The consumer picks this at compile time, typically from the +//! quantization annotations it already has (ONNX `QuantizeLinear` / +//! TFLite tensor quantization: a zero point of 0 is [`CodeSpace::Sym`], any +//! other zero point is [`CodeSpace::Asym`]), and states it as a constant: +//! +//! ``` +//! use lance_graph_contract::lane_codec::{ +//! checked, CodeSpace, EpiLaneClass, EpiLaneSpec, LaneWidth, NanCode, +//! }; +//! +//! /// A class whose lanes are ONNX uint8 values with zero point 128 and a +//! /// presence plane. +//! struct SensorReading; +//! impl EpiLaneClass for SensorReading { +//! const SPEC: EpiLaneSpec = checked(EpiLaneSpec { +//! width: LaneWidth::Bits8, +//! space: CodeSpace::from_zero_point(128), +//! nan: NanCode::PresenceZero, +//! values: 64, +//! presence: Some(96), +//! lanes: 16, +//! }); +//! } +//! assert_eq!(SensorReading::SPEC.space, CodeSpace::Asym); +//! ``` +//! +//! A combination that has no meaning does not compile: +//! +//! ```compile_fail,E0080 +//! use lance_graph_contract::lane_codec::{ +//! checked, CodeSpace, EpiLaneClass, EpiLaneSpec, LaneWidth, NanCode, +//! }; +//! struct Bad; +//! impl EpiLaneClass for Bad { +//! // A 9-bit lane is sign-magnitude: it has no zero point. +//! const SPEC: EpiLaneSpec = checked(EpiLaneSpec { +//! width: LaneWidth::Bits9, +//! space: CodeSpace::Asym, +//! nan: NanCode::PresenceZero, +//! values: 64, +//! presence: Some(96), +//! lanes: 16, +//! }); +//! } +//! let _ = Bad::SPEC; +//! ``` +//! +//! [`ClassView::epi_lanes`](crate::class_view::ClassView::epi_lanes) names the +//! same constant for a class, so a reader holding only a classid can resolve +//! it, and a writer generic over [`EpiLaneClass`] can refuse a row whose class +//! declares a different layout. +//! +//! # Never touched +//! +//! - [`NanCode::PresenceZero`]: presence 0 **and** value 0, at 8 and 9 bits +//! alike. At 9 bits the presence bit is also the sign (DR512, `ndarray` +//! `hpc::codec9`), so presence 0 with a nonzero magnitude is a negative +//! value. At 8 bits presence 0 with a nonzero value is a layout mix-up; the +//! width in this spec is what rules it out. +//! - [`NanCode::SymMin`]: the code `-128` (byte `0x80`) of a narrow symmetric +//! 8-bit lane, which never encodes a value (`ndarray` `codec8::NaNAtMin`). +//! - [`NanCode::None`]: every code is a value; nothing is ever skipped. +//! +//! A sparse write leaves a never-touched lane unwritten, so it keeps the value +//! read before. This module describes layout only; it stores nothing and adds +//! no bytes to a row. + +/// Bits per lane. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum LaneWidth { + /// One byte per lane. + Bits8, + /// One magnitude byte per lane plus its presence/sign bit (DR512). + Bits9, +} + +/// The code space of a lane. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum CodeSpace { + /// Zero point 0: values are symmetric around code 0. + Sym, + /// A nonzero zero point. + Asym, +} + +impl CodeSpace { + /// The code space of an ONNX / TFLite quantization annotation. + #[must_use] + pub const fn from_zero_point(zero_point: i32) -> Self { + if zero_point == 0 { + Self::Sym + } else { + Self::Asym + } + } +} + +/// Which stored code means "never touched". +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum NanCode { + /// No code: every stored code is a value. + None, + /// Presence 0 and value 0. + PresenceZero, + /// Byte `0x80` (code `-128`) of a narrow symmetric 8-bit lane. + SymMin, +} + +/// Where a class keeps its epistemic lanes, and how they are coded. +/// +/// Offsets are bytes into the 512-byte row (key, edge block, value slab). +/// Presence bits are little-endian, bit `i` for lane `i`, in +/// `lanes.div_ceil(8)` bytes. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EpiLaneSpec { + pub width: LaneWidth, + pub space: CodeSpace, + pub nan: NanCode, + /// First value byte; one byte per lane. + pub values: u16, + /// First presence byte, if the class has a presence plane. + pub presence: Option, + /// Number of lanes, `1..=64`. + pub lanes: u8, +} + +/// Bytes of a row. +pub const ROW_BYTES: u16 = 512; +/// First byte of the value slab: lanes never overlap the key or edge block. +pub const VALUE_SLAB_START: u16 = 32; + +/// Why an [`EpiLaneSpec`] is refused. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SpecError { + /// `lanes` is 0 or above 64. + LaneCount, + /// A region starts before the value slab or ends past the row. + OutOfSlab, + /// The value bytes and the presence bytes overlap. + Overlap, + /// A 9-bit lane is sign-magnitude: it is symmetric, its never-touched + /// code is presence 0 and value 0, and it needs the presence plane. + NineBitIsDr512, + /// `PresenceZero` without a presence plane. + NoPresencePlane, + /// A presence plane under `None` or `SymMin`, where it would mean nothing. + UnusedPresencePlane, + /// `SymMin` needs an 8-bit symmetric lane: in an asymmetric space code + /// `-128` is a value. + SymMinNeedsSym8, +} + +impl EpiLaneSpec { + /// Bytes of the presence plane. + #[must_use] + pub const fn presence_bytes(&self) -> u16 { + (self.lanes as u16).div_ceil(8) + } + + /// Checks the spec against the rules above. + /// + /// # Errors + /// The first rule broken. + pub const fn validate(&self) -> Result<(), SpecError> { + if self.lanes == 0 || self.lanes > 64 { + return Err(SpecError::LaneCount); + } + let v_end = self.values + self.lanes as u16; + if self.values < VALUE_SLAB_START || v_end > ROW_BYTES { + return Err(SpecError::OutOfSlab); + } + if let Some(p) = self.presence { + let p_end = p + self.presence_bytes(); + if p < VALUE_SLAB_START || p_end > ROW_BYTES { + return Err(SpecError::OutOfSlab); + } + if p < v_end && self.values < p_end { + return Err(SpecError::Overlap); + } + } + match (self.width, self.space, self.nan, self.presence) { + (LaneWidth::Bits9, CodeSpace::Sym, NanCode::PresenceZero, Some(_)) => Ok(()), + (LaneWidth::Bits9, _, _, _) => Err(SpecError::NineBitIsDr512), + (LaneWidth::Bits8, _, NanCode::PresenceZero, None) => Err(SpecError::NoPresencePlane), + (LaneWidth::Bits8, _, NanCode::PresenceZero, Some(_)) => Ok(()), + (LaneWidth::Bits8, _, NanCode::None | NanCode::SymMin, Some(_)) => { + Err(SpecError::UnusedPresencePlane) + } + (LaneWidth::Bits8, CodeSpace::Sym, NanCode::SymMin, None) => Ok(()), + (LaneWidth::Bits8, CodeSpace::Asym, NanCode::SymMin, None) => { + Err(SpecError::SymMinNeedsSym8) + } + (LaneWidth::Bits8, _, NanCode::None, None) => Ok(()), + } + } + + /// Whether a lane holding `value` with presence bit `present` was never + /// touched. `present` is ignored when the class has no presence plane. + #[must_use] + pub const fn never_touched(&self, value: u8, present: bool) -> bool { + match self.nan { + NanCode::None => false, + NanCode::PresenceZero => !present && value == 0, + NanCode::SymMin => value == 0x80, + } + } + + /// Lane `lane`'s value byte in `row`. + #[must_use] + pub fn value(&self, row: &[u8], lane: usize) -> u8 { + row[self.values as usize + lane] + } + + /// Lane `lane`'s presence bit in `row`; `false` without a presence plane. + #[must_use] + pub fn present(&self, row: &[u8], lane: usize) -> bool { + self.presence + .is_some_and(|p| (row[p as usize + lane / 8] >> (lane % 8)) & 1 == 1) + } +} + +/// Returns `spec`, or fails to compile when it is used in a constant and +/// breaks a rule of [`EpiLaneSpec::validate`]. +#[must_use] +pub const fn checked(spec: EpiLaneSpec) -> EpiLaneSpec { + match spec.validate() { + Ok(()) => spec, + Err(SpecError::LaneCount) => panic!("EpiLaneSpec: lanes must be 1..=64"), + Err(SpecError::OutOfSlab) => panic!("EpiLaneSpec: lanes must lie in the value slab"), + Err(SpecError::Overlap) => panic!("EpiLaneSpec: value and presence bytes overlap"), + Err(SpecError::NineBitIsDr512) => { + panic!("EpiLaneSpec: a 9-bit lane is Sym + PresenceZero with a presence plane") + } + Err(SpecError::NoPresencePlane) => { + panic!("EpiLaneSpec: PresenceZero needs a presence plane") + } + Err(SpecError::UnusedPresencePlane) => { + panic!("EpiLaneSpec: a presence plane needs NanCode::PresenceZero") + } + Err(SpecError::SymMinNeedsSym8) => panic!("EpiLaneSpec: SymMin needs an 8-bit Sym lane"), + } +} + +/// A class's lane layout, fixed at compile time. +pub trait EpiLaneClass { + /// Build with [`checked`] so an invalid layout fails to compile. + const SPEC: EpiLaneSpec; +} + +#[cfg(test)] +mod tests { + use super::*; + + const DR512: EpiLaneSpec = EpiLaneSpec { + width: LaneWidth::Bits9, + space: CodeSpace::Sym, + nan: NanCode::PresenceZero, + values: 64, + presence: Some(96), + lanes: 16, + }; + + #[test] + fn valid_layouts_pass() { + assert_eq!(DR512.validate(), Ok(())); + let u8_asym = EpiLaneSpec { + width: LaneWidth::Bits8, + space: CodeSpace::Asym, + ..DR512 + }; + assert_eq!(u8_asym.validate(), Ok(())); + let tflite = EpiLaneSpec { + width: LaneWidth::Bits8, + nan: NanCode::SymMin, + presence: None, + ..DR512 + }; + assert_eq!(tflite.validate(), Ok(())); + let plain = EpiLaneSpec { + width: LaneWidth::Bits8, + space: CodeSpace::Asym, + nan: NanCode::None, + presence: None, + ..DR512 + }; + assert_eq!(plain.validate(), Ok(())); + } + + #[test] + fn each_rule_refuses() { + let e = |s: EpiLaneSpec| s.validate().unwrap_err(); + assert_eq!(e(EpiLaneSpec { lanes: 0, ..DR512 }), SpecError::LaneCount); + assert_eq!(e(EpiLaneSpec { lanes: 65, ..DR512 }), SpecError::LaneCount); + assert_eq!( + e(EpiLaneSpec { + values: 16, + ..DR512 + }), + SpecError::OutOfSlab + ); + assert_eq!( + e(EpiLaneSpec { + values: 500, + ..DR512 + }), + SpecError::OutOfSlab + ); + assert_eq!( + e(EpiLaneSpec { + presence: Some(511), + ..DR512 + }), + SpecError::OutOfSlab + ); + assert_eq!( + e(EpiLaneSpec { + presence: Some(70), + ..DR512 + }), + SpecError::Overlap + ); + assert_eq!( + e(EpiLaneSpec { + space: CodeSpace::Asym, + ..DR512 + }), + SpecError::NineBitIsDr512 + ); + assert_eq!( + e(EpiLaneSpec { + presence: None, + ..DR512 + }), + SpecError::NineBitIsDr512 + ); + assert_eq!( + e(EpiLaneSpec { + nan: NanCode::SymMin, + ..DR512 + }), + SpecError::NineBitIsDr512 + ); + let b8 = EpiLaneSpec { + width: LaneWidth::Bits8, + ..DR512 + }; + assert_eq!( + e(EpiLaneSpec { + presence: None, + ..b8 + }), + SpecError::NoPresencePlane + ); + assert_eq!( + e(EpiLaneSpec { + nan: NanCode::None, + ..b8 + }), + SpecError::UnusedPresencePlane + ); + assert_eq!( + e(EpiLaneSpec { + nan: NanCode::SymMin, + ..b8 + }), + SpecError::UnusedPresencePlane + ); + assert_eq!( + e(EpiLaneSpec { + nan: NanCode::SymMin, + space: CodeSpace::Asym, + presence: None, + ..b8 + }), + SpecError::SymMinNeedsSym8 + ); + } + + #[test] + fn presence_bytes_round_up() { + assert_eq!(EpiLaneSpec { lanes: 1, ..DR512 }.presence_bytes(), 1); + assert_eq!(EpiLaneSpec { lanes: 9, ..DR512 }.presence_bytes(), 2); + assert_eq!(EpiLaneSpec { lanes: 64, ..DR512 }.presence_bytes(), 8); + } + + #[test] + fn zero_point_selects_the_code_space() { + assert_eq!(CodeSpace::from_zero_point(0), CodeSpace::Sym); + assert_eq!(CodeSpace::from_zero_point(128), CodeSpace::Asym); + assert_eq!(CodeSpace::from_zero_point(-3), CodeSpace::Asym); + } + + /// Presence 0 and value 0 is the only never-touched code under + /// `PresenceZero`; a 9-bit negative and +0 are values. + #[test] + fn never_touched_by_policy() { + assert!(DR512.never_touched(0, false)); + assert!(!DR512.never_touched(5, false), "9-bit -5"); + assert!(!DR512.never_touched(0, true), "+0"); + let tflite = EpiLaneSpec { + width: LaneWidth::Bits8, + nan: NanCode::SymMin, + presence: None, + ..DR512 + }; + assert!(tflite.never_touched(0x80, false)); + assert!(!tflite.never_touched(0, false), "code 0 is a value"); + let plain = EpiLaneSpec { + nan: NanCode::None, + ..tflite + }; + assert!((0..=255u8).all(|v| !plain.never_touched(v, false))); + } + + #[test] + fn presence_bits_are_read_little_endian_past_the_first_byte() { + let mut row = [0u8; 512]; + row[96] = 0b0000_0100; + row[97] = 0b0000_0010; + assert!(DR512.present(&row, 2)); + assert!(DR512.present(&row, 9)); + assert!(!DR512.present(&row, 1)); + assert!(!DR512.present(&row, 8)); + let none = EpiLaneSpec { + width: LaneWidth::Bits8, + nan: NanCode::None, + presence: None, + ..DR512 + }; + assert!(!none.present(&row, 2)); + } +} diff --git a/crates/lance-graph-contract/src/lib.rs b/crates/lance-graph-contract/src/lib.rs index 50fb31184..ee9b459f8 100644 --- a/crates/lance-graph-contract/src/lib.rs +++ b/crates/lance-graph-contract/src/lib.rs @@ -119,6 +119,7 @@ pub mod hotplug; pub mod identity_quad; pub mod jit; pub mod kanban; +pub mod lane_codec; pub mod legacy_outliers; pub mod literal_graph; pub mod mail; From ab7254c28a50016dda6f1f90ab1dfe8ee9ad9c86 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 10:59:19 +0000 Subject: [PATCH 2/4] board: lane layout from ClassView entry Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XAqKMPWTwovjYJEUMuGPb4 --- .../2026-10-28-lane-layout-from-classview.md | 18 ++++++++++++++++++ .claude/board/entries/README.md | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .claude/board/entries/2026-10-28-lane-layout-from-classview.md diff --git a/.claude/board/entries/2026-10-28-lane-layout-from-classview.md b/.claude/board/entries/2026-10-28-lane-layout-from-classview.md new file mode 100644 index 000000000..ebc6b6573 --- /dev/null +++ b/.claude/board/entries/2026-10-28-lane-layout-from-classview.md @@ -0,0 +1,18 @@ +# Lane layout per class: chosen at compile time, resolved through the ClassView + +**Status:** TEST-PINNED. Code: `crates/lance-graph-contract/src/lane_codec.rs`, `ClassView::epi_lanes`, `crates/cognitive-shader-driver/examples/thought_layers_probe.rs` (`write_epi::`). Closes the open point of `2026-10-28-thought-layers-nan-skip.md` (the fixed lab layout). + +## Decision + +- The consumer fixes a class's lane layout at compile time as `EpiLaneClass::SPEC`, built with `checked()`: an invalid layout fails to compile. Fields: width (8 or 9 bits), code space (Sym / Asym), never-touched code (None / PresenceZero / SymMin), value and presence offsets, lane count. +- ONNX `QuantizeLinear` / TFLite annotations pick the code space through `CodeSpace::from_zero_point` (0 = Sym). The never-touched codes mirror `ndarray` `codec8` (`NoNaN`, `NaNAtMin`) and `codec9` (presence 0 and value 0). +- A 9-bit lane is DR512 only: Sym, PresenceZero, with a presence plane, matching `codec9`'s non-configurable contract. +- `ClassView::epi_lanes(class)` names the same constant for a classid. Default `None` = undeclared, and the writer refuses, like `epistemic_reading`. + +## Tests + +Contract: every validation rule refuses, valid layouts pass, presence bits beyond the first byte, never-touched per policy, zero point to code space, a `compile_fail` doctest. Probe: undeclared or different layout refused (nothing stored, no look), NaN not written (DR512 and ONNX uint8), own value kept, 9-bit negative written, computed −0.499 as +0, NaN beside a change, asym code 0 written, TFLite code −128 not written and 0 written, and the contract rule agrees with `codec9` on all 512 codes. Six disables, each red: view check, keep step, presence-bit copy, SymMin code, presence-only test, presence byte offset. + +## Open + +The classid → `ClassView::ClassId` (u16) mapping is the caller's; the probe takes `ClassId` as an argument rather than deriving it from the row key. diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index 454a77a4e..69350c4cb 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -25,11 +25,12 @@ index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately opposite directions; the stranding this convention prevents shows up in exactly one of them, never both. -495 entries, 2026-08-06 .. 2026-10-28. +496 entries, 2026-08-06 .. 2026-10-28. | date | entry id | finding | file | |---|---|---|---| | 2026-10-28 | `thought-layers-nan-skip` | | [2026-10-28-thought-layers-nan-skip.md](2026-10-28-thought-layers-nan-skip.md) | +| 2026-10-28 | `lane-layout-from-classview` | | [2026-10-28-lane-layout-from-classview.md](2026-10-28-lane-layout-from-classview.md) | | 2026-10-28 | `D-SAG-6-1` | | [2026-10-28-d-sag-6-1-audit-reference-ledger.md](2026-10-28-d-sag-6-1-audit-reference-ledger.md) | | 2026-10-28 | `D-DT64-6` | | [2026-10-28-d-dt64-6-routing-bindstore-behavior.md](2026-10-28-d-dt64-6-routing-bindstore-behavior.md) | | 2026-10-28 | `D-DT64-6-1a` | | [2026-10-28-d-dt64-6-ogit-predicates-impl.md](2026-10-28-d-dt64-6-ogit-predicates-impl.md) | From e44ce005193afd40169bb0fe30ba2d33a85e222e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 11:03:18 +0000 Subject: [PATCH 3/4] lane_codec: presence plane mandatory, absent = presence 0 and value 0; bind once The presence plane is not optional: every lane has a presence bit, and a lane is absent when its presence bit is 0 and its value is 0, at 8 and 9 bits alike. NanCode (None, SymMin) is removed and the presence offset is required. A 9-bit lane must be Sym. The probe binds a class to its layout once (bind_lanes checks the ClassView and returns a LaneBinding); writes take the binding and do not look the class up again. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XAqKMPWTwovjYJEUMuGPb4 --- .../examples/thought_layers_probe.rs | 168 ++++++----- crates/lance-graph-contract/src/class_view.rs | 6 +- crates/lance-graph-contract/src/lane_codec.rs | 278 ++++++------------ 3 files changed, 186 insertions(+), 266 deletions(-) diff --git a/crates/cognitive-shader-driver/examples/thought_layers_probe.rs b/crates/cognitive-shader-driver/examples/thought_layers_probe.rs index 4e7508a4c..f8f981d6f 100644 --- a/crates/cognitive-shader-driver/examples/thought_layers_probe.rs +++ b/crates/cognitive-shader-driver/examples/thought_layers_probe.rs @@ -34,6 +34,7 @@ use lance_graph_contract::canonical_node::{EdgeBlock, NodeGuid, NodeRow, TailVar use lance_graph_contract::class_view::{ClassId, ClassView}; use lance_graph_contract::lane_codec::{EpiLaneClass, EpiLaneSpec, LaneWidth}; use ndarray::hpc::codec9::EpiLane9; +use std::marker::PhantomData; /// One thought's writes for [`ThoughtTables::write_parallel`]. pub type ThoughtJob = (ThoughtId, Vec<(AlphaAddr, [u8; 512])>); @@ -190,20 +191,20 @@ pub struct Table { deltas: HashMap, } -/// Whether a lane of `row` was never touched under `spec`. A 9-bit lane is -/// read through `ndarray`'s DR512 codeword, so the probe and the codec share -/// one definition. +/// Whether a lane of `row` is absent (presence 0, value 0) under `spec`. A +/// 9-bit lane is read through `ndarray`'s DR512 codeword, so the probe and the +/// codec share one definition. fn never_touched(spec: &EpiLaneSpec, row: &[u8; 512], lane: usize) -> bool { let (p, m) = (spec.present(row, lane), spec.value(row, lane)); match spec.width { LaneWidth::Bits9 => EpiLane9::from_codeword(u16::from(m) | (u16::from(p) << 8)) .is_some_and(EpiLane9::never_touched), - LaneWidth::Bits8 => spec.never_touched(m, p), + LaneWidth::Bits8 => EpiLaneSpec::absent(m, p), } } -/// Every never-touched lane of `new` takes the lane of `prior`: its value -/// byte and, where the class has one, its presence bit. Returns the lanes kept. +/// Every absent lane of `new` takes the lane of `prior`: its value byte and +/// its presence bit. Returns the lanes kept. fn keep_unknown(spec: &EpiLaneSpec, prior: &[u8; 512], new: &mut [u8; 512]) -> u64 { let mut kept = 0u64; for lane in 0..usize::from(spec.lanes) { @@ -212,15 +213,32 @@ fn keep_unknown(spec: &EpiLaneSpec, prior: &[u8; 512], new: &mut [u8; 512]) -> u kept |= 1 << lane; } } - if let Some(p) = spec.presence { - for lane in (0..usize::from(spec.lanes)).filter(|l| kept >> l & 1 == 1) { - let (byte, bit) = (usize::from(p) + lane / 8, 1u8 << (lane % 8)); - new[byte] = (new[byte] & !bit) | (prior[byte] & bit); - } + for lane in (0..usize::from(spec.lanes)).filter(|l| kept >> l & 1 == 1) { + let (byte, bit) = (usize::from(spec.presence) + lane / 8, 1u8 << (lane % 8)); + new[byte] = (new[byte] & !bit) | (prior[byte] & bit); } kept } +/// A class bound to the lane layout `L`: [`ThoughtTables::bind_lanes`] checked +/// once that the ClassView declares `L::SPEC` for the class. Writes take the +/// binding and do not look the class up again. A binding shared across +/// threads belongs in a `OnceLock` set when the registry loads; `LazyLock` +/// does not fit, because its initializer cannot take the view. +#[derive(Debug)] +pub struct LaneBinding { + class: ClassId, + layout: PhantomData, +} + +impl LaneBinding { + /// The class bound. + #[must_use] + pub fn class(&self) -> ClassId { + self.class + } +} + /// What a write did. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Written { @@ -398,32 +416,41 @@ impl<'a> ThoughtTables<'a> { }) } - /// A sparse write of epistemic lanes laid out as `L` declares. A lane the - /// thought leaves never touched is not written: it keeps what the thought + /// Bind `class` to the lane layout `L`, once. + /// + /// # Errors + /// [`Refusal::LaneLayout`] when `view` declares no layout or another one + /// for `class`. + pub fn bind_lanes( + view: &impl ClassView, + class: ClassId, + ) -> Result, Refusal> { + if view.epi_lanes(class) != Some(L::SPEC) { + return Err(Refusal::LaneLayout); + } + Ok(LaneBinding { + class, + layout: PhantomData, + }) + } + + /// A sparse write of epistemic lanes laid out as `L` declares. An absent + /// lane (presence 0, value 0) is not written: it keeps what the thought /// read there before, so UNKNOWN never overwrites a known value and the /// merge on read returns the earlier value. Every other lane, including a /// 9-bit negative (presence 0, magnitude > 0) and +0, is written as given. /// Bytes outside the lanes are written as by [`write`](Self::write). /// - /// `L` is fixed at compile time; `view` must declare the same layout for - /// `class`, or the write is refused. - /// /// # Errors - /// [`Refusal::LaneLayout`] when `view` declares no layout or another one - /// for `class` (nothing is stored and no look recorded); otherwise as - /// [`write`](Self::write). + /// As [`write`](Self::write). pub fn write_epi( &mut self, - view: &impl ClassView, - class: ClassId, + _binding: &LaneBinding, thought: ThoughtId, addr: AlphaAddr, rung: u8, row: &[u8; 512], ) -> Result { - if view.epi_lanes(class) != Some(L::SPEC) { - return Err(Refusal::LaneLayout); - } let prior = self.read(thought, addr)?; let mut new = *row; keep_unknown(&L::SPEC, &prior, &mut new); @@ -856,7 +883,7 @@ mod tests { // The layout of each class is a compile-time constant (`EpiLaneClass`); // the ClassView names the same constant for the classid. - use lance_graph_contract::lane_codec::{checked, CodeSpace, NanCode}; + use lance_graph_contract::lane_codec::{checked, CodeSpace}; use lance_graph_contract::ontology::{DisplayTemplate, FieldRef}; const VALUES: u16 = 2 * SLOT as u16; @@ -869,9 +896,8 @@ mod tests { const SPEC: EpiLaneSpec = checked(EpiLaneSpec { width: LaneWidth::Bits9, space: CodeSpace::Sym, - nan: NanCode::PresenceZero, values: VALUES, - presence: Some(PRESENCE), + presence: PRESENCE, lanes: 16, }); } @@ -882,22 +908,20 @@ mod tests { const SPEC: EpiLaneSpec = checked(EpiLaneSpec { width: LaneWidth::Bits8, space: CodeSpace::from_zero_point(128), - nan: NanCode::PresenceZero, values: VALUES, - presence: Some(PRESENCE), + presence: PRESENCE, lanes: 16, }); } - /// TFLite narrow symmetric int8 weights, code -128 reserved as NaN. + /// TFLite symmetric int8 weights (zero point 0). struct TfliteSym; impl EpiLaneClass for TfliteSym { const SPEC: EpiLaneSpec = checked(EpiLaneSpec { width: LaneWidth::Bits8, space: CodeSpace::from_zero_point(0), - nan: NanCode::SymMin, values: VALUES, - presence: None, + presence: PRESENCE, lanes: 16, }); } @@ -923,6 +947,10 @@ mod tests { View(Some(L::SPEC)) } + fn bound() -> LaneBinding { + ThoughtTables::bind_lanes::(&view::(), CLASS).expect("declared") + } + /// Base rows whose lanes all hold value 5 + lane with presence 1. fn epi_rows() -> Vec { let (v, p) = (usize::from(VALUES) - 32, usize::from(PRESENCE) - 32); @@ -968,30 +996,25 @@ mod tests { for code in 0u16..512 { let e = EpiLane9::from_codeword(code).unwrap(); assert_eq!( - Dr512::SPEC.never_touched(e.magnitude(), e.presence()), + EpiLaneSpec::absent(e.magnitude(), e.presence()), e.never_touched(), "code {code:#x}" ); } } - /// No declared layout, or a different one, refuses: nothing stored, no - /// look recorded. + /// Binding refuses a class with no declared layout or a different one; + /// the declared one binds once. #[test] - fn an_undeclared_or_different_layout_is_refused() { - let rows = epi_rows(); - let (alloc, th) = one_thought(&rows); - let mut tt = placed(&alloc); - let mut row = row_bytes(&rows[2]); - set_lane(&mut row, 4, true, 99); + fn binding_refuses_an_undeclared_or_different_layout() { for v in [View(None), view::()] { - let r = tt.write_epi::(&v, CLASS, th, rows[2].key, 1, &row); - assert_eq!(r, Err(Refusal::LaneLayout)); + assert!(matches!( + ThoughtTables::bind_lanes::(&v, CLASS), + Err(Refusal::LaneLayout) + )); } - assert_eq!(tt.stored_bytes(), 0); - assert!(!tt.looked(th).unwrap().contains(2), "no look recorded"); - let ok = tt.write_epi::(&view::(), CLASS, th, rows[2].key, 1, &row); - assert!(matches!(ok, Ok(Written::Stored { .. })), "positive control"); + let b = ThoughtTables::bind_lanes::(&view::(), CLASS).unwrap(); + assert_eq!(b.class(), CLASS); } fn nan_over_known() { @@ -1001,7 +1024,7 @@ mod tests { let mut row = row_bytes(&rows[2]); set_lane(&mut row, 4, false, 0); let w = tt - .write_epi::(&view::(), CLASS, th, rows[2].key, 1, &row) + .write_epi(&bound::(), th, rows[2].key, 1, &row) .unwrap(); assert_eq!(w, Written::NoChange); assert_eq!(tt.stored_bytes(), 0); @@ -1026,15 +1049,12 @@ mod tests { let rows = epi_rows(); let (alloc, th) = one_thought(&rows); let mut tt = placed(&alloc); - let v = view::(); + let b = bound::(); let mut row = row_bytes(&rows[1]); set_lane(&mut row, 3, true, 40); - tt.write_epi::(&v, CLASS, th, rows[1].key, 1, &row) - .unwrap(); + tt.write_epi(&b, th, rows[1].key, 1, &row).unwrap(); set_lane(&mut row, 3, false, 0); - let w = tt - .write_epi::(&v, CLASS, th, rows[1].key, 1, &row) - .unwrap(); + let w = tt.write_epi(&b, th, rows[1].key, 1, &row).unwrap(); assert_eq!(w, Written::NoChange); assert_eq!( lane(&tt.read(th, rows[1].key).unwrap(), 3), @@ -1052,7 +1072,7 @@ mod tests { let mut row = row_bytes(&rows[0]); set_lane(&mut row, 6, false, 5); let w = tt - .write_epi::(&view::(), CLASS, th, rows[0].key, 1, &row) + .write_epi(&bound::(), th, rows[0].key, 1, &row) .unwrap(); assert!(matches!(w, Written::Stored { .. })); let (p, m) = lane(&tt.read(th, rows[0].key).unwrap(), 6); @@ -1078,7 +1098,7 @@ mod tests { let mut row = row_bytes(&rows[5]); set_lane(&mut row, 0, code.presence(), code.magnitude()); let w = tt - .write_epi::(&view::(), CLASS, th, rows[5].key, 1, &row) + .write_epi(&bound::(), th, rows[5].key, 1, &row) .unwrap(); assert!( matches!(w, Written::Stored { .. }), @@ -1095,7 +1115,7 @@ mod tests { set_lane(&mut row, 1, false, 0); set_lane(&mut row, 2, true, 99); let w = tt - .write_epi::(&view::(), CLASS, th, rows[4].key, 1, &row) + .write_epi(&bound::(), th, rows[4].key, 1, &row) .unwrap(); assert_eq!(w, Written::Stored { slots: 1 << 2 }, "value slot only"); let read = tt.read(th, rows[4].key).unwrap(); @@ -1120,39 +1140,27 @@ mod tests { let mut row = row_bytes(&rows[3]); set_lane(&mut row, 5, true, 0); let w = tt - .write_epi::(&view::(), CLASS, th, rows[3].key, 1, &row) + .write_epi(&bound::(), th, rows[3].key, 1, &row) .unwrap(); assert!(matches!(w, Written::Stored { .. })); assert_eq!(lane(&tt.read(th, rows[3].key).unwrap(), 5), (true, 0)); } - /// TFLite narrow symmetric: code -128 is not written; code 0 is a value - /// and is. There is no presence plane, so its bytes are never touched. + /// Symmetric int8: absent is presence 0 and value 0 like every layout; + /// code -128 with presence 1 is a value and is written. #[test] - fn a_tflite_min_code_is_not_written_and_zero_is() { + fn a_sym_int8_min_code_is_a_value() { let rows = epi_rows(); let (alloc, th) = one_thought(&rows); let mut tt = placed(&alloc); - let v = view::(); + let b = bound::(); let mut row = row_bytes(&rows[6]); - row[usize::from(VALUES) + 7] = 0x80; - let w = tt - .write_epi::(&v, CLASS, th, rows[6].key, 1, &row) - .unwrap(); - assert_eq!(w, Written::NoChange); - assert_eq!( - tt.read(th, rows[6].key).unwrap()[usize::from(VALUES) + 7], - 12, - "base kept" - ); - row[usize::from(VALUES) + 7] = 0; - let w = tt - .write_epi::(&v, CLASS, th, rows[6].key, 1, &row) - .unwrap(); + set_lane(&mut row, 7, false, 0); + let w = tt.write_epi(&b, th, rows[6].key, 1, &row).unwrap(); + assert_eq!(w, Written::NoChange, "absent: base kept"); + set_lane(&mut row, 7, true, 0x80); + let w = tt.write_epi(&b, th, rows[6].key, 1, &row).unwrap(); assert!(matches!(w, Written::Stored { .. })); - assert_eq!( - tt.read(th, rows[6].key).unwrap()[usize::from(VALUES) + 7], - 0 - ); + assert_eq!(lane(&tt.read(th, rows[6].key).unwrap(), 7), (true, 0x80)); } } diff --git a/crates/lance-graph-contract/src/class_view.rs b/crates/lance-graph-contract/src/class_view.rs index 9d593009f..db5a4c65e 100644 --- a/crates/lance-graph-contract/src/class_view.rs +++ b/crates/lance-graph-contract/src/class_view.rs @@ -1359,13 +1359,13 @@ pub trait ClassView { } /// The epistemic lane layout this class declares - /// ([`lane_codec`](crate::lane_codec)): lane width, code space, which code - /// means never touched, and where the value and presence bytes sit. The + /// ([`lane_codec`](crate::lane_codec)): lane width, code space, and where + /// the value and presence bytes sit (absent = presence 0, value 0). The /// consumer fixes it at compile time as an /// [`EpiLaneClass::SPEC`](crate::lane_codec::EpiLaneClass::SPEC); this /// lookup names that constant for a classid. `None` = undeclared, and a /// writer REFUSES: a lane read under a guessed layout could take a - /// negative 9-bit value for "never touched". Selection only; never changes + /// negative 9-bit value for absent. Selection only; never changes /// stored bytes. #[inline] fn epi_lanes(&self, _class: ClassId) -> Option { diff --git a/crates/lance-graph-contract/src/lane_codec.rs b/crates/lance-graph-contract/src/lane_codec.rs index b211e8c8a..b6083fc79 100644 --- a/crates/lance-graph-contract/src/lane_codec.rs +++ b/crates/lance-graph-contract/src/lane_codec.rs @@ -1,28 +1,26 @@ //! Epistemic lane layout of a class, chosen by the consumer at compile time. //! //! A class that carries quantized values in its row declares, once, how its -//! lanes are stored: their width, the code space, which code means "never -//! touched" (NaN, `$null`, UNKNOWN) and where the value bytes and the presence -//! bits sit. The consumer picks this at compile time, typically from the -//! quantization annotations it already has (ONNX `QuantizeLinear` / -//! TFLite tensor quantization: a zero point of 0 is [`CodeSpace::Sym`], any -//! other zero point is [`CodeSpace::Asym`]), and states it as a constant: +//! lanes are stored: their width, the code space, and where the value bytes +//! and the presence bits sit. The consumer picks this at compile time, +//! typically from the quantization annotations it already has (ONNX +//! `QuantizeLinear` / TFLite tensor quantization: a zero point of 0 is +//! [`CodeSpace::Sym`], any other zero point is [`CodeSpace::Asym`]), and +//! states it as a constant: //! //! ``` //! use lance_graph_contract::lane_codec::{ -//! checked, CodeSpace, EpiLaneClass, EpiLaneSpec, LaneWidth, NanCode, +//! checked, CodeSpace, EpiLaneClass, EpiLaneSpec, LaneWidth, //! }; //! -//! /// A class whose lanes are ONNX uint8 values with zero point 128 and a -//! /// presence plane. +//! /// A class whose lanes are ONNX uint8 values with zero point 128. //! struct SensorReading; //! impl EpiLaneClass for SensorReading { //! const SPEC: EpiLaneSpec = checked(EpiLaneSpec { //! width: LaneWidth::Bits8, //! space: CodeSpace::from_zero_point(128), -//! nan: NanCode::PresenceZero, //! values: 64, -//! presence: Some(96), +//! presence: 96, //! lanes: 16, //! }); //! } @@ -33,7 +31,7 @@ //! //! ```compile_fail,E0080 //! use lance_graph_contract::lane_codec::{ -//! checked, CodeSpace, EpiLaneClass, EpiLaneSpec, LaneWidth, NanCode, +//! checked, CodeSpace, EpiLaneClass, EpiLaneSpec, LaneWidth, //! }; //! struct Bad; //! impl EpiLaneClass for Bad { @@ -41,9 +39,8 @@ //! const SPEC: EpiLaneSpec = checked(EpiLaneSpec { //! width: LaneWidth::Bits9, //! space: CodeSpace::Asym, -//! nan: NanCode::PresenceZero, //! values: 64, -//! presence: Some(96), +//! presence: 96, //! lanes: 16, //! }); //! } @@ -52,28 +49,27 @@ //! //! [`ClassView::epi_lanes`](crate::class_view::ClassView::epi_lanes) names the //! same constant for a class, so a reader holding only a classid can resolve -//! it, and a writer generic over [`EpiLaneClass`] can refuse a row whose class +//! it, and a writer generic over [`EpiLaneClass`] can refuse a class that //! declares a different layout. //! -//! # Never touched +//! # Absent //! -//! - [`NanCode::PresenceZero`]: presence 0 **and** value 0, at 8 and 9 bits -//! alike. At 9 bits the presence bit is also the sign (DR512, `ndarray` -//! `hpc::codec9`), so presence 0 with a nonzero magnitude is a negative -//! value. At 8 bits presence 0 with a nonzero value is a layout mix-up; the -//! width in this spec is what rules it out. -//! - [`NanCode::SymMin`]: the code `-128` (byte `0x80`) of a narrow symmetric -//! 8-bit lane, which never encodes a value (`ndarray` `codec8::NaNAtMin`). -//! - [`NanCode::None`]: every code is a value; nothing is ever skipped. +//! Every lane has a presence bit; the presence plane is not optional. A lane +//! is absent (never touched: NaN, `$null`, UNKNOWN) when its presence bit is 0 +//! **and** its value is 0, at 8 and 9 bits alike. At 9 bits the presence bit +//! is also the sign (DR512, `ndarray` `hpc::codec9`), so presence 0 with a +//! nonzero magnitude is a negative value. At 8 bits presence 0 with a nonzero +//! value cannot arise except by reading a 9-bit lane through an 8-bit layout; +//! the width in this spec is what rules that out. //! -//! A sparse write leaves a never-touched lane unwritten, so it keeps the value -//! read before. This module describes layout only; it stores nothing and adds -//! no bytes to a row. +//! A sparse write leaves an absent lane unwritten, so it keeps the value read +//! before. This module describes layout only; it stores nothing and adds no +//! bytes to a row. /// Bits per lane. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum LaneWidth { - /// One byte per lane. + /// One value byte and one presence bit per lane. Bits8, /// One magnitude byte per lane plus its presence/sign bit (DR512). Bits9, @@ -100,17 +96,6 @@ impl CodeSpace { } } -/// Which stored code means "never touched". -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum NanCode { - /// No code: every stored code is a value. - None, - /// Presence 0 and value 0. - PresenceZero, - /// Byte `0x80` (code `-128`) of a narrow symmetric 8-bit lane. - SymMin, -} - /// Where a class keeps its epistemic lanes, and how they are coded. /// /// Offsets are bytes into the 512-byte row (key, edge block, value slab). @@ -120,11 +105,10 @@ pub enum NanCode { pub struct EpiLaneSpec { pub width: LaneWidth, pub space: CodeSpace, - pub nan: NanCode, /// First value byte; one byte per lane. pub values: u16, - /// First presence byte, if the class has a presence plane. - pub presence: Option, + /// First presence byte. + pub presence: u16, /// Number of lanes, `1..=64`. pub lanes: u8, } @@ -143,16 +127,8 @@ pub enum SpecError { OutOfSlab, /// The value bytes and the presence bytes overlap. Overlap, - /// A 9-bit lane is sign-magnitude: it is symmetric, its never-touched - /// code is presence 0 and value 0, and it needs the presence plane. - NineBitIsDr512, - /// `PresenceZero` without a presence plane. - NoPresencePlane, - /// A presence plane under `None` or `SymMin`, where it would mean nothing. - UnusedPresencePlane, - /// `SymMin` needs an 8-bit symmetric lane: in an asymmetric space code - /// `-128` is a value. - SymMinNeedsSym8, + /// A 9-bit lane is sign-magnitude and therefore symmetric. + NineBitIsSym, } impl EpiLaneSpec { @@ -171,43 +147,28 @@ impl EpiLaneSpec { return Err(SpecError::LaneCount); } let v_end = self.values + self.lanes as u16; - if self.values < VALUE_SLAB_START || v_end > ROW_BYTES { + let p_end = self.presence + self.presence_bytes(); + if self.values < VALUE_SLAB_START + || v_end > ROW_BYTES + || self.presence < VALUE_SLAB_START + || p_end > ROW_BYTES + { return Err(SpecError::OutOfSlab); } - if let Some(p) = self.presence { - let p_end = p + self.presence_bytes(); - if p < VALUE_SLAB_START || p_end > ROW_BYTES { - return Err(SpecError::OutOfSlab); - } - if p < v_end && self.values < p_end { - return Err(SpecError::Overlap); - } + if self.presence < v_end && self.values < p_end { + return Err(SpecError::Overlap); } - match (self.width, self.space, self.nan, self.presence) { - (LaneWidth::Bits9, CodeSpace::Sym, NanCode::PresenceZero, Some(_)) => Ok(()), - (LaneWidth::Bits9, _, _, _) => Err(SpecError::NineBitIsDr512), - (LaneWidth::Bits8, _, NanCode::PresenceZero, None) => Err(SpecError::NoPresencePlane), - (LaneWidth::Bits8, _, NanCode::PresenceZero, Some(_)) => Ok(()), - (LaneWidth::Bits8, _, NanCode::None | NanCode::SymMin, Some(_)) => { - Err(SpecError::UnusedPresencePlane) - } - (LaneWidth::Bits8, CodeSpace::Sym, NanCode::SymMin, None) => Ok(()), - (LaneWidth::Bits8, CodeSpace::Asym, NanCode::SymMin, None) => { - Err(SpecError::SymMinNeedsSym8) - } - (LaneWidth::Bits8, _, NanCode::None, None) => Ok(()), + match (self.width, self.space) { + (LaneWidth::Bits9, CodeSpace::Asym) => Err(SpecError::NineBitIsSym), + _ => Ok(()), } } - /// Whether a lane holding `value` with presence bit `present` was never - /// touched. `present` is ignored when the class has no presence plane. + /// Whether a lane holding `value` with presence bit `present` is absent: + /// presence 0 and value 0. #[must_use] - pub const fn never_touched(&self, value: u8, present: bool) -> bool { - match self.nan { - NanCode::None => false, - NanCode::PresenceZero => !present && value == 0, - NanCode::SymMin => value == 0x80, - } + pub const fn absent(value: u8, present: bool) -> bool { + !present && value == 0 } /// Lane `lane`'s value byte in `row`. @@ -216,11 +177,10 @@ impl EpiLaneSpec { row[self.values as usize + lane] } - /// Lane `lane`'s presence bit in `row`; `false` without a presence plane. + /// Lane `lane`'s presence bit in `row`. #[must_use] pub fn present(&self, row: &[u8], lane: usize) -> bool { - self.presence - .is_some_and(|p| (row[p as usize + lane / 8] >> (lane % 8)) & 1 == 1) + (row[self.presence as usize + lane / 8] >> (lane % 8)) & 1 == 1 } } @@ -233,16 +193,7 @@ pub const fn checked(spec: EpiLaneSpec) -> EpiLaneSpec { Err(SpecError::LaneCount) => panic!("EpiLaneSpec: lanes must be 1..=64"), Err(SpecError::OutOfSlab) => panic!("EpiLaneSpec: lanes must lie in the value slab"), Err(SpecError::Overlap) => panic!("EpiLaneSpec: value and presence bytes overlap"), - Err(SpecError::NineBitIsDr512) => { - panic!("EpiLaneSpec: a 9-bit lane is Sym + PresenceZero with a presence plane") - } - Err(SpecError::NoPresencePlane) => { - panic!("EpiLaneSpec: PresenceZero needs a presence plane") - } - Err(SpecError::UnusedPresencePlane) => { - panic!("EpiLaneSpec: a presence plane needs NanCode::PresenceZero") - } - Err(SpecError::SymMinNeedsSym8) => panic!("EpiLaneSpec: SymMin needs an 8-bit Sym lane"), + Err(SpecError::NineBitIsSym) => panic!("EpiLaneSpec: a 9-bit lane is Sym"), } } @@ -259,36 +210,22 @@ mod tests { const DR512: EpiLaneSpec = EpiLaneSpec { width: LaneWidth::Bits9, space: CodeSpace::Sym, - nan: NanCode::PresenceZero, values: 64, - presence: Some(96), + presence: 96, lanes: 16, }; #[test] fn valid_layouts_pass() { assert_eq!(DR512.validate(), Ok(())); - let u8_asym = EpiLaneSpec { - width: LaneWidth::Bits8, - space: CodeSpace::Asym, - ..DR512 - }; - assert_eq!(u8_asym.validate(), Ok(())); - let tflite = EpiLaneSpec { - width: LaneWidth::Bits8, - nan: NanCode::SymMin, - presence: None, - ..DR512 - }; - assert_eq!(tflite.validate(), Ok(())); - let plain = EpiLaneSpec { - width: LaneWidth::Bits8, - space: CodeSpace::Asym, - nan: NanCode::None, - presence: None, - ..DR512 - }; - assert_eq!(plain.validate(), Ok(())); + for space in [CodeSpace::Sym, CodeSpace::Asym] { + let b8 = EpiLaneSpec { + width: LaneWidth::Bits8, + space, + ..DR512 + }; + assert_eq!(b8.validate(), Ok(())); + } } #[test] @@ -312,72 +249,60 @@ mod tests { ); assert_eq!( e(EpiLaneSpec { - presence: Some(511), + presence: 16, ..DR512 }), SpecError::OutOfSlab ); assert_eq!( e(EpiLaneSpec { - presence: Some(70), + presence: 511, ..DR512 }), - SpecError::Overlap + SpecError::OutOfSlab ); assert_eq!( e(EpiLaneSpec { - space: CodeSpace::Asym, + presence: 70, ..DR512 }), - SpecError::NineBitIsDr512 + SpecError::Overlap ); assert_eq!( e(EpiLaneSpec { - presence: None, + presence: 63, ..DR512 }), - SpecError::NineBitIsDr512 + SpecError::Overlap ); assert_eq!( e(EpiLaneSpec { - nan: NanCode::SymMin, + space: CodeSpace::Asym, ..DR512 }), - SpecError::NineBitIsDr512 - ); - let b8 = EpiLaneSpec { - width: LaneWidth::Bits8, - ..DR512 - }; - assert_eq!( - e(EpiLaneSpec { - presence: None, - ..b8 - }), - SpecError::NoPresencePlane - ); - assert_eq!( - e(EpiLaneSpec { - nan: NanCode::None, - ..b8 - }), - SpecError::UnusedPresencePlane + SpecError::NineBitIsSym ); + } + + /// Adjacent regions do not overlap: presence ending where the values + /// start, and presence starting where the values end, both pass. + #[test] + fn adjacent_regions_pass() { assert_eq!( - e(EpiLaneSpec { - nan: NanCode::SymMin, - ..b8 - }), - SpecError::UnusedPresencePlane + EpiLaneSpec { + presence: 62, + ..DR512 + } + .validate(), + Ok(()) ); assert_eq!( - e(EpiLaneSpec { - nan: NanCode::SymMin, - space: CodeSpace::Asym, - presence: None, - ..b8 - }), - SpecError::SymMinNeedsSym8 + EpiLaneSpec { + presence: 80, + ..DR512 + } + .validate(), + Ok(()) ); } @@ -395,26 +320,20 @@ mod tests { assert_eq!(CodeSpace::from_zero_point(-3), CodeSpace::Asym); } - /// Presence 0 and value 0 is the only never-touched code under - /// `PresenceZero`; a 9-bit negative and +0 are values. + /// Presence 0 and value 0 is the only absent code; a 9-bit negative + /// (presence 0, value > 0) and +0 (presence 1, value 0) are values. #[test] - fn never_touched_by_policy() { - assert!(DR512.never_touched(0, false)); - assert!(!DR512.never_touched(5, false), "9-bit -5"); - assert!(!DR512.never_touched(0, true), "+0"); - let tflite = EpiLaneSpec { - width: LaneWidth::Bits8, - nan: NanCode::SymMin, - presence: None, - ..DR512 - }; - assert!(tflite.never_touched(0x80, false)); - assert!(!tflite.never_touched(0, false), "code 0 is a value"); - let plain = EpiLaneSpec { - nan: NanCode::None, - ..tflite - }; - assert!((0..=255u8).all(|v| !plain.never_touched(v, false))); + fn absent_is_presence_zero_and_value_zero() { + assert!(EpiLaneSpec::absent(0, false)); + assert!(!EpiLaneSpec::absent(5, false), "9-bit -5"); + assert!(!EpiLaneSpec::absent(0, true), "+0"); + assert_eq!( + (0..=255u8) + .flat_map(|v| [(v, false), (v, true)]) + .filter(|&(v, p)| EpiLaneSpec::absent(v, p)) + .count(), + 1 + ); } #[test] @@ -426,12 +345,5 @@ mod tests { assert!(DR512.present(&row, 9)); assert!(!DR512.present(&row, 1)); assert!(!DR512.present(&row, 8)); - let none = EpiLaneSpec { - width: LaneWidth::Bits8, - nan: NanCode::None, - presence: None, - ..DR512 - }; - assert!(!none.present(&row, 2)); } } From c393f651fbba69cfc29eb41acccd5cb92e9f1b8a Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 11:05:55 +0000 Subject: [PATCH 4/4] board: lane layout entry, presence mandatory and bind once Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XAqKMPWTwovjYJEUMuGPb4 --- .../2026-10-28-lane-layout-from-classview.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.claude/board/entries/2026-10-28-lane-layout-from-classview.md b/.claude/board/entries/2026-10-28-lane-layout-from-classview.md index ebc6b6573..11887f94b 100644 --- a/.claude/board/entries/2026-10-28-lane-layout-from-classview.md +++ b/.claude/board/entries/2026-10-28-lane-layout-from-classview.md @@ -1,17 +1,18 @@ -# Lane layout per class: chosen at compile time, resolved through the ClassView +# Lane layout per class: chosen at compile time, resolved once through the ClassView -**Status:** TEST-PINNED. Code: `crates/lance-graph-contract/src/lane_codec.rs`, `ClassView::epi_lanes`, `crates/cognitive-shader-driver/examples/thought_layers_probe.rs` (`write_epi::`). Closes the open point of `2026-10-28-thought-layers-nan-skip.md` (the fixed lab layout). +**Status:** TEST-PINNED. Code: `crates/lance-graph-contract/src/lane_codec.rs`, `ClassView::epi_lanes`, `crates/cognitive-shader-driver/examples/thought_layers_probe.rs` (`bind_lanes::`, `write_epi`). Closes the open point of `2026-10-28-thought-layers-nan-skip.md` (the fixed lab layout). ## Decision -- The consumer fixes a class's lane layout at compile time as `EpiLaneClass::SPEC`, built with `checked()`: an invalid layout fails to compile. Fields: width (8 or 9 bits), code space (Sym / Asym), never-touched code (None / PresenceZero / SymMin), value and presence offsets, lane count. -- ONNX `QuantizeLinear` / TFLite annotations pick the code space through `CodeSpace::from_zero_point` (0 = Sym). The never-touched codes mirror `ndarray` `codec8` (`NoNaN`, `NaNAtMin`) and `codec9` (presence 0 and value 0). -- A 9-bit lane is DR512 only: Sym, PresenceZero, with a presence plane, matching `codec9`'s non-configurable contract. -- `ClassView::epi_lanes(class)` names the same constant for a classid. Default `None` = undeclared, and the writer refuses, like `epistemic_reading`. +- The consumer fixes a class's lane layout at compile time as `EpiLaneClass::SPEC`, built with `checked()`: an invalid layout fails to compile. Fields: width (8 or 9 bits), code space (Sym / Asym), value offset, presence offset, lane count. +- The presence plane is mandatory. Absent (NaN, `$null`, UNKNOWN) is always presence 0 and value 0, at 8 and 9 bits alike. At 9 bits the presence bit is also the sign, so presence 0 with a nonzero magnitude is a negative value. A 9-bit lane must be Sym. +- ONNX `QuantizeLinear` / TFLite annotations pick the code space through `CodeSpace::from_zero_point` (0 = Sym). +- `ClassView::epi_lanes(class)` names the same constant for a classid. Default `None` = undeclared, and binding refuses, like `epistemic_reading`. +- A class is bound once (`bind_lanes::` returns a `LaneBinding`); writes take the binding and do not look the class up again. A binding shared across threads belongs in a `OnceLock` set when the registry loads; `LazyLock` does not fit, because its initializer cannot take the view. ## Tests -Contract: every validation rule refuses, valid layouts pass, presence bits beyond the first byte, never-touched per policy, zero point to code space, a `compile_fail` doctest. Probe: undeclared or different layout refused (nothing stored, no look), NaN not written (DR512 and ONNX uint8), own value kept, 9-bit negative written, computed −0.499 as +0, NaN beside a change, asym code 0 written, TFLite code −128 not written and 0 written, and the contract rule agrees with `codec9` on all 512 codes. Six disables, each red: view check, keep step, presence-bit copy, SymMin code, presence-only test, presence byte offset. +Contract: every validation rule refuses, adjacent regions pass, valid layouts pass, absent is exactly one of the 512 (value, presence) pairs, presence bits beyond the first byte, zero point to code space, a `compile_fail` doctest. Probe: binding refuses an undeclared or different layout; absent not written (DR512 and ONNX uint8); own value kept; 9-bit negative written; computed −0.499 written as +0; absent beside a change; asym code 0 written; sym int8 code −128 with presence 1 is a value; the contract rule agrees with `codec9` on all 512 codes. Eight disables, each red: bind check, keep step, presence-bit copy, presence-only test, value-only test, presence byte offset, overlap check, 9-bit Asym. ## Open