ruvector_sparse_inference/pi/
constants.rs

1//! π-derived calibration constants for low-precision systems
2//!
3//! Using π (or π-derived constants) for normalization, angular embeddings,
4//! periodic projections, and phase encoding gives a stable, universal reference
5//! that doesn't align with powers of two or quantization boundaries.
6//!
7//! This avoids resonance artifacts where values collapse into repeating buckets.
8//! In short: **π breaks symmetry**.
9
10use crate::precision::PrecisionLane;
11use std::f32::consts::PI;
12
13/// π-based scale factor for 3-bit quantization
14/// Chosen to avoid power-of-2 boundaries
15pub const PI_SCALE_3BIT: f32 = PI / 4.0;  // ~0.785
16
17/// π-based scale factor for 5-bit quantization
18pub const PI_SCALE_5BIT: f32 = PI / 16.0; // ~0.196
19
20/// π-based scale factor for 7-bit quantization
21pub const PI_SCALE_7BIT: f32 = PI / 64.0; // ~0.049
22
23/// Golden ratio derived from π for optimal distribution
24pub const PHI_APPROX: f32 = 2.0 / (PI - 1.0); // ~0.934
25
26/// First 100 digits of π for deterministic seeding
27pub const PI_DIGITS: [u8; 100] = [
28    3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4,
29    6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7,
30    1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4,
31    4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4, 0, 6, 2, 8, 6, 2, 0, 8, 9,
32    9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7,
33];
34
35/// π-derived calibration constants for a precision lane
36#[derive(Debug, Clone, Copy)]
37pub struct PiCalibration {
38    /// Base scale factor (π / 2^bits)
39    pub scale: f32,
40    /// Phase offset for angular encoding
41    pub phase_offset: f32,
42    /// Normalization factor
43    pub norm_factor: f32,
44    /// Precision lane
45    pub lane: PrecisionLane,
46    /// Anti-resonance offset (prevents bucket collapse)
47    pub anti_resonance: f32,
48}
49
50impl PiCalibration {
51    /// Create calibration constants for a precision lane
52    pub fn for_lane(lane: PrecisionLane) -> Self {
53        match lane {
54            PrecisionLane::Bit3 => Self {
55                scale: PI_SCALE_3BIT,
56                phase_offset: PI / 8.0,
57                norm_factor: 3.0 / PI,
58                lane,
59                anti_resonance: Self::compute_anti_resonance(3),
60            },
61            PrecisionLane::Bit5 => Self {
62                scale: PI_SCALE_5BIT,
63                phase_offset: PI / 32.0,
64                norm_factor: 15.0 / PI,
65                lane,
66                anti_resonance: Self::compute_anti_resonance(5),
67            },
68            PrecisionLane::Bit7 => Self {
69                scale: PI_SCALE_7BIT,
70                phase_offset: PI / 128.0,
71                norm_factor: 63.0 / PI,
72                lane,
73                anti_resonance: Self::compute_anti_resonance(7),
74            },
75            PrecisionLane::Float32 => Self {
76                scale: 1.0,
77                phase_offset: 0.0,
78                norm_factor: 1.0,
79                lane,
80                anti_resonance: 0.0,
81            },
82        }
83    }
84
85    /// Compute anti-resonance offset for given bit depth
86    /// Uses π fractional part to avoid power-of-2 alignment
87    fn compute_anti_resonance(bits: u8) -> f32 {
88        let pi_frac = PI - 3.0; // 0.14159...
89        pi_frac / (1 << bits) as f32
90    }
91
92    /// Normalize a value using π-based constants
93    pub fn normalize(&self, value: f32) -> f32 {
94        (value * self.norm_factor + self.anti_resonance) * self.scale
95    }
96
97    /// Denormalize a value
98    pub fn denormalize(&self, value: f32) -> f32 {
99        (value / self.scale - self.anti_resonance) / self.norm_factor
100    }
101
102    /// Apply phase encoding (maps to -π to π range)
103    pub fn phase_encode(&self, value: f32) -> f32 {
104        let normalized = self.normalize(value);
105        (normalized + self.phase_offset).sin() * PI
106    }
107
108    /// Decode phase-encoded value
109    pub fn phase_decode(&self, phase: f32) -> f32 {
110        let normalized = (phase / PI).asin() - self.phase_offset;
111        self.denormalize(normalized)
112    }
113
114    /// Get π-based angular velocity (for streaming updates)
115    pub fn angular_velocity(&self, delta: f32) -> f32 {
116        delta * self.scale * 2.0 * PI
117    }
118
119    /// Quantize with π-based rounding (breaks symmetry)
120    pub fn pi_quantize(&self, value: f32, max_val: i8) -> i8 {
121        let scaled = value * self.norm_factor + self.anti_resonance;
122        let rounded = (scaled + 0.5 * self.anti_resonance).round();
123        (rounded as i8).clamp(-max_val, max_val - 1)
124    }
125
126    /// Dequantize with π-based scaling
127    pub fn pi_dequantize(&self, quantized: i8) -> f32 {
128        ((quantized as f32) - self.anti_resonance) / self.norm_factor
129    }
130}
131
132/// Angular frequency table for SIMD-friendly operations
133pub struct AngularFrequencyTable {
134    /// Precomputed sin values at π intervals
135    pub sin_table: [f32; 256],
136    /// Precomputed cos values at π intervals
137    pub cos_table: [f32; 256],
138    /// Table resolution
139    pub resolution: usize,
140}
141
142impl AngularFrequencyTable {
143    /// Create a new angular frequency table
144    pub fn new() -> Self {
145        let mut sin_table = [0.0f32; 256];
146        let mut cos_table = [0.0f32; 256];
147
148        for i in 0..256 {
149            let angle = (i as f32) * 2.0 * PI / 256.0;
150            sin_table[i] = angle.sin();
151            cos_table[i] = angle.cos();
152        }
153
154        Self {
155            sin_table,
156            cos_table,
157            resolution: 256,
158        }
159    }
160
161    /// Fast sin approximation using table lookup
162    pub fn fast_sin(&self, angle: f32) -> f32 {
163        let normalized = angle.rem_euclid(2.0 * PI);
164        let index = ((normalized * 256.0 / (2.0 * PI)) as usize) % 256;
165        self.sin_table[index]
166    }
167
168    /// Fast cos approximation using table lookup
169    pub fn fast_cos(&self, angle: f32) -> f32 {
170        let normalized = angle.rem_euclid(2.0 * PI);
171        let index = ((normalized * 256.0 / (2.0 * PI)) as usize) % 256;
172        self.cos_table[index]
173    }
174}
175
176impl Default for AngularFrequencyTable {
177    fn default() -> Self {
178        Self::new()
179    }
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185
186    #[test]
187    fn test_pi_scales() {
188        assert!((PI_SCALE_3BIT - 0.785).abs() < 0.01);
189        assert!((PI_SCALE_5BIT - 0.196).abs() < 0.01);
190        assert!((PI_SCALE_7BIT - 0.049).abs() < 0.01);
191    }
192
193    #[test]
194    fn test_calibration_roundtrip() {
195        let cal = PiCalibration::for_lane(PrecisionLane::Bit5);
196        let original = 0.5f32;
197        let normalized = cal.normalize(original);
198        let denormalized = cal.denormalize(normalized);
199        assert!((original - denormalized).abs() < 0.001);
200    }
201
202    #[test]
203    fn test_phase_encoding_roundtrip() {
204        let cal = PiCalibration::for_lane(PrecisionLane::Bit7);
205        let original = 0.3f32;
206        let encoded = cal.phase_encode(original);
207        // Phase encoding is lossy for values outside valid range
208        assert!(encoded.is_finite());
209    }
210
211    #[test]
212    fn test_pi_quantize() {
213        let cal = PiCalibration::for_lane(PrecisionLane::Bit3);
214        let q = cal.pi_quantize(1.0, 4);
215        assert!(q >= -4 && q <= 3);
216    }
217
218    #[test]
219    fn test_angular_frequency_table() {
220        let table = AngularFrequencyTable::new();
221
222        // Test at known angles
223        assert!((table.fast_sin(0.0) - 0.0).abs() < 0.03);
224        assert!((table.fast_sin(PI / 2.0) - 1.0).abs() < 0.03);
225        assert!((table.fast_cos(0.0) - 1.0).abs() < 0.03);
226        assert!((table.fast_cos(PI) - (-1.0)).abs() < 0.03);
227    }
228
229    #[test]
230    fn test_anti_resonance_nonzero() {
231        let cal = PiCalibration::for_lane(PrecisionLane::Bit5);
232        assert!(cal.anti_resonance > 0.0);
233        assert!(cal.anti_resonance < 0.01);
234    }
235}