1use super::schrodinger::{Complex, WaveFunction1D, SchrodingerSolver1D};
2use super::wavefunction::DensityMatrix;
3
4#[derive(Clone, Debug)]
6pub struct MeasurementBasis {
7 pub eigenstates: Vec<Vec<Complex>>,
8 pub eigenvalues: Vec<f64>,
9}
10
11impl MeasurementBasis {
12 pub fn new(eigenstates: Vec<Vec<Complex>>, eigenvalues: Vec<f64>) -> Self {
13 Self { eigenstates, eigenvalues }
14 }
15
16 pub fn position_basis(n: usize) -> Self {
18 let mut eigenstates = Vec::with_capacity(n);
19 let eigenvalues: Vec<f64> = (0..n).map(|i| i as f64).collect();
20 for i in 0..n {
21 let mut state = vec![Complex::zero(); n];
22 state[i] = Complex::one();
23 eigenstates.push(state);
24 }
25 Self { eigenstates, eigenvalues }
26 }
27}
28
29pub fn measure(psi: &[Complex], basis: &MeasurementBasis, rng_val: f64) -> (usize, Vec<Complex>) {
32 let probabilities: Vec<f64> = basis
33 .eigenstates
34 .iter()
35 .map(|eigenstate| {
36 let overlap = inner_product(eigenstate, psi);
37 overlap.norm_sq()
38 })
39 .collect();
40
41 let total: f64 = probabilities.iter().sum();
42 let mut cumulative = 0.0;
43 let mut outcome = 0;
44
45 for (i, &p) in probabilities.iter().enumerate() {
46 cumulative += p / total;
47 if rng_val < cumulative {
48 outcome = i;
49 break;
50 }
51 if i == probabilities.len() - 1 {
52 outcome = i;
53 }
54 }
55
56 let collapsed = basis.eigenstates[outcome].clone();
58 (outcome, collapsed)
59}
60
61pub fn projective_measurement(psi: &[Complex], projector: &[Vec<Complex>]) -> (f64, Vec<Complex>) {
64 let n = psi.len();
65 let mut projected = vec![Complex::zero(); n];
67 for i in 0..n {
68 for j in 0..n {
69 projected[i] += projector[i][j] * psi[j];
70 }
71 }
72
73 let probability: f64 = projected.iter().map(|c| c.norm_sq()).sum();
74
75 if probability > 1e-30 {
77 let norm = probability.sqrt();
78 for c in &mut projected {
79 *c = *c / norm;
80 }
81 }
82
83 (probability, projected)
84}
85
86fn inner_product(a: &[Complex], b: &[Complex]) -> Complex {
88 a.iter()
89 .zip(b.iter())
90 .map(|(ai, bi)| ai.conj() * *bi)
91 .fold(Complex::zero(), |acc, x| acc + x)
92}
93
94pub fn decoherence(rho: &mut DensityMatrix, rate: f64, dt: f64) {
97 let n = rho.dim();
98 let decay = (-rate * dt).exp();
99 for i in 0..n {
100 for j in 0..n {
101 if i != j {
102 rho.rho[i][j] = rho.rho[i][j] * decay;
103 }
104 }
105 }
106}
107
108pub fn quantum_zeno_effect(
112 psi_initial: &[Complex],
113 potential: &[f64],
114 measurement_interval: f64,
115 total_time: f64,
116 dx: f64,
117 mass: f64,
118 hbar: f64,
119) -> Vec<f64> {
120 let n = psi_initial.len();
121 let dt = measurement_interval / 10.0; let n_measurements = (total_time / measurement_interval).ceil() as usize;
123 let steps_per_measurement = 10;
124
125 let mut wf = WaveFunction1D::new(psi_initial.to_vec(), dx, 0.0);
126 let mut solver = SchrodingerSolver1D::new(wf, potential.to_vec(), mass, hbar, dt);
127
128 let mut survival_probs = Vec::with_capacity(n_measurements);
129
130 for _ in 0..n_measurements {
131 for _ in 0..steps_per_measurement {
133 solver.step();
134 }
135
136 let overlap = inner_product(psi_initial, &solver.psi.psi);
138 let prob = overlap.norm_sq();
139 survival_probs.push(prob);
140
141 if prob > 0.5 {
144 solver.psi.psi = psi_initial.to_vec();
145 }
146 }
147
148 survival_probs
149}
150
151pub fn weak_measurement(
154 psi: &[Complex],
155 observable: &[Vec<Complex>],
156 strength: f64,
157) -> (f64, Vec<Complex>) {
158 let n = psi.len();
159
160 let mut a_psi = vec![Complex::zero(); n];
162 for i in 0..n {
163 for j in 0..n {
164 a_psi[i] += observable[i][j] * psi[j];
165 }
166 }
167
168 let exp_a = inner_product(psi, &a_psi);
170
171 let mut result = vec![Complex::zero(); n];
174 for i in 0..n {
175 result[i] = psi[i] + (a_psi[i] - psi[i] * exp_a) * strength;
176 }
177
178 let norm_sq: f64 = result.iter().map(|c| c.norm_sq()).sum();
180 let norm = norm_sq.sqrt();
181 if norm > 1e-30 {
182 for c in &mut result {
183 *c = *c / norm;
184 }
185 }
186
187 (exp_a.re, result)
188}
189
190pub struct MeasurementRenderer {
192 pub width: usize,
193}
194
195impl MeasurementRenderer {
196 pub fn new(width: usize) -> Self {
197 Self { width }
198 }
199
200 pub fn render(
203 &self,
204 psi: &[Complex],
205 collapse_point: usize,
206 collapse_progress: f64,
207 ) -> Vec<(char, f64, f64, f64)> {
208 let n = psi.len();
209 let mut result = Vec::with_capacity(self.width);
210
211 for i in 0..self.width {
212 let idx = (i * n) / self.width.max(1);
213 let idx = idx.min(n.saturating_sub(1));
214
215 let original_prob = if n > 0 { psi[idx].norm_sq() } else { 0.0 };
216
217 let collapse_idx = (collapse_point * self.width) / n.max(1);
219 let collapsed_prob = if i == collapse_idx.min(self.width - 1) { 1.0 } else { 0.0 };
220
221 let prob = (1.0 - collapse_progress) * original_prob * 10.0 + collapse_progress * collapsed_prob;
222 let brightness = prob.min(1.0);
223
224 let ch = if collapse_progress > 0.8 && i == collapse_idx.min(self.width - 1) {
225 '!' } else if brightness > 0.5 {
227 '#'
228 } else if brightness > 0.2 {
229 '*'
230 } else if brightness > 0.05 {
231 '.'
232 } else {
233 ' '
234 };
235
236 let r = collapse_progress * brightness;
238 let g = collapse_progress * brightness;
239 let b = (1.0 - collapse_progress) * brightness;
240
241 result.push((ch, r, g, b));
242 }
243 result
244 }
245}
246
247pub struct BornRule;
249
250impl BornRule {
251 pub fn probabilities(amplitudes: &[Complex]) -> Vec<f64> {
253 amplitudes.iter().map(|c| c.norm_sq()).collect()
254 }
255
256 pub fn is_normalized(amplitudes: &[Complex], tolerance: f64) -> bool {
258 let sum: f64 = amplitudes.iter().map(|c| c.norm_sq()).sum();
259 (sum - 1.0).abs() < tolerance
260 }
261
262 pub fn sample(amplitudes: &[Complex], rng_val: f64) -> usize {
264 let probs = Self::probabilities(amplitudes);
265 let total: f64 = probs.iter().sum();
266 let mut cumulative = 0.0;
267 for (i, &p) in probs.iter().enumerate() {
268 cumulative += p / total;
269 if rng_val < cumulative {
270 return i;
271 }
272 }
273 amplitudes.len() - 1
274 }
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn test_born_rule_probabilities() {
283 let amps = vec![
284 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
285 Complex::new(0.0, 1.0 / 2.0_f64.sqrt()),
286 ];
287 let probs = BornRule::probabilities(&s);
288 assert!((probs[0] - 0.5).abs() < 1e-10);
289 assert!((probs[1] - 0.5).abs() < 1e-10);
290 }
291
292 #[test]
293 fn test_born_rule_normalized() {
294 let amps = vec![
295 Complex::new(0.6, 0.0),
296 Complex::new(0.0, 0.8),
297 ];
298 assert!(BornRule::is_normalized(&s, 1e-10));
299 }
300
301 #[test]
302 fn test_measurement_collapses() {
303 let psi = vec![
304 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
305 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
306 ];
307 let basis = MeasurementBasis::new(
308 vec![
309 vec![Complex::one(), Complex::zero()],
310 vec![Complex::zero(), Complex::one()],
311 ],
312 vec![0.0, 1.0],
313 );
314
315 let (outcome, collapsed) = measure(&psi, &basis, 0.3);
316 assert!(outcome == 0 || outcome == 1);
317 let norm: f64 = collapsed.iter().map(|c| c.norm_sq()).sum();
319 assert!((norm - 1.0).abs() < 1e-10);
320 }
321
322 #[test]
323 fn test_projective_measurement() {
324 let psi = vec![
325 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
326 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
327 ];
328 let projector = vec![
330 vec![Complex::one(), Complex::zero()],
331 vec![Complex::zero(), Complex::zero()],
332 ];
333 let (prob, state) = projective_measurement(&psi, &projector);
334 assert!((prob - 0.5).abs() < 1e-10, "Projection prob: {}", prob);
335 assert!((state[0].norm() - 1.0).abs() < 1e-10);
336 assert!(state[1].norm() < 1e-10);
337 }
338
339 #[test]
340 fn test_decoherence() {
341 let psi = vec![
342 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
343 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
344 ];
345 let mut dm = DensityMatrix::from_pure_state(&psi);
346 assert!((dm.purity() - 1.0).abs() < 1e-10);
347
348 for _ in 0..100 {
350 decoherence(&mut dm, 10.0, 0.1);
351 }
352
353 assert!(dm.rho[0][1].norm() < 0.01, "Off-diagonal: {:?}", dm.rho[0][1]);
355 assert!(dm.rho[1][0].norm() < 0.01);
356 assert!((dm.rho[0][0].re - 0.5).abs() < 0.01);
358 assert!((dm.rho[1][1].re - 0.5).abs() < 0.01);
359 }
360
361 #[test]
362 fn test_quantum_zeno_effect() {
363 let n = 64;
365 let dx = 0.1;
366 let potential = vec![0.0; n];
367 let sigma = 1.0;
368 let psi: Vec<Complex> = (0..n)
369 .map(|i| {
370 let x = -3.2 + i as f64 * dx;
371 Complex::new((-x * x / (2.0 * sigma * sigma)).exp(), 0.0)
372 })
373 .collect();
374 let mut psi_norm = psi.clone();
375 let norm_sq: f64 = psi_norm.iter().map(|c| c.norm_sq()).sum::<f64>() * dx;
376 let norm = norm_sq.sqrt();
377 for c in &mut psi_norm {
378 *c = *c / norm;
379 }
380
381 let probs_frequent = quantum_zeno_effect(&psi_norm, &potential, 0.01, 0.1, dx, 1.0, 1.0);
383
384 let probs_infrequent = quantum_zeno_effect(&psi_norm, &potential, 0.05, 0.1, dx, 1.0, 1.0);
386
387 if !probs_frequent.is_empty() && !probs_infrequent.is_empty() {
389 let avg_frequent: f64 = probs_frequent.iter().sum::<f64>() / probs_frequent.len() as f64;
390 let avg_infrequent: f64 = probs_infrequent.iter().sum::<f64>() / probs_infrequent.len() as f64;
391 assert!(
392 avg_frequent >= avg_infrequent - 0.2,
393 "Zeno: frequent={}, infrequent={}",
394 avg_frequent,
395 avg_infrequent
396 );
397 }
398 }
399
400 #[test]
401 fn test_weak_measurement() {
402 let psi = vec![
403 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
404 Complex::new(1.0 / 2.0_f64.sqrt(), 0.0),
405 ];
406 let obs = vec![
408 vec![Complex::one(), Complex::zero()],
409 vec![Complex::zero(), Complex::new(-1.0, 0.0)],
410 ];
411 let (weak_val, post_state) = weak_measurement(&psi, &obs, 0.01);
412 assert!(weak_val.abs() < 1e-10, "Weak value: {}", weak_val);
414 let overlap = inner_product(&psi, &post_state).norm_sq();
416 assert!(overlap > 0.99, "Overlap: {}", overlap);
417 }
418
419 #[test]
420 fn test_measurement_renderer() {
421 let psi: Vec<Complex> = (0..64)
422 .map(|i| {
423 let x = -3.2 + i as f64 * 0.1;
424 Complex::new((-x * x / 2.0).exp(), 0.0)
425 })
426 .collect();
427 let renderer = MeasurementRenderer::new(30);
428 let before = renderer.render(&psi, 32, 0.0);
429 let after = renderer.render(&psi, 32, 1.0);
430 assert_eq!(before.len(), 30);
431 assert_eq!(after.len(), 30);
432 let flashes: usize = after.iter().filter(|&&(c, _, _, _)| c == '!').count();
434 assert!(flashes > 0);
435 }
436
437 #[test]
438 fn test_born_rule_sample() {
439 let amps = vec![
440 Complex::new(1.0, 0.0),
441 Complex::zero(),
442 ];
443 assert_eq!(BornRule::sample(&s, 0.5), 0);
445 assert_eq!(BornRule::sample(&s, 0.99), 0);
446 }
447}