q1tsim/gates/
z.rs

1// Copyright 2019 Q1t BV
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::gates::Gate;
16use crate::stabilizer::PauliOp;
17
18/// The Pauli Z gate.
19///
20/// The Z gate rotates the state over π radians around the `z` axis of
21/// the Bloch sphere, i.e. it flips the sign of the |1⟩ components of the qubit.
22pub struct Z
23{
24}
25
26impl Z
27{
28    /// Create a new Pauli Z gate.
29    pub fn new() -> Self
30    {
31        Z { }
32    }
33}
34
35impl crate::gates::Gate for Z
36{
37    fn cost(&self) -> f64
38    {
39        crate::gates::U1::cost()
40    }
41
42    fn description(&self) -> &str
43    {
44        "Z"
45    }
46
47    fn nr_affected_bits(&self) -> usize
48    {
49        1
50    }
51
52    fn matrix(&self) -> crate::cmatrix::CMatrix
53    {
54        let z = crate::cmatrix::COMPLEX_ZERO;
55        let o = crate::cmatrix::COMPLEX_ONE;
56        array![[o, z], [z, -o]]
57    }
58
59    fn apply_slice(&self, mut state: crate::cmatrix::CVecSliceMut)
60    {
61        assert!(state.len() % 2 == 0, "Number of rows is not even.");
62
63        let n = state.len() / 2;
64        state.slice_mut(s![n..]).mapv_inplace(|c| -c);
65    }
66
67    fn apply_mat_slice(&self, mut state: crate::cmatrix::CMatSliceMut)
68    {
69        assert!(state.rows() % 2 == 0, "Number of rows is not even.");
70
71        let n = state.rows() / 2;
72        state.slice_mut(s![n.., ..]).mapv_inplace(|c| -c);
73    }
74
75    fn is_stabilizer(&self) -> bool
76    {
77        true
78    }
79
80    fn conjugate(&self, ops: &mut [PauliOp]) -> crate::error::Result<bool>
81    {
82        self.check_nr_bits(ops.len())?;
83        Ok(ops[0] == PauliOp::X || ops[0] == PauliOp::Y)
84    }
85}
86
87impl crate::export::OpenQasm for Z
88{
89    fn open_qasm(&self, bit_names: &[String], bits: &[usize])
90        -> crate::error::Result<String>
91    {
92        Ok(format!("z {}", bit_names[bits[0]]))
93    }
94}
95
96impl crate::export::CQasm for Z
97{
98    fn c_qasm(&self, bit_names: &[String], bits: &[usize])
99        -> crate::error::Result<String>
100    {
101        Ok(format!("z {}", bit_names[bits[0]]))
102    }
103}
104
105impl crate::export::Latex for Z
106{
107    fn latex(&self, bits: &[usize], state: &mut crate::export::LatexExportState)
108        -> crate::error::Result<()>
109    {
110        self.check_nr_bits(bits.len())?;
111
112        let symbol = if state.is_controlled() { r"\control \qw" } else { r"\gate{Z}" };
113        state.set_field(bits[0], String::from(symbol))
114    }
115}
116
117#[cfg(test)]
118mod tests
119{
120    use super::Z;
121    use crate::gates::{gate_test, Gate};
122    use crate::export::{Latex, LatexExportState, OpenQasm, CQasm};
123    use crate::stabilizer::PauliOp;
124
125    #[test]
126    fn test_description()
127    {
128        let gate = Z::new();
129        assert_eq!(gate.description(), "Z");
130    }
131
132    #[test]
133    fn test_cost()
134    {
135        let gate = Z::new();
136        assert_eq!(gate.cost(), 7.0);
137    }
138
139    #[test]
140    fn test_matrix()
141    {
142        let gate = Z::new();
143        let z = crate::cmatrix::COMPLEX_ZERO;
144        let o = crate::cmatrix::COMPLEX_ONE;
145        assert_complex_matrix_eq!(gate.matrix(), array![[o, z], [z, -o]]);
146    }
147
148    #[test]
149    fn test_apply()
150    {
151        let z = crate::cmatrix::COMPLEX_ZERO;
152        let o = crate::cmatrix::COMPLEX_ONE;
153        let x = crate::cmatrix::COMPLEX_HSQRT2;
154        let mut state = array![[o, z, x, x], [z, o, x, -x]];
155        let result = array![[o, z, x, x], [ z, -o, -x, x]];
156        gate_test(Z::new(), &mut state, &result);
157    }
158
159    #[test]
160    fn test_open_qasm()
161    {
162        let bit_names = [String::from("qb")];
163        let qasm = Z::new().open_qasm(&bit_names, &[0]);
164        assert_eq!(qasm, Ok(String::from("z qb")));
165    }
166
167    #[test]
168    fn test_c_qasm()
169    {
170        let bit_names = [String::from("qb")];
171        let qasm = Z::new().c_qasm(&bit_names, &[0]);
172        assert_eq!(qasm, Ok(String::from("z qb")));
173    }
174
175    #[test]
176    fn test_latex()
177    {
178        let gate = Z::new();
179        let mut state = LatexExportState::new(1, 0);
180        assert_eq!(gate.latex(&[0], &mut state), Ok(()));
181        assert_eq!(state.code(),
182r#"\Qcircuit @C=1em @R=.7em {
183    \lstick{\ket{0}} & \gate{Z} & \qw \\
184}
185"#);
186    }
187
188    #[test]
189    fn test_conjugate()
190    {
191        let mut op = [PauliOp::I];
192        assert_eq!(Z::new().conjugate(&mut op), Ok(false));
193        assert_eq!(op, [PauliOp::I]);
194
195        let mut op = [PauliOp::Z];
196        assert_eq!(Z::new().conjugate(&mut op), Ok(false));
197        assert_eq!(op, [PauliOp::Z]);
198
199        let mut op = [PauliOp::X];
200        assert_eq!(Z::new().conjugate(&mut op), Ok(true));
201        assert_eq!(op, [PauliOp::X]);
202
203        let mut op = [PauliOp::Y];
204        assert_eq!(Z::new().conjugate(&mut op), Ok(true));
205        assert_eq!(op, [PauliOp::Y]);
206    }
207}