1pub mod channel;
8pub mod circuit;
9pub mod density;
10pub mod embedding;
11pub mod error;
12pub mod gates;
13pub mod handle;
14pub mod kernel;
15pub mod midcircuit;
16pub mod mps;
17pub mod pauli;
18pub mod ptx_kernels;
19pub mod qaoa;
20pub mod stabilizer;
21pub mod statevec;
22pub mod trotter;
23pub mod vqe;
24
25pub use error::{QuantumError, QuantumResult};
26pub use midcircuit::{
27 ClassicalRegister, MidCircuitOp, apply_if, measure_and_collapse, measure_deterministic,
28 run as run_midcircuit,
29};
30pub use mps::{MatrixProductState, MpsConfig};
31
32#[cfg(test)]
33mod e2e_tests {
34 use crate::channel::noise::{amplitude_damping_channel, depolarizing_channel};
35 use crate::circuit::circuit::{GateOp, QuantumCircuit};
36 use crate::density::density::DensityMatrix;
37 use crate::density::metrics::purity;
38 use crate::gates::controlled::apply_cnot;
39 use crate::gates::hadamard::gate_h;
40 use crate::gates::pauli::gate_x;
41 use crate::handle::LcgRng;
42 use crate::pauli::expval::expectation_value;
43 use crate::pauli::hamiltonian::Hamiltonian;
44 use crate::pauli::pauli_string::PauliOp;
45 use crate::ptx_kernels::{
46 expval_pauli_ptx, measure_prob_ptx, partial_trace_ptx, statevec_apply_1q_ptx,
47 statevec_apply_2q_ptx, statevec_apply_cnot_ptx, trotter_step_ptx,
48 };
49 use crate::qaoa::qaoa::QaoaCircuit;
50 use crate::statevec::apply_1q::apply_1q_inplace;
51 use crate::statevec::state::StateVector;
52 use crate::vqe::ansatz::HardwareEfficientAnsatz;
53 use crate::vqe::vqe::VqeOptimizer;
54
55 #[test]
57 fn e2e_01_zero_state_norm_is_one() {
58 let sv = StateVector::new_zero_state(3).unwrap();
59 let norm = sv.norm_sq();
60 assert!((norm - 1.0).abs() < 1e-6, "norm={norm}");
61 }
62
63 #[test]
65 fn e2e_02_hadamard_creates_superposition() {
66 let mut sv = StateVector::new_zero_state(1).unwrap();
67 apply_1q_inplace(&mut sv, 0, &gate_h()).unwrap();
68 let inv_sqrt2 = std::f32::consts::FRAC_1_SQRT_2;
69 assert!(
70 (sv.amps[0].re - inv_sqrt2).abs() < 1e-5,
71 "amp0={:?}",
72 sv.amps[0]
73 );
74 assert!(
75 (sv.amps[1].re - inv_sqrt2).abs() < 1e-5,
76 "amp1={:?}",
77 sv.amps[1]
78 );
79 }
80
81 #[test]
83 fn e2e_03_hadamard_round_trip() {
84 let mut sv = StateVector::new_zero_state(1).unwrap();
85 apply_1q_inplace(&mut sv, 0, &gate_h()).unwrap();
86 apply_1q_inplace(&mut sv, 0, &gate_h()).unwrap();
87 assert!((sv.amps[0].re - 1.0).abs() < 1e-5, "amp0={:?}", sv.amps[0]);
88 assert!(sv.amps[1].norm() < 1e-5, "amp1={:?}", sv.amps[1]);
89 }
90
91 #[test]
93 fn e2e_04_cnot_creates_bell_state() {
94 let mut sv = StateVector::new_zero_state(2).unwrap();
95 apply_1q_inplace(&mut sv, 0, &gate_h()).unwrap();
96 apply_cnot(&mut sv, 0, 1).unwrap();
97 let inv_sqrt2 = std::f32::consts::FRAC_1_SQRT_2;
98 assert!((sv.amps[0].re - inv_sqrt2).abs() < 1e-5);
100 assert!((sv.amps[3].re - inv_sqrt2).abs() < 1e-5);
101 assert!(sv.amps[1].norm() < 1e-5);
102 assert!(sv.amps[2].norm() < 1e-5);
103 }
104
105 #[test]
107 fn e2e_05_pauli_z_expval_zero_state() {
108 let sv = StateVector::new_zero_state(1).unwrap();
109 let mut ham = Hamiltonian::new();
110 ham.add_term(1.0, vec![PauliOp::Z]);
111 let ev = expectation_value(&sv, &ham).unwrap();
112 assert!((ev - 1.0).abs() < 1e-5, "ev={ev}");
113 }
114
115 #[test]
117 fn e2e_06_pauli_z_expval_one_state() {
118 let mut sv = StateVector::new_zero_state(1).unwrap();
119 apply_1q_inplace(&mut sv, 0, &gate_x()).unwrap(); let mut ham = Hamiltonian::new();
121 ham.add_term(1.0, vec![PauliOp::Z]);
122 let ev = expectation_value(&sv, &ham).unwrap();
123 assert!((ev - (-1.0)).abs() < 1e-5, "ev={ev}");
124 }
125
126 #[test]
128 fn e2e_07_mixed_hamiltonian_expval_finite() {
129 let mut sv = StateVector::new_zero_state(2).unwrap();
130 apply_1q_inplace(&mut sv, 0, &gate_h()).unwrap();
131 apply_cnot(&mut sv, 0, 1).unwrap();
132 let mut ham = Hamiltonian::new();
133 ham.add_term(0.5, vec![PauliOp::Z, PauliOp::Z]);
134 ham.add_term(0.3, vec![PauliOp::X, PauliOp::I]);
135 ham.add_term(0.2, vec![PauliOp::I, PauliOp::Y]);
136 let ev = expectation_value(&sv, &ham).unwrap();
137 assert!(ev.is_finite(), "ev={ev}");
138 }
139
140 #[test]
142 fn e2e_08_vqe_energy_decreases() {
143 let ans = HardwareEfficientAnsatz::new(2, 1);
144 let mut ham = Hamiltonian::new();
145 ham.add_term(1.0, vec![PauliOp::Z, PauliOp::Z]);
146 ham.add_term(-0.5, vec![PauliOp::X, PauliOp::I]);
147 let mut rng = LcgRng::new(42);
148 let mut opt = VqeOptimizer::new(ans, ham, &mut rng);
149 let e_initial = opt.energy(&opt.params.clone()).unwrap();
150 let (e_final, _) = opt.optimize(5, 0.1).unwrap();
151 assert!(
152 e_final <= e_initial + 1e-3,
153 "e_initial={e_initial}, e_final={e_final}"
154 );
155 }
156
157 #[test]
159 fn e2e_09_qaoa_runs_without_error() {
160 let circuit = QaoaCircuit::new(4, 2, vec![0.3, 0.5], vec![0.7, 0.2]).unwrap();
161 let graph = vec![(0, 1), (1, 2), (2, 3), (3, 0)];
162 let sv = circuit.run(&graph).unwrap();
163 let norm = sv.norm_sq();
164 assert!((norm - 1.0).abs() < 1e-4, "norm={norm}");
165 }
166
167 #[test]
169 fn e2e_10_pure_state_purity_is_one() {
170 let sv = StateVector::new_zero_state(2).unwrap();
171 let dm = DensityMatrix::from_pure_state(&sv);
172 let p = purity(&dm);
173 assert!((p - 1.0).abs() < 1e-5, "purity={p}");
174 }
175
176 #[test]
178 fn e2e_11_depolarizing_channel_reduces_purity() {
179 let sv = StateVector::new_zero_state(1).unwrap();
180 let dm = DensityMatrix::from_pure_state(&sv);
181 let p_initial = purity(&dm);
182
183 let ch = depolarizing_channel(0.5, 2).unwrap();
184 let dm_out = ch.apply(&dm).unwrap();
185 let p_final = purity(&dm_out);
186
187 assert!(
188 p_final < p_initial,
189 "purity did not decrease: {p_initial} → {p_final}"
190 );
191 }
192
193 #[test]
195 fn e2e_12_ptx_kernels_non_empty_all_sm() {
196 for sm in [75u32, 80, 86, 89, 90, 100] {
197 let s1 = statevec_apply_1q_ptx(sm);
198 let s2 = statevec_apply_2q_ptx(sm);
199 let s3 = statevec_apply_cnot_ptx(sm);
200 let s4 = expval_pauli_ptx(sm);
201 let s5 = partial_trace_ptx(sm);
202 let s6 = trotter_step_ptx(sm);
203 let s7 = measure_prob_ptx(sm);
204 assert!(!s1.is_empty(), "statevec_apply_1q sm={sm}");
205 assert!(!s2.is_empty(), "statevec_apply_2q sm={sm}");
206 assert!(!s3.is_empty(), "statevec_apply_cnot sm={sm}");
207 assert!(!s4.is_empty(), "expval_pauli sm={sm}");
208 assert!(!s5.is_empty(), "partial_trace sm={sm}");
209 assert!(!s6.is_empty(), "trotter_step sm={sm}");
210 assert!(!s7.is_empty(), "measure_prob sm={sm}");
211 }
212 }
213
214 #[test]
216 fn e2e_13_amplitude_damping_channel() {
217 let sv = StateVector::new_zero_state(1).unwrap();
218 let dm = DensityMatrix::from_pure_state(&sv);
219 let ch = amplitude_damping_channel(0.3).unwrap();
220 let dm_out = ch.apply(&dm).unwrap();
221 let tr = dm_out.trace();
222 assert!((tr.re - 1.0).abs() < 1e-5, "trace={}", tr.re);
223 }
224
225 #[test]
227 fn e2e_14_circuit_bell_state() {
228 let mut circ = QuantumCircuit::new(2);
229 circ.add_gate(GateOp::H);
230 circ.add_gate(GateOp::Cnot { ctrl: 0, tgt: 1 });
231 let sv = StateVector::new_zero_state(2).unwrap();
232 let mut rng = LcgRng::new(7);
233 let out = circ.exec_on_state(&sv, &mut rng).unwrap();
234 let inv_sqrt2 = std::f32::consts::FRAC_1_SQRT_2;
235 assert!((out.amps[0].re - inv_sqrt2).abs() < 1e-5);
236 assert!((out.amps[3].re - inv_sqrt2).abs() < 1e-5);
237 }
238}