amplitude_encoding/
amplitude_encoding.rs1use quantrs2_ml::error::Result;
19use quantrs2_ml::utils::encoding::amplitude_encode;
20use scirs2_core::ndarray::{array, Array1};
21use scirs2_core::Complex64;
22
23fn main() -> Result<()> {
24 println!("=== Amplitude Encoding: Classical Data → Quantum State ===\n");
25
26 println!("--- Example 1: 4D vector (2 qubits) ---");
28 let v1 = array![1.0f64, 2.0, 3.0, 4.0];
29 let norm_v1: f64 = v1.iter().map(|x| x * x).sum::<f64>().sqrt();
30
31 let encoded1 = amplitude_encode(&v1)?;
32 let norm_enc1: f64 = encoded1.iter().map(|c| c.norm_sqr()).sum::<f64>().sqrt();
33
34 println!("Input vector : {:?}", v1.as_slice().expect("slice"));
35 println!("Input norm : {norm_v1:.6}");
36 println!("Encoded state:");
37 for (i, &) in encoded1.iter().enumerate() {
38 println!(
39 " |{i:02b}⟩ : amplitude = {:+.4}{:+.4}i (prob = {:.6})",
40 amp.re,
41 amp.im,
42 amp.norm_sqr()
43 );
44 }
45 println!("Encoded norm : {norm_enc1:.10} (should be 1.0)");
46
47 assert!(
48 (norm_enc1 - 1.0).abs() < 1e-10,
49 "Encoded state must be normalised, got norm={norm_enc1}"
50 );
51
52 println!("\n--- Example 2: 8D image patch (3 qubits) ---");
54 let image_patch = array![0.1f64, 0.5, 0.9, 0.3, 0.7, 0.2, 0.8, 0.4];
56 let encoded2 = amplitude_encode(&image_patch)?;
57 let norm_enc2: f64 = encoded2.iter().map(|c| c.norm_sqr()).sum::<f64>().sqrt();
58
59 println!(
60 "Image patch (8 pixels): {:?}",
61 image_patch.as_slice().expect("slice")
62 );
63 println!("Quantum state norms² :");
64 for (i, &) in encoded2.iter().enumerate() {
65 let bar = "#".repeat((amp.norm_sqr() * 20.0).round() as usize);
66 println!(" |{i:03b}⟩ : {:.4} {bar}", amp.norm_sqr());
67 }
68 println!("Norm check : {norm_enc2:.10} (should be 1.0)");
69
70 assert!((norm_enc2 - 1.0).abs() < 1e-10, "Norm must be 1.0");
71
72 println!("\n--- Example 3: Quantum Inner Product ---");
75
76 let a = array![1.0f64, 0.0, 0.0, 0.0]; let b = array![1.0f64, 0.0, 0.0, 0.0]; let c = array![0.0f64, 1.0, 0.0, 0.0]; let d = array![1.0f64, 1.0, 0.0, 0.0]; let enc_a = amplitude_encode(&a)?;
82 let enc_b = amplitude_encode(&b)?;
83 let enc_c = amplitude_encode(&c)?;
84 let enc_d = amplitude_encode(&d)?;
85
86 let fidelity_ab = quantum_fidelity(&enc_a, &enc_b);
87 let fidelity_ac = quantum_fidelity(&enc_a, &enc_c);
88 let fidelity_ad = quantum_fidelity(&enc_a, &enc_d);
89
90 println!(" ⟨e1|e1⟩² = {fidelity_ab:.6} (expected 1.0 — identical)");
91 println!(" ⟨e1|e2⟩² = {fidelity_ac:.6} (expected 0.0 — orthogonal)");
92 println!(" ⟨e1|d ⟩² = {fidelity_ad:.6} (expected 0.5 — 45°)");
93
94 assert!(
95 (fidelity_ab - 1.0).abs() < 1e-10,
96 "Identical vectors: fidelity=1"
97 );
98 assert!(fidelity_ac < 1e-10, "Orthogonal vectors: fidelity=0");
99 assert!((fidelity_ad - 0.5).abs() < 0.01, "45° angle: fidelity≈0.5");
100
101 println!("\n--- Example 4: Error handling (zero vector) ---");
103 let zero = array![0.0f64, 0.0, 0.0, 0.0];
104 match amplitude_encode(&zero) {
105 Err(e) => println!(" Zero vector rejected: {e} ✓"),
106 Ok(_) => panic!("Should have rejected zero vector"),
107 }
108
109 println!("\n=== Summary ===");
111 println!(" d=4 → 2 qubits (log₂(4) = 2)");
112 println!(" d=8 → 3 qubits (log₂(8) = 3)");
113 println!(" d=2^n data encoded in n qubits — exponential compression");
114 println!(" Quantum inner product computable in O(1) measurement shots");
115
116 println!("\nAll checks passed — OK");
117
118 Ok(())
119}
120
121fn quantum_fidelity(psi_a: &Array1<Complex64>, psi_b: &Array1<Complex64>) -> f64 {
123 let inner: Complex64 = psi_a
125 .iter()
126 .zip(psi_b.iter())
127 .map(|(&a, &b)| a.conj() * b)
128 .sum();
129 inner.norm_sqr()
130}