Skip to main content

ppvm_tableau/gates/
u3.rs

1// SPDX-FileCopyrightText: 2026 The PPVM Authors
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::prelude::*;
5use num::Complex;
6
7impl<T: Config, I, C: SparseVector<Complex<T::Coeff>, I>> U3Gate<T> for GeneralizedTableau<T, I, C>
8where
9    GeneralizedTableau<T, I, C>: RotationOne<T>,
10{
11    fn u3(&mut self, addr0: usize, theta: T::Coeff, phi: T::Coeff, lambda: T::Coeff) {
12        // RZ(phi)RY(theta)RZ(lambda)
13        self.rz(addr0, lambda);
14        self.ry(addr0, theta);
15        self.rz(addr0, phi);
16    }
17}
18
19#[cfg(test)]
20mod tests {
21    use super::*;
22    use ppvm_pauli_sum::config::fxhash::ByteF64;
23    use std::f64::consts::PI;
24
25    type TestConfig = ByteF64<1>;
26    type TestTableau = GeneralizedTableau<TestConfig>;
27
28    #[test]
29    fn test_u3_identity() {
30        // U3(0, 0, 0) = I, |0⟩ stays |0⟩
31        let mut tab: TestTableau = GeneralizedTableau::new(1, 1e-12);
32        tab.u3(0, 0.0, 0.0, 0.0);
33        assert_eq!(tab.coefficients.len(), 1);
34        assert!(!tab.measure(0).unwrap());
35    }
36
37    #[test]
38    fn test_u3_x_gate() {
39        // U3(π, 0, 0) = RY(π) (up to global phase): |0⟩ → |1⟩
40        let mut tab: TestTableau = GeneralizedTableau::new(1, 1e-12);
41        tab.u3(0, PI, 0.0, 0.0);
42        assert_eq!(tab.coefficients.len(), 1);
43        assert!(tab.measure(0).unwrap());
44    }
45
46    #[test]
47    fn test_u3_superposition() {
48        // U3(π/2, 0, 0) = RY(π/2): creates a superposition
49        let mut tab: TestTableau = GeneralizedTableau::new(1, 1e-12);
50        tab.u3(0, PI / 2.0, 0.0, 0.0);
51        assert_eq!(tab.coefficients.len(), 2);
52    }
53
54    #[test]
55    fn test_u3_matches_rz_ry_rz() {
56        // U3(θ, φ, λ) must give identical measurement statistics to manual RZ(φ)·RY(θ)·RZ(λ)
57        let (theta, phi, lambda) = (0.34 * PI, 0.21 * PI, 0.46 * PI);
58
59        let mut tab_u3: TestTableau = GeneralizedTableau::new_with_seed(1, 1e-12, 0);
60        tab_u3.u3(0, theta, phi, lambda);
61
62        let mut tab_manual: TestTableau = GeneralizedTableau::new_with_seed(1, 1e-12, 0);
63        tab_manual.rz(0, lambda);
64        tab_manual.ry(0, theta);
65        tab_manual.rz(0, phi);
66
67        for seed in 0..200 {
68            let result_u3 = tab_u3.fork(Some(seed)).measure(0).unwrap();
69            let result_manual = tab_manual.fork(Some(seed)).measure(0).unwrap();
70            assert_eq!(result_u3, result_manual, "mismatch at seed {}", seed);
71        }
72    }
73}