1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use core::f64::consts::PI;
use libm::{cos, sin};

use crate::complex::Complex;
use crate::quantum::gate::matrix::const_sized::Gate;
use crate::quantum::operator::rotation::rotation_z::rz;
use crate::quantum::operator::traits::{ApplyGate, Parameterized, ToGate, UsedWires};
use crate::quantum::computer::QuantumComputer;

pub fn rpy(phi: f64) -> Gate<1> {
    Complex::new(cos(phi / 2.0), sin(phi / 2.0)) * rz(phi)
}

#[cfg(feature = "wasm-pack")]
use tsify::Tsify;

#[cfg_attr(feature = "wasm-pack", derive(Tsify))]
#[cfg_attr(feature = "wasm-pack", tsify(from_wasm_abi))]
#[cfg_attr(feature = "wasm-pack", derive(serde::Deserialize))]
#[cfg_attr(feature = "wasm-pack", serde(rename_all = "camelCase"))]
#[derive(Copy, Clone, PartialEq)]
pub struct RotationPauliZ {
    wire: u32,
    phi: f64,
}

impl RotationPauliZ {
    pub fn new(wire: u32, phi: f64) -> RotationPauliZ {
        RotationPauliZ { wire, phi }
    }
}

impl ToGate<1> for RotationPauliZ {
    fn to_gate(&self) -> Gate<1> {
        rpy(self.phi)
    }
}

impl UsedWires<1> for RotationPauliZ {
    fn wires(&self) -> [u32; 1] {
        [self.wire]
    }
}

impl ApplyGate<1> for RotationPauliZ {
    fn apply(&self, computer: &mut QuantumComputer) {
        self.to_gate().apply(computer, [self.wire]);
    }
}

impl Parameterized<1> for RotationPauliZ {
    fn parameterized(&self) -> fn(&RotationPauliZ, f64) -> Gate<1> {
        fn create_parameterized(g: &RotationPauliZ, phi: f64) -> Gate<1> {
            RotationPauliZ::new(g.wire, g.phi / PI * phi).to_gate()
        }

        create_parameterized
    }
}

#[cfg(test)]
mod test {
    use crate::quantum::gate::matrix::const_sized::Gate;
    use crate::quantum::operator::simple::pauli_z::PauliZ;
    use crate::quantum::operator::rotation::rotation_pauli_z::RotationPauliZ;
    use crate::quantum::operator::traits::ToGate;
    use core::f64::consts::PI;
    use float_cmp::assert_approx_eq;

    #[test]
    fn test_full() {
        let gate_rz = RotationPauliZ::new(0, PI).to_gate();
        let gate_z = PauliZ::new(0).to_gate();
        assert_approx_eq!(Gate<1>, gate_rz, gate_z, epsilon = 0.000001);
    }

    #[test]
    fn test_half() {
        let gate_rz = RotationPauliZ::new(0, PI / 2.0).to_gate();
        let gate_z = PauliZ::new(0).to_gate();
        assert_approx_eq!(Gate<1>, gate_rz * gate_rz, gate_z, epsilon = 0.000001);
    }

    #[test]
    fn test_third() {
        let gate_rz = RotationPauliZ::new(0, PI / 3.0).to_gate();
        let gate_z = PauliZ::new(0).to_gate();
        assert_approx_eq!(
            Gate<1>,
            gate_rz * gate_rz * gate_rz,
            gate_z,
            epsilon = 0.000001
        );
    }

    #[test]
    fn test_quarter() {
        let gate_rz = RotationPauliZ::new(0, PI / 4.0).to_gate();
        let gate_z = PauliZ::new(0).to_gate();
        assert_approx_eq!(
            Gate<1>,
            gate_rz * gate_rz * gate_rz * gate_rz,
            gate_z,
            epsilon = 0.000001
        );
    }
}