q1tsim/gates/
t.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;
16
17/// The `T` gate
18///
19/// The `T` gate rotates the state over π/4 radians around the `z` axis of
20/// the Bloch sphere. It is the square root of the `S` gate.
21pub struct T
22{
23}
24
25impl T
26{
27    /// Create a new `T` gate.
28    pub fn new() -> Self
29    {
30        T { }
31    }
32}
33
34impl crate::gates::Gate for T
35{
36    fn cost(&self) -> f64
37    {
38        crate::gates::U1::cost()
39    }
40
41    fn description(&self) -> &str
42    {
43        "T"
44    }
45
46    fn nr_affected_bits(&self) -> usize
47    {
48        1
49    }
50
51    fn matrix(&self) -> crate::cmatrix::CMatrix
52    {
53        let z = crate::cmatrix::COMPLEX_ZERO;
54        let o = crate::cmatrix::COMPLEX_ONE;
55        let x = crate::cmatrix::COMPLEX_HSQRT2;
56        let i = crate::cmatrix::COMPLEX_I;
57        array![[o, z], [z, x+x*i]]
58    }
59
60    fn apply_slice(&self, mut state: crate::cmatrix::CVecSliceMut)
61    {
62        assert!(state.len() % 2 == 0, "Number of rows is not even.");
63
64        let n = state.len() / 2;
65        let mut slice = state.slice_mut(s![n..]);
66        slice *= num_complex::Complex::from_polar(&1.0, &::std::f64::consts::FRAC_PI_4);
67    }
68
69    fn apply_mat_slice(&self, mut state: crate::cmatrix::CMatSliceMut)
70    {
71        assert!(state.rows() % 2 == 0, "Number of rows is not even.");
72
73        let n = state.rows() / 2;
74        let mut slice = state.slice_mut(s![n.., ..]);
75        slice *= num_complex::Complex::from_polar(&1.0, &::std::f64::consts::FRAC_PI_4);
76    }
77}
78
79impl crate::export::OpenQasm for T
80{
81    fn open_qasm(&self, bit_names: &[String], bits: &[usize])
82        -> crate::error::Result<String>
83    {
84        Ok(format!("t {}", bit_names[bits[0]]))
85    }
86}
87
88impl crate::export::CQasm for T
89{
90    fn c_qasm(&self, bit_names: &[String], bits: &[usize])
91        -> crate::error::Result<String>
92    {
93        Ok(format!("t {}", bit_names[bits[0]]))
94    }
95}
96
97impl crate::export::Latex for T
98{
99    fn latex(&self, bits: &[usize], state: &mut crate::export::LatexExportState)
100        -> crate::error::Result<()>
101    {
102        self.check_nr_bits(bits.len())?;
103        state.add_block_gate(bits, "T")
104    }
105}
106
107/// Conjugate of `T` gate
108///
109/// The `T`<sup>`†`</sup> gate rotates the state over -π/4 radians around the
110/// `z` axis of the Bloch sphere. It is the conjugate of the `T` gate.
111pub struct Tdg
112{
113}
114
115impl Tdg
116{
117    /// Create a new `T`<sup>`†`</sup> gate.
118    pub fn new() -> Self
119    {
120        Tdg { }
121    }
122}
123
124impl crate::gates::Gate for Tdg
125{
126    fn cost(&self) -> f64
127    {
128        crate::gates::U1::cost()
129    }
130
131    fn description(&self) -> &str
132    {
133        "T†"
134    }
135
136    fn nr_affected_bits(&self) -> usize
137    {
138        1
139    }
140
141    fn matrix(&self) -> crate::cmatrix::CMatrix
142    {
143        let z = crate::cmatrix::COMPLEX_ZERO;
144        let o = crate::cmatrix::COMPLEX_ONE;
145        let x = crate::cmatrix::COMPLEX_HSQRT2;
146        let i = crate::cmatrix::COMPLEX_I;
147        array![[o, z], [z, x-x*i]]
148    }
149
150    fn apply_slice(&self, mut state: crate::cmatrix::CVecSliceMut)
151    {
152        assert!(state.len() % 2 == 0, "Number of rows is not even.");
153
154        let n = state.len() / 2;
155        let mut slice = state.slice_mut(s![n..]);
156        slice *= num_complex::Complex::from_polar(&1.0, &-::std::f64::consts::FRAC_PI_4);
157    }
158
159    fn apply_mat_slice(&self, mut state: crate::cmatrix::CMatSliceMut)
160    {
161        assert!(state.rows() % 2 == 0, "Number of rows is not even.");
162
163        let n = state.rows() / 2;
164        let mut slice = state.slice_mut(s![n.., ..]);
165        slice *= num_complex::Complex::from_polar(&1.0, &-::std::f64::consts::FRAC_PI_4);
166    }
167}
168
169impl crate::export::OpenQasm for Tdg
170{
171    fn open_qasm(&self, bit_names: &[String], bits: &[usize])
172        -> crate::error::Result<String>
173    {
174        Ok(format!("tdg {}", bit_names[bits[0]]))
175    }
176}
177
178impl crate::export::CQasm for Tdg
179{
180    fn c_qasm(&self, bit_names: &[String], bits: &[usize])
181        -> crate::error::Result<String>
182    {
183        Ok(format!("tdag {}", bit_names[bits[0]]))
184    }
185}
186
187impl crate::export::Latex for Tdg
188{
189    fn latex(&self, bits: &[usize], state: &mut crate::export::LatexExportState)
190        -> crate::error::Result<()>
191    {
192        self.check_nr_bits(bits.len())?;
193        state.add_block_gate(bits, r"T^\dagger")
194    }
195}
196
197#[cfg(test)]
198mod tests
199{
200    use super::{T, Tdg};
201    use crate::gates::{gate_test, Gate};
202    use crate::export::{Latex, LatexExportState, OpenQasm, CQasm};
203
204    #[test]
205    fn test_description()
206    {
207        let gate = T::new();
208        assert_eq!(gate.description(), "T");
209        let gate = Tdg::new();
210        assert_eq!(gate.description(), "T†");
211    }
212
213    #[test]
214    fn test_cost()
215    {
216        let gate = T::new();
217        assert_eq!(gate.cost(), 7.0);
218        let gate = Tdg::new();
219        assert_eq!(gate.cost(), 7.0);
220    }
221
222    #[test]
223    fn test_matrix()
224    {
225        let z = crate::cmatrix::COMPLEX_ZERO;
226        let o = crate::cmatrix::COMPLEX_ONE;
227        let t = num_complex::Complex::from_polar(&1.0, &::std::f64::consts::FRAC_PI_4);
228
229        let gate = T::new();
230        assert_complex_matrix_eq!(gate.matrix(), array![[o, z], [z, t]]);
231
232        let gate = Tdg::new();
233        assert_complex_matrix_eq!(gate.matrix(), array![[o, z], [z, t.conj()]]);
234    }
235
236    #[test]
237    fn test_apply()
238    {
239        let z = crate::cmatrix::COMPLEX_ZERO;
240        let o = crate::cmatrix::COMPLEX_ONE;
241        let h = 0.5 * o;
242        let x = crate::cmatrix::COMPLEX_HSQRT2;
243        let t = num_complex::Complex::from_polar(&1.0, &::std::f64::consts::FRAC_PI_4);
244        let td = t.conj();
245
246        let mut state = array![
247            [o, z, x,  h, z],
248            [z, o, z, -h, z],
249            [z, z, x,  h, z],
250            [z, z, z, -h, o]
251        ];
252        let result = array![
253            [o, z,   x,    h, z],
254            [z, o,   z,   -h, z],
255            [z, z, t*x,  t*h, z],
256            [z, z,   z, -t*h, t]
257        ];
258        gate_test(T::new(), &mut state, &result);
259
260        let mut state = array![
261            [o, z, x,  h, z],
262            [z, o, z, -h, z],
263            [z, z, x,  h, z],
264            [z, z, z, -h, o]
265        ];
266        let result = array![
267            [o, z,    x,     h,  z],
268            [z, o,    z,    -h,  z],
269            [z, z, td*x,  td*h,  z],
270            [z, z,    z, -td*h, td]
271        ];
272        gate_test(Tdg::new(), &mut state, &result);
273    }
274
275    #[test]
276    fn test_apply_mat()
277    {
278        let z = crate::cmatrix::COMPLEX_ZERO;
279        let o = crate::cmatrix::COMPLEX_ONE;
280        let h = 0.5 * o;
281        let x = crate::cmatrix::COMPLEX_HSQRT2;
282        let t = num_complex::Complex::from_polar(&1.0, &::std::f64::consts::FRAC_PI_4);
283        let td = t.conj();
284
285        let mut state = array![
286            [o, z, x,  h, z],
287            [z, o, z, -h, z],
288            [z, z, x,  h, z],
289            [z, z, z, -h, o]
290        ];
291        T::new().apply_mat(&mut state);
292        assert_complex_matrix_eq!(&state, &array![
293            [o, z,   x,    h, z],
294            [z, o,   z,   -h, z],
295            [z, z, t*x,  t*h, z],
296            [z, z,   z, -t*h, t]
297        ]);
298
299        let mut state = array![
300            [o, z, x,  h, z],
301            [z, o, z, -h, z],
302            [z, z, x,  h, z],
303            [z, z, z, -h, o]
304        ];
305        Tdg::new().apply_mat(&mut state);
306        assert_complex_matrix_eq!(&state, &array![
307            [o, z,    x,     h,  z],
308            [z, o,    z,    -h,  z],
309            [z, z, td*x,  td*h,  z],
310            [z, z,    z, -td*h, td]
311        ]);
312    }
313
314    #[test]
315    fn test_open_qasm()
316    {
317        let bit_names = [String::from("qb")];
318        let qasm = T::new().open_qasm(&bit_names, &[0]);
319        assert_eq!(qasm, Ok(String::from("t qb")));
320        let qasm = Tdg::new().open_qasm(&bit_names, &[0]);
321        assert_eq!(qasm, Ok(String::from("tdg qb")));
322    }
323
324    #[test]
325    fn test_c_qasm()
326    {
327        let bit_names = [String::from("qb")];
328        let qasm = T::new().c_qasm(&bit_names, &[0]);
329        assert_eq!(qasm, Ok(String::from("t qb")));
330        let qasm = Tdg::new().c_qasm(&bit_names, &[0]);
331        assert_eq!(qasm, Ok(String::from("tdag qb")));
332    }
333
334    #[test]
335    fn test_latex()
336    {
337        let gate = T::new();
338        let mut state = LatexExportState::new(1, 0);
339        assert_eq!(gate.latex(&[0], &mut state), Ok(()));
340        assert_eq!(state.code(),
341r#"\Qcircuit @C=1em @R=.7em {
342    \lstick{\ket{0}} & \gate{T} & \qw \\
343}
344"#);
345
346        let gate = Tdg::new();
347        let mut state = LatexExportState::new(1, 0);
348        assert_eq!(gate.latex(&[0], &mut state), Ok(()));
349        assert_eq!(state.code(),
350r#"\Qcircuit @C=1em @R=.7em {
351    \lstick{\ket{0}} & \gate{T^\dagger} & \qw \\
352}
353"#);
354    }
355}