rustiq_core/synthesis/clifford/isometry/
common.rs

1use crate::routines::f2_linalg::*;
2use crate::structures::{CliffordCircuit, CliffordGate, IsometryTableau, PauliLike, PauliSet};
3
4pub fn extract_abcd(isometry: &IsometryTableau) -> (Matrix, Matrix, Matrix, Matrix) {
5    let mut a = vec![vec![false; isometry.n + isometry.k]; isometry.n + isometry.k];
6    let mut b = vec![vec![false; isometry.n + isometry.k]; isometry.n + isometry.k];
7    for i in 0..isometry.n {
8        let (_, vec) = isometry.logicals.get_as_vec_bool(i + isometry.n);
9        for j in 0..(isometry.n + isometry.k) {
10            a[j][i] = vec[j + isometry.n + isometry.k];
11            b[j][i] = vec[j];
12        }
13    }
14    for i in 0..isometry.k {
15        let (_, vec) = isometry.stabilizers.get_as_vec_bool(i);
16        for j in 0..(isometry.n + isometry.k) {
17            a[j][i + isometry.n] = vec[j + isometry.n + isometry.k];
18            b[j][i + isometry.n] = vec[j];
19        }
20    }
21    let mut c = vec![vec![false; isometry.n]; isometry.n + isometry.k];
22    let mut d = vec![vec![false; isometry.n]; isometry.n + isometry.k];
23    for i in 0..isometry.n {
24        let (_, vec) = isometry.logicals.get_as_vec_bool(i);
25        for j in 0..(isometry.n + isometry.k) {
26            c[j][i] = vec[j + isometry.n + isometry.k];
27            d[j][i] = vec[j];
28        }
29    }
30    (a, b, c, d)
31}
32
33fn make_b_full_rank(
34    a: &mut Matrix,
35    b: &mut Matrix,
36    c: &mut Matrix,
37    d: &mut Matrix,
38) -> CliffordCircuit {
39    let mut circuit = CliffordCircuit::new(a.len());
40    let mut wit = Vec::new();
41    for i in 0..b.len() {
42        wit.push(b[i].clone());
43        if f2_rank(&wit) < i + 1 {
44            wit[i] = a[i].clone();
45            std::mem::swap(&mut a[i], &mut b[i]);
46            std::mem::swap(&mut c[i], &mut d[i]);
47            circuit.gates.push(CliffordGate::H(i));
48        }
49    }
50    assert_eq!(f2_rank(b), b.len());
51    circuit
52}
53
54pub fn decompose(isometry: &IsometryTableau) -> (Matrix, Matrix, Matrix, CliffordCircuit) {
55    let (mut a, mut b, mut c, mut d) = extract_abcd(isometry);
56    let piece = make_b_full_rank(&mut a, &mut b, &mut c, &mut d);
57    let inv_b = inverse_f2(&b);
58    let b_k: Matrix = inv_b.clone().drain(..isometry.n).collect();
59    let gn = mult_f2(&a, &inv_b);
60    let gk = mult_f2(&inv_b, &d).drain(..isometry.n).collect();
61    (gk, gn, b_k, piece)
62}
63
64pub fn fix_phases(isometry: &IsometryTableau, circuit: &mut CliffordCircuit) {
65    if isometry.k > 0 {
66        return;
67    }
68    let mut simulated = IsometryTableau::new(isometry.n, 0);
69    simulated.conjugate_with_circuit(circuit);
70    let mut pvec = vec![false; 2 * isometry.n];
71    for i in 0..isometry.n {
72        if isometry.logicals.get_phase(i) ^ simulated.logicals.get_phase(i) {
73            pvec[i + isometry.n] = true;
74        }
75        if isometry.logicals.get_phase(i + isometry.n)
76            ^ simulated.logicals.get_phase(i + isometry.n)
77        {
78            pvec[i] = true;
79        }
80    }
81    let mut pset = PauliSet::new(isometry.n);
82    pset.insert_vec_bool(&pvec, false);
83    pset.conjugate_with_circuit(circuit);
84    let (_, pstring) = pset.get(0);
85    for (i, c) in pstring.chars().enumerate() {
86        match c {
87            'X' => {
88                circuit.gates.push(CliffordGate::SqrtX(i));
89                circuit.gates.push(CliffordGate::SqrtX(i));
90            }
91            'Z' => {
92                circuit.gates.push(CliffordGate::S(i));
93                circuit.gates.push(CliffordGate::S(i));
94            }
95            'Y' => {
96                circuit.gates.push(CliffordGate::SqrtX(i));
97                circuit.gates.push(CliffordGate::S(i));
98                circuit.gates.push(CliffordGate::S(i));
99                circuit.gates.push(CliffordGate::SqrtXd(i));
100            }
101            _ => {}
102        }
103    }
104}
105
106// Write a test module for this function
107#[cfg(test)]
108mod tests {
109    use super::*;
110    use crate::structures::IsometryTableau;
111
112    fn is_symmetric(table: &Matrix) -> bool {
113        for i in 0..table.len() {
114            for j in 0..table.len() {
115                if table[j][i] != table[i][j] {
116                    return false;
117                }
118            }
119        }
120        true
121    }
122    #[test]
123    fn test_decompose() {
124        let n = 2; // Number of qubits
125        let k = 1; // Size of the extension
126        let isometry = IsometryTableau::random(n, k);
127
128        let (gk, gn, b_k, _) = decompose(&isometry);
129
130        assert_eq!(gk.len(), n);
131        assert!(gk.iter().all(|row| row.len() == n));
132        assert_eq!(gn.len(), k + n);
133        assert!(gn.iter().all(|row| row.len() == k + n));
134
135        assert!(is_symmetric(&gk));
136        assert!(is_symmetric(&gn));
137        assert_eq!(f2_rank(&b_k), b_k.len());
138    }
139}