1pub mod algorithm;
8pub mod algorithms;
9pub mod channel;
10pub mod circuit;
11pub mod density;
12pub mod embedding;
13pub mod error;
14pub mod error_correction;
15pub mod fourier;
16pub mod gates;
17pub mod handle;
18pub mod kernel;
19pub mod linear_systems;
20pub mod midcircuit;
21pub mod mps;
22pub mod pauli;
23pub mod ptx_kernels;
24pub mod qaoa;
25pub mod qml;
26pub mod stabilizer;
27pub mod statevec;
28pub mod tensor;
29pub mod trotter;
30pub mod vqe;
31
32pub use algorithm::{
33 BernsteinVaziraniResult, DeutschJozsaResult, FunctionKind, GroverResult, OrderFindingResult,
34 ShorResult, SimonResult, SuperdenseResult, TeleportResult, bernstein_vazirani,
35 bit_flip_correct, bit_flip_encode, classical_order, continued_fraction_convergents,
36 deutsch_jozsa, factor_from_order, gcd, grover_search, hadamard_test, marked_probability,
37 mod_exp, optimal_iterations, order_finding, phase_flip_correct, phase_flip_encode, prepare_ghz,
38 prepare_w, recover_period_from_constraints, shor_factor, simon, superdense_decode, swap_test,
39 teleport,
40};
41pub use algorithms::{
42 AmplitudeEstimationResult, CoinInit, CoinedWalk, IterativeQpeResult, LcuOperator, Mat2, Pauli,
43 PauliTerm, StatePreparation, VqlsResult, VqlsSolver, amplitude_estimation,
44 chebyshev_qsp_angles, chebyshev_t, iterative_phase_estimation, position_std_about,
45 qsp_top_left, qsp_unitary, signal_operator,
46};
47pub use channel::pauli_channel::{
48 bit_flip_channel, bit_phase_flip_channel, pauli_channel, pauli_twirl, phase_flip_channel,
49};
50pub use error::{QuantumError, QuantumResult};
51pub use error_correction::{
52 PauliError, StabKind, Stabilizer, SurfaceCode, SurfaceCodeConfig, Syndrome,
53};
54pub use fourier::{PhaseEstimationResult, phase_estimation, qft_inplace, qft_inverse_inplace};
55pub use linear_systems::{HermitianMatrix, HhlConfig, HhlResult, hhl_solve};
56pub use midcircuit::{
57 ClassicalRegister, MidCircuitOp, apply_if, measure_and_collapse, measure_deterministic,
58 run as run_midcircuit,
59};
60pub use mps::{MatrixProductState, MpsConfig};
61
62#[cfg(test)]
63mod e2e_tests {
64 use crate::channel::noise::{amplitude_damping_channel, depolarizing_channel};
65 use crate::circuit::circuit::{GateOp, QuantumCircuit};
66 use crate::density::density::DensityMatrix;
67 use crate::density::metrics::purity;
68 use crate::fourier::{phase_estimation, qft_inplace, qft_inverse_inplace};
69 use crate::gates::controlled::apply_cnot;
70 use crate::gates::hadamard::gate_h;
71 use crate::gates::hadamard::gate_s;
72 use crate::gates::pauli::gate_x;
73 use crate::handle::LcgRng;
74 use crate::pauli::expval::expectation_value;
75 use crate::pauli::hamiltonian::Hamiltonian;
76 use crate::pauli::pauli_string::PauliOp;
77 use crate::ptx_kernels::{
78 expval_pauli_ptx, measure_prob_ptx, partial_trace_ptx, qft_butterfly_ptx,
79 statevec_apply_1q_ptx, statevec_apply_2q_ptx, statevec_apply_cnot_ptx, trotter_step_ptx,
80 };
81 use crate::qaoa::qaoa::QaoaCircuit;
82 use crate::statevec::apply_1q::apply_1q_inplace;
83 use crate::statevec::state::StateVector;
84 use crate::vqe::ansatz::HardwareEfficientAnsatz;
85 use crate::vqe::vqe::VqeOptimizer;
86
87 #[test]
89 fn e2e_01_zero_state_norm_is_one() {
90 let sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
91 let norm = sv.norm_sq();
92 assert!((norm - 1.0).abs() < 1e-6, "norm={norm}");
93 }
94
95 #[test]
97 fn e2e_02_hadamard_creates_superposition() {
98 let mut sv = StateVector::new_zero_state(1).expect("valid 1-qubit zero state");
99 apply_1q_inplace(&mut sv, 0, &gate_h()).expect("valid qubit index for H gate");
100 let inv_sqrt2 = std::f32::consts::FRAC_1_SQRT_2;
101 assert!(
102 (sv.amps[0].re - inv_sqrt2).abs() < 1e-5,
103 "amp0={:?}",
104 sv.amps[0]
105 );
106 assert!(
107 (sv.amps[1].re - inv_sqrt2).abs() < 1e-5,
108 "amp1={:?}",
109 sv.amps[1]
110 );
111 }
112
113 #[test]
115 fn e2e_03_hadamard_round_trip() {
116 let mut sv = StateVector::new_zero_state(1).expect("valid 1-qubit zero state");
117 apply_1q_inplace(&mut sv, 0, &gate_h()).expect("valid qubit index for first H gate");
118 apply_1q_inplace(&mut sv, 0, &gate_h()).expect("valid qubit index for second H gate");
119 assert!((sv.amps[0].re - 1.0).abs() < 1e-5, "amp0={:?}", sv.amps[0]);
120 assert!(sv.amps[1].norm() < 1e-5, "amp1={:?}", sv.amps[1]);
121 }
122
123 #[test]
125 fn e2e_04_cnot_creates_bell_state() {
126 let mut sv = StateVector::new_zero_state(2).expect("valid 2-qubit zero state");
127 apply_1q_inplace(&mut sv, 0, &gate_h()).expect("valid qubit index for H gate");
128 apply_cnot(&mut sv, 0, 1).expect("valid CNOT qubit indices");
129 let inv_sqrt2 = std::f32::consts::FRAC_1_SQRT_2;
130 assert!((sv.amps[0].re - inv_sqrt2).abs() < 1e-5);
132 assert!((sv.amps[3].re - inv_sqrt2).abs() < 1e-5);
133 assert!(sv.amps[1].norm() < 1e-5);
134 assert!(sv.amps[2].norm() < 1e-5);
135 }
136
137 #[test]
139 fn e2e_05_pauli_z_expval_zero_state() {
140 let sv = StateVector::new_zero_state(1).expect("valid 1-qubit zero state");
141 let mut ham = Hamiltonian::new();
142 ham.add_term(1.0, vec![PauliOp::Z]);
143 let ev = expectation_value(&sv, &ham).expect("valid Hamiltonian expectation value");
144 assert!((ev - 1.0).abs() < 1e-5, "ev={ev}");
145 }
146
147 #[test]
149 fn e2e_06_pauli_z_expval_one_state() {
150 let mut sv = StateVector::new_zero_state(1).expect("valid 1-qubit zero state");
151 apply_1q_inplace(&mut sv, 0, &gate_x()).expect("valid qubit index for X gate"); let mut ham = Hamiltonian::new();
153 ham.add_term(1.0, vec![PauliOp::Z]);
154 let ev = expectation_value(&sv, &ham).expect("valid Hamiltonian expectation value");
155 assert!((ev - (-1.0)).abs() < 1e-5, "ev={ev}");
156 }
157
158 #[test]
160 fn e2e_07_mixed_hamiltonian_expval_finite() {
161 let mut sv = StateVector::new_zero_state(2).expect("valid 2-qubit zero state");
162 apply_1q_inplace(&mut sv, 0, &gate_h()).expect("valid qubit index for H gate");
163 apply_cnot(&mut sv, 0, 1).expect("valid CNOT qubit indices");
164 let mut ham = Hamiltonian::new();
165 ham.add_term(0.5, vec![PauliOp::Z, PauliOp::Z]);
166 ham.add_term(0.3, vec![PauliOp::X, PauliOp::I]);
167 ham.add_term(0.2, vec![PauliOp::I, PauliOp::Y]);
168 let ev = expectation_value(&sv, &ham).expect("valid Hamiltonian expectation value");
169 assert!(ev.is_finite(), "ev={ev}");
170 }
171
172 #[test]
174 fn e2e_08_vqe_energy_decreases() {
175 let ans = HardwareEfficientAnsatz::new(2, 1);
176 let mut ham = Hamiltonian::new();
177 ham.add_term(1.0, vec![PauliOp::Z, PauliOp::Z]);
178 ham.add_term(-0.5, vec![PauliOp::X, PauliOp::I]);
179 let mut rng = LcgRng::new(42);
180 let mut opt = VqeOptimizer::new(ans, ham, &mut rng);
181 let e_initial = opt
182 .energy(&opt.params.clone())
183 .expect("valid energy computation");
184 let (e_final, _) = opt.optimize(5, 0.1).expect("valid VQE optimization run");
185 assert!(
186 e_final <= e_initial + 1e-3,
187 "e_initial={e_initial}, e_final={e_final}"
188 );
189 }
190
191 #[test]
193 fn e2e_09_qaoa_runs_without_error() {
194 let circuit = QaoaCircuit::new(4, 2, vec![0.3, 0.5], vec![0.7, 0.2])
195 .expect("valid QAOA circuit parameters");
196 let graph = vec![(0, 1), (1, 2), (2, 3), (3, 0)];
197 let sv = circuit.run(&graph).expect("valid QAOA circuit run");
198 let norm = sv.norm_sq();
199 assert!((norm - 1.0).abs() < 1e-4, "norm={norm}");
200 }
201
202 #[test]
204 fn e2e_10_pure_state_purity_is_one() {
205 let sv = StateVector::new_zero_state(2).expect("valid 2-qubit zero state");
206 let dm = DensityMatrix::from_pure_state(&sv);
207 let p = purity(&dm);
208 assert!((p - 1.0).abs() < 1e-5, "purity={p}");
209 }
210
211 #[test]
213 fn e2e_11_depolarizing_channel_reduces_purity() {
214 let sv = StateVector::new_zero_state(1).expect("valid 1-qubit zero state");
215 let dm = DensityMatrix::from_pure_state(&sv);
216 let p_initial = purity(&dm);
217
218 let ch = depolarizing_channel(0.5, 2).expect("valid depolarizing channel");
219 let dm_out = ch.apply(&dm).expect("valid channel application");
220 let p_final = purity(&dm_out);
221
222 assert!(
223 p_final < p_initial,
224 "purity did not decrease: {p_initial} → {p_final}"
225 );
226 }
227
228 #[test]
230 fn e2e_12_ptx_kernels_non_empty_all_sm() {
231 for sm in [75u32, 80, 86, 89, 90, 100] {
232 let s1 = statevec_apply_1q_ptx(sm);
233 let s2 = statevec_apply_2q_ptx(sm);
234 let s3 = statevec_apply_cnot_ptx(sm);
235 let s4 = expval_pauli_ptx(sm);
236 let s5 = partial_trace_ptx(sm);
237 let s6 = trotter_step_ptx(sm);
238 let s7 = measure_prob_ptx(sm);
239 let s8 = qft_butterfly_ptx(sm);
240 assert!(!s1.is_empty(), "statevec_apply_1q sm={sm}");
241 assert!(!s2.is_empty(), "statevec_apply_2q sm={sm}");
242 assert!(!s3.is_empty(), "statevec_apply_cnot sm={sm}");
243 assert!(!s4.is_empty(), "expval_pauli sm={sm}");
244 assert!(!s5.is_empty(), "partial_trace sm={sm}");
245 assert!(!s6.is_empty(), "trotter_step sm={sm}");
246 assert!(!s7.is_empty(), "measure_prob sm={sm}");
247 assert!(!s8.is_empty(), "qft_butterfly sm={sm}");
248 }
249 }
250
251 #[test]
253 fn e2e_13_amplitude_damping_channel() {
254 let sv = StateVector::new_zero_state(1).expect("valid 1-qubit zero state");
255 let dm = DensityMatrix::from_pure_state(&sv);
256 let ch = amplitude_damping_channel(0.3).expect("valid amplitude damping channel");
257 let dm_out = ch.apply(&dm).expect("valid channel application");
258 let tr = dm_out.trace();
259 assert!((tr.re - 1.0).abs() < 1e-5, "trace={}", tr.re);
260 }
261
262 #[test]
264 fn e2e_14_circuit_bell_state() {
265 let mut circ = QuantumCircuit::new(2);
266 circ.add_gate(GateOp::H);
267 circ.add_gate(GateOp::Cnot { ctrl: 0, tgt: 1 });
268 let sv = StateVector::new_zero_state(2).expect("valid 2-qubit zero state");
269 let mut rng = LcgRng::new(7);
270 let out = circ
271 .exec_on_state(&sv, &mut rng)
272 .expect("valid circuit execution");
273 let inv_sqrt2 = std::f32::consts::FRAC_1_SQRT_2;
274 assert!((out.amps[0].re - inv_sqrt2).abs() < 1e-5);
275 assert!((out.amps[3].re - inv_sqrt2).abs() < 1e-5);
276 }
277
278 #[test]
280 fn e2e_15_qft_uniform_from_zero_state() {
281 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
282 qft_inplace(&mut sv, &[0, 1, 2]).expect("valid QFT qubit indices");
283 let expected = 1.0 / (8.0_f32).sqrt();
284 for a in &sv.amps {
285 assert!((a.re - expected).abs() < 1e-5, "re={}", a.re);
286 assert!(a.im.abs() < 1e-5, "im={}", a.im);
287 }
288 }
289
290 #[test]
292 fn e2e_16_qft_roundtrip_identity() {
293 let mut rng = LcgRng::new(2024);
294 let mut amps = Vec::with_capacity(8);
295 for _ in 0..8 {
296 amps.push(num_complex::Complex::new(
297 rng.next_normal(),
298 rng.next_normal(),
299 ));
300 }
301 let mut sv = StateVector { amps, n_qubits: 3 };
302 sv.normalize_inplace();
303 let original = sv.amps.clone();
304 qft_inplace(&mut sv, &[0, 1, 2]).expect("valid QFT qubit indices");
305 qft_inverse_inplace(&mut sv, &[0, 1, 2]).expect("valid inverse QFT qubit indices");
306 for (a, b) in sv.amps.iter().zip(original.iter()) {
307 assert!((a.re - b.re).abs() < 1e-5, "re {a:?} vs {b:?}");
308 assert!((a.im - b.im).abs() < 1e-5, "im {a:?} vs {b:?}");
309 }
310 }
311
312 #[test]
314 fn e2e_17_qpe_recovers_quarter_phase() {
315 let mut sv = StateVector::new_zero_state(3).expect("valid 3-qubit zero state");
316 apply_1q_inplace(&mut sv, 2, &gate_x())
317 .expect("valid qubit index for X gate on target qubit"); let res =
319 phase_estimation(&mut sv, &[0, 1], 2, &gate_s()).expect("valid QPE configuration");
320 assert_eq!(res.integer, 1, "integer={}", res.integer);
321 assert!((res.phase - 0.25).abs() < 1e-6, "phase={}", res.phase);
322 assert!(res.probability > 0.999, "prob={}", res.probability);
323 }
324}