ruvector_sparse_inference/precision/
lanes.rs

1//! Precision Lane definitions and configuration
2//!
3//! Defines the three precision lanes (3/5/7-bit) that map to intelligence roles.
4
5use serde::{Deserialize, Serialize};
6
7/// Precision lanes for layered quantization
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub enum PrecisionLane {
10    /// 3-bit lane: Reflex signals, gating, boundaries, health metrics
11    /// Uses signed int4 container restricted to 3-bit domain
12    /// LUT activation for speed
13    Bit3,
14
15    /// 5-bit lane: Streaming embeddings, semantic motion, drift detection
16    /// Uses signed int8 container with values in -16..15
17    /// Per-channel or per-block scale
18    Bit5,
19
20    /// 7-bit lane: Reasoning, synthesis, memory writes, micro-LoRA
21    /// Uses signed int8 container with values in -64..63
22    /// Stable accumulators, close to int8 quality
23    Bit7,
24
25    /// Float lane: Training, calibration, aggregation boundaries only
26    Float32,
27}
28
29impl PrecisionLane {
30    /// Get the number of bits for this lane
31    pub fn bits(&self) -> u8 {
32        match self {
33            Self::Bit3 => 3,
34            Self::Bit5 => 5,
35            Self::Bit7 => 7,
36            Self::Float32 => 32,
37        }
38    }
39
40    /// Get the value range for this lane
41    pub fn value_range(&self) -> (i32, i32) {
42        match self {
43            Self::Bit3 => (-4, 3),      // 3-bit signed: -4 to 3
44            Self::Bit5 => (-16, 15),    // 5-bit signed: -16 to 15
45            Self::Bit7 => (-64, 63),    // 7-bit signed: -64 to 63
46            Self::Float32 => (i32::MIN, i32::MAX),
47        }
48    }
49
50    /// Get bytes per element (storage container)
51    pub fn bytes_per_element(&self) -> f32 {
52        match self {
53            Self::Bit3 => 0.5,   // Packed into int4
54            Self::Bit5 => 1.0,   // int8 container
55            Self::Bit7 => 1.0,   // int8 container
56            Self::Float32 => 4.0,
57        }
58    }
59
60    /// Get the default scale factor for this lane
61    pub fn default_scale(&self) -> f32 {
62        match self {
63            Self::Bit3 => 0.25,   // Conservative for reflexes
64            Self::Bit5 => 0.0625, // 1/16 for streaming
65            Self::Bit7 => 0.015625, // 1/64 for reasoning
66            Self::Float32 => 1.0,
67        }
68    }
69
70    /// Check if this lane supports memory writes
71    pub fn allows_memory_writes(&self) -> bool {
72        matches!(self, Self::Bit7 | Self::Float32)
73    }
74
75    /// Check if this lane is event-driven vs continuous
76    pub fn is_event_driven(&self) -> bool {
77        matches!(self, Self::Bit5 | Self::Bit7)
78    }
79}
80
81impl Default for PrecisionLane {
82    fn default() -> Self {
83        Self::Bit7  // Default to reasoning lane
84    }
85}
86
87/// Configuration for precision lane behavior
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct LaneConfig {
90    /// Default lane for new operations
91    pub default_lane: PrecisionLane,
92
93    /// Time budget per tick for 3-bit lane (microseconds)
94    pub bit3_tick_budget_us: u64,
95
96    /// Maximum consecutive 5-bit updates before forced graduation check
97    pub bit5_max_updates: usize,
98
99    /// Minimum stability steps before demotion
100    pub min_stability_steps: usize,
101
102    /// Novelty threshold for escalation (0.0 to 1.0)
103    pub novelty_threshold: f32,
104
105    /// Drift persistence threshold (steps)
106    pub drift_persistence_threshold: usize,
107
108    /// Confidence threshold for graduation (0.0 to 1.0)
109    pub confidence_threshold: f32,
110
111    /// Cost budget for escalation (arbitrary units)
112    pub escalation_budget: f32,
113
114    /// Enable automatic lane selection
115    pub auto_lane_selection: bool,
116}
117
118impl Default for LaneConfig {
119    fn default() -> Self {
120        Self {
121            default_lane: PrecisionLane::Bit5, // Start at streaming lane
122            bit3_tick_budget_us: 100,          // 100μs per tick for reflexes
123            bit5_max_updates: 10,              // Check graduation every 10 updates
124            min_stability_steps: 5,            // 5 stable steps before demotion
125            novelty_threshold: 0.3,            // 30% novelty triggers escalation
126            drift_persistence_threshold: 3,   // 3 steps of drift
127            confidence_threshold: 0.7,        // 70% confidence required
128            escalation_budget: 1.0,           // Normalized budget
129            auto_lane_selection: true,
130        }
131    }
132}
133
134/// Hardware target for lane optimization
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
136pub enum HardwareTarget {
137    /// ESP32: 3-bit only, tiny models
138    Esp32,
139    /// V0 Appliance: 5-bit streaming + 7-bit reasoning
140    V0Appliance,
141    /// Desktop/Server: Full lane support
142    Desktop,
143    /// FPGA: Deterministic 7-bit with witness logging
144    Fpga,
145}
146
147impl HardwareTarget {
148    /// Get supported lanes for this hardware
149    pub fn supported_lanes(&self) -> Vec<PrecisionLane> {
150        match self {
151            Self::Esp32 => vec![PrecisionLane::Bit3],
152            Self::V0Appliance => vec![PrecisionLane::Bit3, PrecisionLane::Bit5, PrecisionLane::Bit7],
153            Self::Desktop => vec![PrecisionLane::Bit3, PrecisionLane::Bit5, PrecisionLane::Bit7, PrecisionLane::Float32],
154            Self::Fpga => vec![PrecisionLane::Bit7],
155        }
156    }
157
158    /// Get the default lane for this hardware
159    pub fn default_lane(&self) -> PrecisionLane {
160        match self {
161            Self::Esp32 => PrecisionLane::Bit3,
162            Self::V0Appliance => PrecisionLane::Bit5,
163            Self::Desktop => PrecisionLane::Bit7,
164            Self::Fpga => PrecisionLane::Bit7,
165        }
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172
173    #[test]
174    fn test_lane_bits() {
175        assert_eq!(PrecisionLane::Bit3.bits(), 3);
176        assert_eq!(PrecisionLane::Bit5.bits(), 5);
177        assert_eq!(PrecisionLane::Bit7.bits(), 7);
178        assert_eq!(PrecisionLane::Float32.bits(), 32);
179    }
180
181    #[test]
182    fn test_lane_ranges() {
183        assert_eq!(PrecisionLane::Bit3.value_range(), (-4, 3));
184        assert_eq!(PrecisionLane::Bit5.value_range(), (-16, 15));
185        assert_eq!(PrecisionLane::Bit7.value_range(), (-64, 63));
186    }
187
188    #[test]
189    fn test_memory_write_permission() {
190        assert!(!PrecisionLane::Bit3.allows_memory_writes());
191        assert!(!PrecisionLane::Bit5.allows_memory_writes());
192        assert!(PrecisionLane::Bit7.allows_memory_writes());
193        assert!(PrecisionLane::Float32.allows_memory_writes());
194    }
195
196    #[test]
197    fn test_hardware_targets() {
198        assert_eq!(HardwareTarget::Esp32.supported_lanes(), vec![PrecisionLane::Bit3]);
199        assert!(HardwareTarget::Desktop.supported_lanes().contains(&PrecisionLane::Float32));
200    }
201}