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