ruvector_sparse_inference/pi/
constants.rs1use crate::precision::PrecisionLane;
11use std::f32::consts::PI;
12
13pub const PI_SCALE_3BIT: f32 = PI / 4.0; pub const PI_SCALE_5BIT: f32 = PI / 16.0; pub const PI_SCALE_7BIT: f32 = PI / 64.0; pub const PHI_APPROX: f32 = 2.0 / (PI - 1.0); pub 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#[derive(Debug, Clone, Copy)]
37pub struct PiCalibration {
38 pub scale: f32,
40 pub phase_offset: f32,
42 pub norm_factor: f32,
44 pub lane: PrecisionLane,
46 pub anti_resonance: f32,
48}
49
50impl PiCalibration {
51 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 fn compute_anti_resonance(bits: u8) -> f32 {
88 let pi_frac = PI - 3.0; pi_frac / (1 << bits) as f32
90 }
91
92 pub fn normalize(&self, value: f32) -> f32 {
94 (value * self.norm_factor + self.anti_resonance) * self.scale
95 }
96
97 pub fn denormalize(&self, value: f32) -> f32 {
99 (value / self.scale - self.anti_resonance) / self.norm_factor
100 }
101
102 pub fn phase_encode(&self, value: f32) -> f32 {
104 let normalized = self.normalize(value);
105 (normalized + self.phase_offset).sin() * PI
106 }
107
108 pub fn phase_decode(&self, phase: f32) -> f32 {
110 let normalized = (phase / PI).asin() - self.phase_offset;
111 self.denormalize(normalized)
112 }
113
114 pub fn angular_velocity(&self, delta: f32) -> f32 {
116 delta * self.scale * 2.0 * PI
117 }
118
119 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 pub fn pi_dequantize(&self, quantized: i8) -> f32 {
128 ((quantized as f32) - self.anti_resonance) / self.norm_factor
129 }
130}
131
132pub struct AngularFrequencyTable {
134 pub sin_table: [f32; 256],
136 pub cos_table: [f32; 256],
138 pub resolution: usize,
140}
141
142impl AngularFrequencyTable {
143 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 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 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 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 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}