rustiq_core/synthesis/clifford/isometry/
common.rs1use 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#[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; let k = 1; 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}