1use ndarray::{s, Array1, Array2, ArrayView1};
5use num_complex::Complex;
6
7pub type C64 = Complex<f64>;
10
11pub const ONE_C: C64 = Complex::new(1f64, 0f64);
14
15pub const ZERO_C: C64 = Complex::new(0f64, 0f64);
18
19pub const I_C: C64 = Complex::new(0f64, 1f64);
22
23#[cfg(feature = "web-sys-log")]
24fn log_message(msg: &str) {
25 web_sys::console::log_1(&msg.into());
26}
27
28#[cfg(not(feature = "web-sys-log"))]
29fn log_message(msg: &str) {
30 println!("{}", msg);
31}
32
33pub fn log_as_err<T>(msg: String) -> Result<T, String> {
35 log(&msg);
36 Err(msg)
37}
38
39pub fn log(msg: &str) {
41 log_message(msg);
42}
43
44pub fn swap_columns<T: Clone>(data: &mut Array2<T>, idxs: (usize, usize)) {
46 let tmp_a = data.slice(s![.., idxs.0]).to_owned();
49 let tmp_b = data.slice(s![.., idxs.1]).to_owned();
50 data.slice_mut(s![.., idxs.0]).assign(&tmp_b);
51 data.slice_mut(s![.., idxs.1]).assign(&tmp_a);
52}
53
54pub fn set_vec_to_row_sum(data: &mut Array1<bool>, matrix: &Array2<bool>, idx_source: usize) {
58 for idx_col in 0..matrix.shape()[1] - 1 {
61 data[idx_col] ^= matrix[(idx_source, idx_col)];
62 }
63
64 let idx_phase = data.shape()[0] - 1;
65 data[idx_phase] = phase_product(&data.slice(s![..]), &matrix.slice(s![idx_source, ..]));
66}
67
68pub fn set_row_to_row_sum(data: &mut Array2<bool>, idx_source: usize, idx_target: usize) {
72 for idx_col in 0..data.shape()[1] - 1 {
75 data[(idx_target, idx_col)] ^= data[(idx_source, idx_col)];
76 }
77
78 let idx_phase = data.shape()[1] - 1;
79 data[(idx_target, idx_phase)] = phase_product(
80 &data.slice(s![idx_target, ..]),
81 &data.slice(s![idx_source, ..]),
82 );
83}
84
85fn g(x1: bool, z1: bool, x2: bool, z2: bool) -> i32 {
86 match (x1, z1) {
87 (false, false) => 0,
88 (true, true) => (if z2 { 1 } else { 0 }) - (if x2 { 1 } else { 0 }),
89 (true, false) => (if z2 { 1 } else { 0 }) * (if x2 { 1 } else { -1 }),
90 (false, true) => (if x2 { 1 } else { 0 }) * (if z2 { 1 } else { -1 }),
91 }
92}
93
94pub fn split_row(row: &ArrayView1<bool>) -> (Array1<bool>, Array1<bool>, bool) {
97 let n_qubits = (row.shape()[0] - 1) / 2;
98 (
100 row.slice(s![0..n_qubits]).to_owned(),
101 row.slice(s![n_qubits..]).to_owned(),
102 row[2 * n_qubits],
103 )
104}
105
106pub fn phase_product(row1: &ArrayView1<bool>, row2: &ArrayView1<bool>) -> bool {
108 let mut acc = 0i32;
109 let (xs1, zs1, r1) = split_row(row1);
110 let (xs2, zs2, r2) = split_row(row2);
111
112 for idx_col in 0..xs1.shape()[0] {
113 acc += g(xs1[idx_col], zs1[idx_col], xs2[idx_col], zs2[idx_col]);
114 }
115
116 ((if r1 { 2 } else { 0 }) + (if r2 { 2 } else { 0 }) + acc) % 4 == 2
117}