exo_core/backends/
quantum_stub.rs1use super::{AdaptResult, SearchResult, SubstrateBackend};
11use std::time::Instant;
12
13#[derive(Debug, Clone)]
15pub struct QuantumMeasurement {
16 pub basis_state: u64,
17 pub probability: f64,
18 pub amplitude_re: f64,
19 pub amplitude_im: f64,
20}
21
22#[derive(Debug, Clone)]
24pub struct DecoherenceParams {
25 pub t1_ms: f64,
27 pub t2_ms: f64,
29}
30
31impl Default for DecoherenceParams {
32 fn default() -> Self {
33 Self {
35 t1_ms: 100.0,
36 t2_ms: 50.0,
37 }
38 }
39}
40
41struct InterferenceState {
43 #[allow(dead_code)]
44 n_qubits: usize,
45 amplitudes: Vec<(u64, f64, f64)>, age_ms: f64,
49 params: DecoherenceParams,
50}
51
52impl InterferenceState {
53 fn new(n_qubits: usize) -> Self {
54 let n_states = 1usize << n_qubits.min(8); let amp = 1.0 / (n_states as f64).sqrt();
57 let amplitudes = (0..n_states as u64).map(|i| (i, amp, 0.0)).collect();
58 Self {
59 n_qubits: n_qubits.min(8),
60 amplitudes,
61 age_ms: 0.0,
62 params: DecoherenceParams::default(),
63 }
64 }
65
66 fn decohere(&mut self, dt_ms: f64) {
68 self.age_ms += dt_ms;
69 let t1_decay = (-self.age_ms / self.params.t1_ms).exp();
70 let t2_decay = (-self.age_ms / self.params.t2_ms).exp();
71 for (_, re, im) in self.amplitudes.iter_mut() {
72 *re *= t1_decay * t2_decay;
73 *im *= t2_decay;
74 }
75 }
76
77 fn purity(&self) -> f64 {
79 let norm_sq: f64 = self
80 .amplitudes
81 .iter()
82 .map(|(_, re, im)| re * re + im * im)
83 .sum();
84 norm_sq
85 }
86
87 fn embed_vector(&mut self, vec: &[f32]) {
90 use std::f64::consts::TAU;
91 for (i, (_, re, im)) in self.amplitudes.iter_mut().enumerate() {
92 let v = vec.get(i).copied().unwrap_or(0.0) as f64;
93 let phase = v * TAU; let magnitude = (*re * *re + *im * *im).sqrt();
95 *re = phase.cos() * magnitude;
96 *im = phase.sin() * magnitude;
97 }
98 let norm = self
100 .amplitudes
101 .iter()
102 .map(|(_, r, i)| r * r + i * i)
103 .sum::<f64>()
104 .sqrt();
105 if norm > 1e-10 {
106 for (_, re, im) in self.amplitudes.iter_mut() {
107 *re /= norm;
108 *im /= norm;
109 }
110 }
111 }
112
113 #[allow(dead_code)]
115 fn measure_top_k(&self, k: usize) -> Vec<QuantumMeasurement> {
116 let mut measurements: Vec<QuantumMeasurement> = self
117 .amplitudes
118 .iter()
119 .map(|&(basis_state, re, im)| QuantumMeasurement {
120 basis_state,
121 probability: re * re + im * im,
122 amplitude_re: re,
123 amplitude_im: im,
124 })
125 .collect();
126 measurements.sort_unstable_by(|a, b| {
127 b.probability
128 .partial_cmp(&a.probability)
129 .unwrap_or(std::cmp::Ordering::Equal)
130 });
131 measurements.truncate(k);
132 measurements
133 }
134}
135
136pub struct QuantumStubBackend {
138 n_qubits: usize,
139 state: InterferenceState,
140 stored_patterns: Vec<(u64, Vec<f32>)>,
141 next_id: u64,
142 decohere_dt_ms: f64,
143}
144
145impl QuantumStubBackend {
146 pub fn new(n_qubits: usize) -> Self {
147 let n = n_qubits.min(8);
148 Self {
149 n_qubits: n,
150 state: InterferenceState::new(n),
151 stored_patterns: Vec::new(),
152 next_id: 0,
153 decohere_dt_ms: 10.0,
154 }
155 }
156
157 pub fn evict_decoherent(&mut self, coherence_threshold: f64) {
159 self.state.decohere(self.decohere_dt_ms);
160 let purity = self.state.purity();
161 if purity < coherence_threshold {
162 self.state = InterferenceState::new(self.n_qubits);
164 }
165 }
166
167 pub fn purity(&self) -> f64 {
168 self.state.purity()
169 }
170
171 pub fn store(&mut self, pattern: &[f32]) -> u64 {
172 let id = self.next_id;
173 self.stored_patterns.push((id, pattern.to_vec()));
174 self.next_id += 1;
175 self.state.embed_vector(pattern);
177 id
178 }
179}
180
181impl SubstrateBackend for QuantumStubBackend {
182 fn name(&self) -> &'static str {
183 "quantum-interference-stub"
184 }
185
186 fn similarity_search(&self, query: &[f32], k: usize) -> Vec<SearchResult> {
187 let t0 = Instant::now();
188 let mut results: Vec<SearchResult> = self
190 .stored_patterns
191 .iter()
192 .map(|(id, pattern)| {
193 let inner: f32 = pattern
195 .iter()
196 .zip(query.iter())
197 .map(|(a, b)| a * b)
198 .sum::<f32>();
199 let norm_p = pattern.iter().map(|x| x * x).sum::<f32>().sqrt().max(1e-8);
200 let norm_q = query.iter().map(|x| x * x).sum::<f32>().sqrt().max(1e-8);
201 let score = (inner / (norm_p * norm_q)) * self.state.purity() as f32;
203 SearchResult {
204 id: *id,
205 score: score.max(0.0),
206 embedding: pattern.clone(),
207 }
208 })
209 .collect();
210 results.sort_unstable_by(|a, b| {
211 b.score
212 .partial_cmp(&a.score)
213 .unwrap_or(std::cmp::Ordering::Equal)
214 });
215 results.truncate(k);
216 let _elapsed = t0.elapsed();
217 results
218 }
219
220 fn adapt(&mut self, pattern: &[f32], reward: f32) -> AdaptResult {
221 let t0 = Instant::now();
222 if reward.abs() > 0.5 {
223 self.store(pattern);
224 }
225 self.evict_decoherent(0.5);
227 let delta_norm = pattern.iter().map(|x| x * x).sum::<f32>().sqrt() * reward.abs();
228 AdaptResult {
229 delta_norm,
230 mode: "quantum-decay-adapt",
231 latency_us: t0.elapsed().as_micros() as u64,
232 }
233 }
234
235 fn coherence(&self) -> f32 {
236 self.state.purity() as f32
237 }
238
239 fn reset(&mut self) {
240 self.state = InterferenceState::new(self.n_qubits);
241 self.stored_patterns.clear();
242 self.next_id = 0;
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn test_quantum_state_initialized() {
252 let backend = QuantumStubBackend::new(4);
253 assert!(
255 (backend.purity() - 1.0).abs() < 1e-6,
256 "Initial state should be pure"
257 );
258 }
259
260 #[test]
261 fn test_quantum_decoherence() {
262 let mut backend = QuantumStubBackend::new(4);
263 backend.state.params.t1_ms = 10.0;
264 backend.state.params.t2_ms = 5.0;
265 let initial_purity = backend.purity();
266 for _ in 0..50 {
267 backend.evict_decoherent(0.01); backend.state.decohere(2.0);
269 }
270 assert!(
272 backend.purity() < initial_purity,
273 "Decoherence should reduce purity"
274 );
275 }
276
277 #[test]
278 fn test_quantum_similarity_search() {
279 let mut backend = QuantumStubBackend::new(4);
280 let p1 = vec![1.0f32, 0.0, 0.0, 0.0];
281 let p2 = vec![0.0f32, 1.0, 0.0, 0.0];
282 backend.store(&p1);
283 backend.store(&p2);
284
285 let results = backend.similarity_search(&p1, 2);
286 assert!(!results.is_empty());
287 assert!(results[0].score >= results.get(1).map(|r| r.score).unwrap_or(0.0));
289 }
290
291 #[test]
292 fn test_interference_embedding() {
293 let mut state = InterferenceState::new(4);
294 let vec = vec![0.5f32; 8];
295 state.embed_vector(&vec);
296 assert!(
298 state.purity() <= 1.0 + 1e-6,
299 "Quantum state must remain normalized"
300 );
301 }
302}