use super::{AdaptResult, SearchResult, SubstrateBackend};
use std::time::Instant;
#[derive(Debug, Clone)]
pub struct QuantumMeasurement {
pub basis_state: u64,
pub probability: f64,
pub amplitude_re: f64,
pub amplitude_im: f64,
}
#[derive(Debug, Clone)]
pub struct DecoherenceParams {
pub t1_ms: f64,
pub t2_ms: f64,
}
impl Default for DecoherenceParams {
fn default() -> Self {
Self {
t1_ms: 100.0,
t2_ms: 50.0,
}
}
}
struct InterferenceState {
#[allow(dead_code)]
n_qubits: usize,
amplitudes: Vec<(u64, f64, f64)>, age_ms: f64,
params: DecoherenceParams,
}
impl InterferenceState {
fn new(n_qubits: usize) -> Self {
let n_states = 1usize << n_qubits.min(8); let amp = 1.0 / (n_states as f64).sqrt();
let amplitudes = (0..n_states as u64).map(|i| (i, amp, 0.0)).collect();
Self {
n_qubits: n_qubits.min(8),
amplitudes,
age_ms: 0.0,
params: DecoherenceParams::default(),
}
}
fn decohere(&mut self, dt_ms: f64) {
self.age_ms += dt_ms;
let t1_decay = (-self.age_ms / self.params.t1_ms).exp();
let t2_decay = (-self.age_ms / self.params.t2_ms).exp();
for (_, re, im) in self.amplitudes.iter_mut() {
*re *= t1_decay * t2_decay;
*im *= t2_decay;
}
}
fn purity(&self) -> f64 {
let norm_sq: f64 = self
.amplitudes
.iter()
.map(|(_, re, im)| re * re + im * im)
.sum();
norm_sq
}
fn embed_vector(&mut self, vec: &[f32]) {
use std::f64::consts::TAU;
for (i, (_, re, im)) in self.amplitudes.iter_mut().enumerate() {
let v = vec.get(i).copied().unwrap_or(0.0) as f64;
let phase = v * TAU; let magnitude = (*re * *re + *im * *im).sqrt();
*re = phase.cos() * magnitude;
*im = phase.sin() * magnitude;
}
let norm = self
.amplitudes
.iter()
.map(|(_, r, i)| r * r + i * i)
.sum::<f64>()
.sqrt();
if norm > 1e-10 {
for (_, re, im) in self.amplitudes.iter_mut() {
*re /= norm;
*im /= norm;
}
}
}
#[allow(dead_code)]
fn measure_top_k(&self, k: usize) -> Vec<QuantumMeasurement> {
let mut measurements: Vec<QuantumMeasurement> = self
.amplitudes
.iter()
.map(|&(basis_state, re, im)| QuantumMeasurement {
basis_state,
probability: re * re + im * im,
amplitude_re: re,
amplitude_im: im,
})
.collect();
measurements.sort_unstable_by(|a, b| {
b.probability
.partial_cmp(&a.probability)
.unwrap_or(std::cmp::Ordering::Equal)
});
measurements.truncate(k);
measurements
}
}
pub struct QuantumStubBackend {
n_qubits: usize,
state: InterferenceState,
stored_patterns: Vec<(u64, Vec<f32>)>,
next_id: u64,
decohere_dt_ms: f64,
}
impl QuantumStubBackend {
pub fn new(n_qubits: usize) -> Self {
let n = n_qubits.min(8);
Self {
n_qubits: n,
state: InterferenceState::new(n),
stored_patterns: Vec::new(),
next_id: 0,
decohere_dt_ms: 10.0,
}
}
pub fn evict_decoherent(&mut self, coherence_threshold: f64) {
self.state.decohere(self.decohere_dt_ms);
let purity = self.state.purity();
if purity < coherence_threshold {
self.state = InterferenceState::new(self.n_qubits);
}
}
pub fn purity(&self) -> f64 {
self.state.purity()
}
pub fn store(&mut self, pattern: &[f32]) -> u64 {
let id = self.next_id;
self.stored_patterns.push((id, pattern.to_vec()));
self.next_id += 1;
self.state.embed_vector(pattern);
id
}
}
impl SubstrateBackend for QuantumStubBackend {
fn name(&self) -> &'static str {
"quantum-interference-stub"
}
fn similarity_search(&self, query: &[f32], k: usize) -> Vec<SearchResult> {
let t0 = Instant::now();
let mut results: Vec<SearchResult> = self
.stored_patterns
.iter()
.map(|(id, pattern)| {
let inner: f32 = pattern
.iter()
.zip(query.iter())
.map(|(a, b)| a * b)
.sum::<f32>();
let norm_p = pattern.iter().map(|x| x * x).sum::<f32>().sqrt().max(1e-8);
let norm_q = query.iter().map(|x| x * x).sum::<f32>().sqrt().max(1e-8);
let score = (inner / (norm_p * norm_q)) * self.state.purity() as f32;
SearchResult {
id: *id,
score: score.max(0.0),
embedding: pattern.clone(),
}
})
.collect();
results.sort_unstable_by(|a, b| {
b.score
.partial_cmp(&a.score)
.unwrap_or(std::cmp::Ordering::Equal)
});
results.truncate(k);
let _elapsed = t0.elapsed();
results
}
fn adapt(&mut self, pattern: &[f32], reward: f32) -> AdaptResult {
let t0 = Instant::now();
if reward.abs() > 0.5 {
self.store(pattern);
}
self.evict_decoherent(0.5);
let delta_norm = pattern.iter().map(|x| x * x).sum::<f32>().sqrt() * reward.abs();
AdaptResult {
delta_norm,
mode: "quantum-decay-adapt",
latency_us: t0.elapsed().as_micros() as u64,
}
}
fn coherence(&self) -> f32 {
self.state.purity() as f32
}
fn reset(&mut self) {
self.state = InterferenceState::new(self.n_qubits);
self.stored_patterns.clear();
self.next_id = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quantum_state_initialized() {
let backend = QuantumStubBackend::new(4);
assert!(
(backend.purity() - 1.0).abs() < 1e-6,
"Initial state should be pure"
);
}
#[test]
fn test_quantum_decoherence() {
let mut backend = QuantumStubBackend::new(4);
backend.state.params.t1_ms = 10.0;
backend.state.params.t2_ms = 5.0;
let initial_purity = backend.purity();
for _ in 0..50 {
backend.evict_decoherent(0.01); backend.state.decohere(2.0);
}
assert!(
backend.purity() < initial_purity,
"Decoherence should reduce purity"
);
}
#[test]
fn test_quantum_similarity_search() {
let mut backend = QuantumStubBackend::new(4);
let p1 = vec![1.0f32, 0.0, 0.0, 0.0];
let p2 = vec![0.0f32, 1.0, 0.0, 0.0];
backend.store(&p1);
backend.store(&p2);
let results = backend.similarity_search(&p1, 2);
assert!(!results.is_empty());
assert!(results[0].score >= results.get(1).map(|r| r.score).unwrap_or(0.0));
}
#[test]
fn test_interference_embedding() {
let mut state = InterferenceState::new(4);
let vec = vec![0.5f32; 8];
state.embed_vector(&vec);
assert!(
state.purity() <= 1.0 + 1e-6,
"Quantum state must remain normalized"
);
}
}