From ae39bec7905f6acb06d44512476e2bdbd470d1a9 Mon Sep 17 00:00:00 2001 From: Mark Skilbeck Date: Mon, 12 Jul 2021 12:10:01 +0100 Subject: [PATCH] Fix: lift non-adjacent 2Q gates --- src/gates/mod.rs | 78 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/src/gates/mod.rs b/src/gates/mod.rs index 04be314..6fff932 100644 --- a/src/gates/mod.rs +++ b/src/gates/mod.rs @@ -1,6 +1,5 @@ pub mod standard; -use itertools::Itertools; use ndarray::{Array, Array2}; use num::complex::Complex64; @@ -49,17 +48,7 @@ impl QGate { match self.qubits.len().cmp(&2) { std::cmp::Ordering::Less => self.lift_adjacent(self.qubits[0], n_qubits), std::cmp::Ordering::Equal => { - let start = *self - .qubits - .iter() - .sorted() - .rev() - .collect_vec() - .last() - .unwrap() - .to_owned(); - - let (permutation, _) = + let (permutation, _, start) = juxtaposing_permutation_matrix(self.qubits[0], self.qubits[1], n_qubits); let permutation_dag = conj(permutation.clone().reversed_axes()); let lifted = self.lift_adjacent(start, n_qubits); @@ -84,25 +73,29 @@ fn conj(arr: Array2) -> Array2 { /// Creates a permutation matrix that moves the Hilbert space for qubit `i` into /// a position adjacent to that of qubit `j`. -fn juxtaposing_permutation_matrix(j: u64, k: u64, n_qubits: u64) -> (Array2, Vec) { +fn juxtaposing_permutation_matrix( + j: u64, + k: u64, + n_qubits: u64, +) -> (Array2, Vec, u64) { let mut permutation = Array::eye(2u64.pow(n_qubits as u32) as usize); let mut new_q_map = (0..n_qubits).collect(); match j.cmp(&k) { - std::cmp::Ordering::Equal => (permutation, new_q_map), + std::cmp::Ordering::Equal => (permutation, new_q_map, j), std::cmp::Ordering::Less => { for i in j..k { permutation = swap(0, 1).lift_adjacent(i, n_qubits).dot(&permutation); new_q_map.swap(i as usize, (i + 1) as usize) } - (permutation, new_q_map) + (permutation, new_q_map, k - 1) } std::cmp::Ordering::Greater => { - for i in j..k { + for i in (k + 1..j).rev() { permutation = swap(0, 1).lift_adjacent(i - 1, n_qubits).dot(&permutation); new_q_map.swap((i - 1) as usize, i as usize) } - (permutation, new_q_map) + (permutation, new_q_map, j - 1) } } } @@ -159,6 +152,55 @@ mod tests { #[test] fn lift_2q() { let gate = super::cnot(0, 1); - println!("{:#}", gate.lift(3)); + assert_eq!( + gate.lift(2), + arr2(&[ + [C1, C0, C0, C0], + [C0, C0, C0, C1], + [C0, C0, C1, C0], + [C0, C1, C0, C0], + ]) + ); + + let gate = super::cnot(1, 0); + assert_eq!( + gate.lift(2), + arr2(&[ + [C1, C0, C0, C0], + [C0, C1, C0, C0], + [C0, C0, C0, C1], + [C0, C0, C1, C0], + ]) + ); + + let gate = super::cnot(0, 2); + assert_eq!( + gate.lift(3), + arr2(&[ + [C1, C0, C0, C0, C0, C0, C0, C0], + [C0, C0, C0, C0, C0, C1, C0, C0], + [C0, C0, C1, C0, C0, C0, C0, C0], + [C0, C0, C0, C0, C0, C0, C0, C1], + [C0, C0, C0, C0, C1, C0, C0, C0], + [C0, C1, C0, C0, C0, C0, C0, C0], + [C0, C0, C0, C0, C0, C0, C1, C0], + [C0, C0, C0, C1, C0, C0, C0, C0], + ]) + ); + + let gate = super::cnot(2, 0); + assert_eq!( + gate.lift(3), + arr2(&[ + [C1, C0, C0, C0, C0, C0, C0, C0], + [C0, C1, C0, C0, C0, C0, C0, C0], + [C0, C0, C1, C0, C0, C0, C0, C0], + [C0, C0, C0, C1, C0, C0, C0, C0], + [C0, C0, C0, C0, C0, C1, C0, C0], + [C0, C0, C0, C0, C1, C0, C0, C0], + [C0, C0, C0, C0, C0, C0, C0, C1], + [C0, C0, C0, C0, C0, C0, C1, C0], + ]) + ); } }