Files
wifi-densepose/vendor/ruvector/crates/ruQu/src/schema.rs

556 lines
16 KiB
Rust

//! Data Model and Schema for ruQu
//!
//! Defines the core data types and a versioned binary log format.
//!
//! ## Binary Format
//!
//! The log format is designed for speed and compactness:
//! - 4-byte magic header: "RUQU"
//! - 1-byte version
//! - Sequence of variable-length records
//!
//! Each record:
//! - 1-byte record type
//! - 4-byte length (little-endian)
//! - Payload bytes
//! - 4-byte CRC32 checksum
use serde::{Deserialize, Serialize};
use std::io::{Read, Write};
/// Current schema version
pub const SCHEMA_VERSION: u8 = 1;
/// Magic header for binary logs
pub const LOG_MAGIC: &[u8; 4] = b"RUQU";
// ============================================================================
// CORE DATA TYPES
// ============================================================================
/// A single syndrome measurement round
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SyndromeRound {
/// Round number (monotonically increasing)
pub round_id: u64,
/// Timestamp in nanoseconds since epoch
pub timestamp_ns: u64,
/// Code distance
pub code_distance: u8,
/// Detector events in this round
pub events: Vec<DetectorEvent>,
/// Optional metadata
#[serde(default)]
pub metadata: RoundMetadata,
}
impl SyndromeRound {
/// Create a new syndrome round
pub fn new(round_id: u64, code_distance: u8) -> Self {
Self {
round_id,
timestamp_ns: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0),
code_distance,
events: Vec::new(),
metadata: RoundMetadata::default(),
}
}
/// Add a detector event
pub fn add_event(&mut self, event: DetectorEvent) {
self.events.push(event);
}
/// Get the number of fired detectors
pub fn fired_count(&self) -> usize {
self.events.iter().filter(|e| e.fired).count()
}
}
/// A detector event within a syndrome round
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DetectorEvent {
/// Detector index
pub detector_id: u32,
/// Whether the detector fired (syndrome bit = 1)
pub fired: bool,
/// Measurement confidence (0.0 to 1.0)
#[serde(default = "default_confidence")]
pub confidence: f32,
/// Spatial coordinates (if known)
#[serde(default)]
pub coords: Option<DetectorCoords>,
}
fn default_confidence() -> f32 {
1.0
}
/// Spatial coordinates of a detector
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct DetectorCoords {
/// X coordinate (column)
pub x: i16,
/// Y coordinate (row)
pub y: i16,
/// Time slice (for 3D codes)
pub t: i16,
}
/// Round metadata
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct RoundMetadata {
/// Source identifier
#[serde(default)]
pub source: String,
/// Error rate at this round (if known)
#[serde(default)]
pub error_rate: Option<f64>,
/// Whether this round is from a hardware run
#[serde(default)]
pub is_hardware: bool,
/// Injected fault (if any)
#[serde(default)]
pub injected_fault: Option<String>,
}
/// Boundary identifier for surface codes
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum BoundaryId {
/// Left boundary (X logical)
Left,
/// Right boundary (X logical)
Right,
/// Top boundary (Z logical)
Top,
/// Bottom boundary (Z logical)
Bottom,
/// Virtual boundary (for matching)
Virtual,
/// Custom boundary with ID
Custom(u32),
}
/// A permit token issued by the gate
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PermitToken {
/// Unique token ID
pub token_id: u64,
/// Round at which permit was issued
pub issued_at_round: u64,
/// Timestamp when issued (ns since epoch)
pub issued_at_ns: u64,
/// Time-to-live in nanoseconds
pub ttl_ns: u64,
/// Permitted regions (bitmask)
pub region_mask: u64,
/// Confidence level
pub confidence: f32,
/// Min-cut value at issuance
pub min_cut_value: f32,
}
impl PermitToken {
/// Check if the token is still valid
pub fn is_valid(&self, current_time_ns: u64) -> bool {
current_time_ns < self.issued_at_ns.saturating_add(self.ttl_ns)
}
/// Remaining time-to-live in nanoseconds
pub fn remaining_ttl_ns(&self, current_time_ns: u64) -> u64 {
self.issued_at_ns
.saturating_add(self.ttl_ns)
.saturating_sub(current_time_ns)
}
}
/// A gate decision record
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct GateDecision {
/// Round ID when decision was made
pub round_id: u64,
/// Timestamp of decision (ns since epoch)
pub timestamp_ns: u64,
/// Decision type
pub decision: DecisionType,
/// Processing latency in nanoseconds
pub latency_ns: u64,
/// Input metrics
pub metrics: GateMetrics,
}
/// Decision type
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DecisionType {
/// Operation permitted with token
Permit(PermitToken),
/// Operation deferred
Defer {
/// Wait time in nanoseconds
wait_ns: u64,
/// Uncertainty level
uncertainty: f32,
},
/// Operation denied
Deny {
/// Risk level (0-1)
risk_level: f32,
/// Affected region bitmask
affected_regions: u64,
},
}
/// Metrics used for gate decision
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct GateMetrics {
/// Min-cut value
pub min_cut: f32,
/// Cut value standard deviation
pub cut_std: f32,
/// Shift from baseline
pub shift: f32,
/// Evidence accumulation
pub evidence: f32,
/// Number of fired detectors
pub fired_count: u32,
/// Clustering score
pub clustering: f32,
}
/// A mitigation action taken
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MitigationAction {
/// Action ID
pub action_id: u64,
/// Timestamp when action was initiated
pub timestamp_ns: u64,
/// Action type
pub action_type: ActionTypeSchema,
/// Target regions
pub target_regions: Vec<u32>,
/// Duration in nanoseconds
pub duration_ns: u64,
/// Result of the action
pub result: ActionResult,
}
/// Action types in schema format
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum ActionTypeSchema {
/// Quarantine a region to prevent error propagation
QuarantineRegion,
/// Increase syndrome measurement rounds for higher fidelity
IncreaseSyndromeRounds,
/// Switch decoder mode (e.g., from fast to accurate)
SwitchDecodeMode,
/// Trigger re-weighting of decoder graph
TriggerReweight,
/// Pause learning/write operations during instability
PauseLearningWrites,
/// Log event for audit trail
LogEvent,
/// Alert human operator
AlertOperator,
}
/// Result of a mitigation action
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ActionResult {
/// Action completed successfully
Success,
/// Action partially completed
Partial {
/// Fraction completed (0.0 to 1.0)
completed: f32,
},
/// Action failed
Failed {
/// Reason for failure
reason: String,
},
/// Action is pending execution
Pending,
}
// ============================================================================
// BINARY LOG FORMAT
// ============================================================================
/// Record types for binary log
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum RecordType {
/// Syndrome round record
SyndromeRound = 1,
/// Gate decision record
GateDecision = 2,
/// Mitigation action record
MitigationAction = 3,
/// Checkpoint for log recovery
Checkpoint = 4,
/// Configuration snapshot
Config = 5,
/// Metrics snapshot
Metrics = 6,
}
impl TryFrom<u8> for RecordType {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(RecordType::SyndromeRound),
2 => Ok(RecordType::GateDecision),
3 => Ok(RecordType::MitigationAction),
4 => Ok(RecordType::Checkpoint),
5 => Ok(RecordType::Config),
6 => Ok(RecordType::Metrics),
_ => Err(()),
}
}
}
/// Binary log writer
pub struct LogWriter<W: Write> {
writer: W,
record_count: u64,
}
impl<W: Write> LogWriter<W> {
/// Create a new log writer
pub fn new(mut writer: W) -> std::io::Result<Self> {
// Write header
writer.write_all(LOG_MAGIC)?;
writer.write_all(&[SCHEMA_VERSION])?;
Ok(Self {
writer,
record_count: 0,
})
}
/// Write a syndrome round
pub fn write_syndrome(&mut self, round: &SyndromeRound) -> std::io::Result<()> {
let payload = serde_json::to_vec(round)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
self.write_record(RecordType::SyndromeRound, &payload)
}
/// Write a gate decision
pub fn write_decision(&mut self, decision: &GateDecision) -> std::io::Result<()> {
let payload = serde_json::to_vec(decision)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
self.write_record(RecordType::GateDecision, &payload)
}
/// Write a mitigation action
pub fn write_action(&mut self, action: &MitigationAction) -> std::io::Result<()> {
let payload = serde_json::to_vec(action)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
self.write_record(RecordType::MitigationAction, &payload)
}
fn write_record(&mut self, record_type: RecordType, payload: &[u8]) -> std::io::Result<()> {
// Record type (1 byte)
self.writer.write_all(&[record_type as u8])?;
// Length (4 bytes, little-endian)
let len = payload.len() as u32;
self.writer.write_all(&len.to_le_bytes())?;
// Payload
self.writer.write_all(payload)?;
// CRC32 checksum
let crc = crc32fast::hash(payload);
self.writer.write_all(&crc.to_le_bytes())?;
self.record_count += 1;
Ok(())
}
/// Flush and get record count
pub fn finish(mut self) -> std::io::Result<u64> {
self.writer.flush()?;
Ok(self.record_count)
}
}
/// Binary log reader
pub struct LogReader<R: Read> {
reader: R,
version: u8,
}
impl<R: Read> LogReader<R> {
/// Open a log for reading
pub fn new(mut reader: R) -> std::io::Result<Self> {
// Read and verify header
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
if &magic != LOG_MAGIC {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Invalid magic header",
));
}
let mut version = [0u8; 1];
reader.read_exact(&mut version)?;
Ok(Self {
reader,
version: version[0],
})
}
/// Get schema version
pub fn version(&self) -> u8 {
self.version
}
/// Read next record
pub fn read_record(&mut self) -> std::io::Result<Option<LogRecord>> {
// Read record type
let mut type_byte = [0u8; 1];
match self.reader.read_exact(&mut type_byte) {
Ok(()) => (),
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(None),
Err(e) => return Err(e),
}
let record_type = RecordType::try_from(type_byte[0]).map_err(|_| {
std::io::Error::new(std::io::ErrorKind::InvalidData, "Unknown record type")
})?;
// Read length
let mut len_bytes = [0u8; 4];
self.reader.read_exact(&mut len_bytes)?;
let len = u32::from_le_bytes(len_bytes) as usize;
// Read payload
let mut payload = vec![0u8; len];
self.reader.read_exact(&mut payload)?;
// Read and verify checksum
let mut crc_bytes = [0u8; 4];
self.reader.read_exact(&mut crc_bytes)?;
let stored_crc = u32::from_le_bytes(crc_bytes);
let computed_crc = crc32fast::hash(&payload);
if stored_crc != computed_crc {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"CRC mismatch",
));
}
// Parse payload
let record = match record_type {
RecordType::SyndromeRound => {
let round: SyndromeRound = serde_json::from_slice(&payload)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
LogRecord::Syndrome(round)
}
RecordType::GateDecision => {
let decision: GateDecision = serde_json::from_slice(&payload)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
LogRecord::Decision(decision)
}
RecordType::MitigationAction => {
let action: MitigationAction = serde_json::from_slice(&payload)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
LogRecord::Action(action)
}
_ => LogRecord::Unknown(payload),
};
Ok(Some(record))
}
}
/// A record from the log
#[derive(Debug, Clone)]
pub enum LogRecord {
/// Syndrome round record
Syndrome(SyndromeRound),
/// Gate decision record
Decision(GateDecision),
/// Mitigation action record
Action(MitigationAction),
/// Unknown record type (for forward compatibility)
Unknown(Vec<u8>),
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_syndrome_round() {
let mut round = SyndromeRound::new(1, 5);
round.add_event(DetectorEvent {
detector_id: 0,
fired: true,
confidence: 0.99,
coords: Some(DetectorCoords { x: 0, y: 0, t: 0 }),
});
round.add_event(DetectorEvent {
detector_id: 1,
fired: false,
confidence: 1.0,
coords: None,
});
assert_eq!(round.fired_count(), 1);
}
#[test]
fn test_permit_token_validity() {
let token = PermitToken {
token_id: 1,
issued_at_round: 100,
issued_at_ns: 1000000,
ttl_ns: 100000,
region_mask: 0xFF,
confidence: 0.95,
min_cut_value: 5.5,
};
assert!(token.is_valid(1050000));
assert!(!token.is_valid(1200000));
assert_eq!(token.remaining_ttl_ns(1050000), 50000);
}
#[test]
fn test_log_roundtrip() {
let mut buffer = Vec::new();
// Write
{
let mut writer = LogWriter::new(&mut buffer).unwrap();
let round = SyndromeRound::new(1, 5);
writer.write_syndrome(&round).unwrap();
writer.finish().unwrap();
}
// Read
{
let mut reader = LogReader::new(Cursor::new(&buffer)).unwrap();
assert_eq!(reader.version(), SCHEMA_VERSION);
let record = reader.read_record().unwrap().unwrap();
match record {
LogRecord::Syndrome(round) => {
assert_eq!(round.round_id, 1);
assert_eq!(round.code_distance, 5);
}
_ => panic!("Expected syndrome record"),
}
}
}
}