rustiq_core/routines/
rotation_extraction.rs

1/// A simple function that expresses a given circuit as a sequence of Pauli rotations
2/// followed by a final Clifford operator
3use crate::structures::{PauliLike, Tableau};
4
5pub fn extract_rotations(
6    circuit: &[(String, Vec<usize>)],
7    nqubits: usize,
8) -> (Vec<(bool, String)>, Tableau) {
9    let mut clifford = Tableau::new(nqubits);
10    let mut rotations = Vec::new();
11    for (gate_name, qbits) in circuit.iter() {
12        match gate_name.as_str() {
13            "CX" => clifford.cnot(qbits[0], qbits[1]),
14            "CZ" => clifford.cz(qbits[0], qbits[1]),
15            "H" => clifford.h(qbits[0]),
16            "S" => clifford.s(qbits[0]),
17            "Sd" => clifford.sd(qbits[0]),
18            "SqrtX" => clifford.sqrt_x(qbits[0]),
19            "SqrtXd" => clifford.sqrt_xd(qbits[0]),
20            "X" => {
21                clifford.sqrt_x(qbits[0]);
22                clifford.sqrt_x(qbits[0])
23            }
24            "Z" => {
25                clifford.s(qbits[0]);
26                clifford.s(qbits[0])
27            }
28            "Y" => {
29                clifford.sqrt_x(qbits[0]);
30                clifford.s(qbits[0]);
31                clifford.s(qbits[0]);
32                clifford.sqrt_xd(qbits[0]);
33            }
34            "RZ" => {
35                rotations.push(clifford.get_inverse_z(qbits[0]));
36            }
37            _ => panic!("Unsupported gate {}", gate_name),
38        }
39    }
40    (rotations, clifford)
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    fn rotations_to_circuit(rotations: &[(&str, f64)], n: usize) -> Vec<(String, Vec<usize>)> {
48        let mut circuit = Vec::new();
49        for (axis, _) in rotations {
50            for q in 0..n {
51                match axis.chars().nth(q).unwrap() {
52                    'X' => circuit.push(("H".to_string(), vec![q])),
53                    'Y' => circuit.push(("SqrtX".to_string(), vec![q])),
54                    _ => {}
55                }
56            }
57            let mut support: Vec<_> = (0..n)
58                .filter(|q| axis.chars().nth(*q).unwrap() != 'I')
59                .collect();
60            let control = support.pop().unwrap();
61            for q in support.iter() {
62                circuit.push(("CX".to_string(), vec![*q, control]));
63            }
64            circuit.push(("RZ".to_string(), vec![control]));
65            for q in support.iter() {
66                circuit.push(("CX".to_string(), vec![*q, control]));
67            }
68            for q in 0..n {
69                match axis.chars().nth(q).unwrap() {
70                    'X' => circuit.push(("H".to_string(), vec![q])),
71                    'Y' => circuit.push(("SqrtXd".to_string(), vec![q])),
72                    _ => {}
73                }
74            }
75        }
76        circuit
77    }
78
79    #[test]
80    fn simple_rotation_extraction() {
81        let rotations = [
82            ("ZX", 4.512201785772802),
83            ("XX", 2.851130732235927),
84            ("YZ", 6.202871194609474),
85            ("ZY", 5.709017144348731),
86            ("XI", 5.20162260375333),
87            ("ZZ", 4.0981647318566905),
88            ("IX", 1.20103093057112),
89            ("XX", 3.748132932778756),
90            ("IX", 2.7013063221306455),
91            ("YI", 2.085429040429552),
92        ];
93        let circuit = rotations_to_circuit(&rotations, 2);
94        let (new_rotations, clifford) = extract_rotations(&circuit, 2);
95        println!("{:?}", new_rotations);
96        assert_eq!(clifford, Tableau::new(2));
97        for (r1, r2) in rotations.iter().zip(new_rotations.iter()) {
98            assert_eq!(r1.0, r2.1);
99            assert!(!r2.0);
100        }
101        println!("{}", clifford.logicals);
102        for i in 0..4 {
103            assert!(!clifford.logicals.get_phase(i));
104        }
105    }
106}