diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 2efef0c3..f2f3c247 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -9,7 +9,6 @@ use petgraph::{ visit::{IntoNodeReferences, NodeIndexable, NodeRef}, }; use std::collections::HashMap; -use std::ops::Index; /// Get all the vertices in a graph that are non-cutting (won't make the graph disconnected) fn get_non_cutting_vertices( @@ -85,7 +84,7 @@ impl Connectivity { pub fn from_graph(graph: StableUnGraph) -> Self { let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); - let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); + let distance = distance.into_iter().collect(); Connectivity { graph, @@ -259,10 +258,10 @@ impl Architecture for Connectivity { fn disconnect(&self, i: GraphIndex) -> Connectivity { let mut graph = self.graph.clone(); - graph.retain_nodes(|_, index| if index.index() == i { false } else { true }); + graph.retain_nodes(|_, index| index.index() != i); let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); - let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); + let distance = distance.into_iter().collect(); Connectivity { graph, @@ -444,14 +443,14 @@ mod tests { fn test_best_simple_path() { let new_architecture = Connectivity::from_edges(&setup_simple()); - assert_eq!(vec![0, 1, 2, 4], new_architecture.best_path(0, 4)); + assert_eq!(new_architecture.best_path(0, 4), vec![0, 1, 2, 4]); } #[test] fn test_best_weighted_path() { let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); - assert_eq!(vec![0, 1, 2, 3, 4], new_architecture.best_path(0, 4)); + assert_eq!(new_architecture.best_path(0, 4), vec![0, 1, 2, 3, 4]); } #[test] @@ -464,9 +463,9 @@ mod tests { #[test] fn test_distance() { let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); - assert_eq!(2, new_architecture.distance(2, 4)); - assert_eq!(2, new_architecture.distance(4, 2)); - assert_eq!(10, new_architecture.distance(0, 4)); + assert_eq!(new_architecture.distance(2, 4), 2); + assert_eq!(new_architecture.distance(4, 2), 2); + assert_eq!(new_architecture.distance(0, 4), 10); } #[test] @@ -479,7 +478,7 @@ mod tests { #[test] fn test_neighbors() { let new_architecture = Connectivity::from_edges(&setup_simple()); - assert_eq!(vec![4, 3, 1], new_architecture.neighbors(2)); + assert_eq!(new_architecture.neighbors(2), vec![4, 3, 1]); } #[test] diff --git a/src/data_structures.rs b/src/data_structures.rs index 577c5aae..cd7143cb 100644 --- a/src/data_structures.rs +++ b/src/data_structures.rs @@ -94,7 +94,7 @@ where } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum PauliLetter { I, X, diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 2a056fff..482888a0 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -1,7 +1,7 @@ use bitvec::prelude::BitVec; use itertools::{izip, Itertools}; use std::fmt; -use std::iter::{self, zip}; +use std::iter::zip; use std::ops::Mul; use super::HasAdjoint; @@ -23,7 +23,7 @@ impl CliffordTableau { pub fn new(n: usize) -> Self { CliffordTableau { pauli_columns: { (0..n).map(|i| PauliString::from_basis_int(i, n)).collect() }, - signs: BitVec::from_iter(iter::repeat(false).take(2 * n)), + signs: BitVec::repeat(false, 2 * n), size: n, } } @@ -67,26 +67,23 @@ impl CliffordTableau { // Loop re-order to be (k, i, j) as j ordering is contiguous. for (k, rhs_pauli_column) in self.pauli_columns.iter().enumerate() { for i in 0..size { - *(pauli_columns[k].x.write().unwrap()) ^= - BitVec::repeat(rhs_pauli_column.x.read().unwrap()[i], 2 * size) - & lhs.pauli_columns[i].x.read().unwrap().as_bitslice(); - *(pauli_columns[k].x.write().unwrap()) ^= - BitVec::repeat(rhs_pauli_column.x.read().unwrap()[i + size], 2 * size) - & lhs.pauli_columns[i].z.read().unwrap().as_bitslice(); - *(pauli_columns[k].z.write().unwrap()) ^= - BitVec::repeat(rhs_pauli_column.z.read().unwrap()[i], 2 * size) - & lhs.pauli_columns[i].x.read().unwrap().as_bitslice(); - *(pauli_columns[k].z.write().unwrap()) ^= - BitVec::repeat(rhs_pauli_column.z.read().unwrap()[i + size], 2 * size) - & lhs.pauli_columns[i].z.read().unwrap().as_bitslice(); + let mut x = pauli_columns[k].x.write().unwrap(); + let mut z = pauli_columns[k].z.write().unwrap(); + *x ^= BitVec::repeat(rhs_pauli_column.x(i), 2 * size) + & lhs.pauli_columns[i].x.read().unwrap().as_bitslice(); + *x ^= BitVec::repeat(rhs_pauli_column.x(i + size), 2 * size) + & lhs.pauli_columns[i].z.read().unwrap().as_bitslice(); + *z ^= BitVec::repeat(rhs_pauli_column.z(i), 2 * size) + & lhs.pauli_columns[i].x.read().unwrap().as_bitslice(); + *z ^= BitVec::repeat(rhs_pauli_column.z(i + size), 2 * size) + & lhs.pauli_columns[i].z.read().unwrap().as_bitslice(); } } let mut i_factors = vec![0_usize; 2 * size]; // Keep track of the inherent i factors of left-hand tableau (where there are Y's in tableau rows) for lhs_pauli_column in lhs.pauli_columns.iter() { - let local_sign = lhs_pauli_column.x.read().unwrap().clone() - & lhs_pauli_column.z.read().unwrap().as_bitslice(); + let local_sign = lhs_pauli_column.y_bitmask(); for (fact, sign) in zip(i_factors.iter_mut(), local_sign) { *fact += sign as usize; } @@ -155,7 +152,7 @@ impl CliffordTableau { .collect::(); new_signs ^= p; - new_signs ^= lhs.signs.clone(); + new_signs ^= lhs.signs.as_bitslice(); CliffordTableau { pauli_columns, @@ -164,17 +161,18 @@ impl CliffordTableau { } } - pub fn permute(&mut self, permutation_vector: Vec) { + pub fn permute(&mut self, permutation_vector: &[usize]) { assert_eq!( permutation_vector .iter() .copied() - .sorted() + .sorted_unstable() .collect::>(), (0..self.size()).collect::>() ); - let sorted_pauli_columns = zip(self.pauli_columns.clone(), permutation_vector) - .sorted_by_key(|a| a.1) + let pauli_columns = std::mem::take(&mut self.pauli_columns); + let sorted_pauli_columns = zip(pauli_columns, permutation_vector) + .sorted_unstable_by_key(|a| a.1) .map(|a| a.0) .collect::>(); self.pauli_columns = sorted_pauli_columns; @@ -197,10 +195,12 @@ impl HasAdjoint for CliffordTableau { pauli_column.z(i + size), ); - new_columns[i].x.write().unwrap().replace(j, x1); - new_columns[i].z.write().unwrap().replace(j, z1); - new_columns[i].x.write().unwrap().replace(j + size, x2); - new_columns[i].z.write().unwrap().replace(j + size, z2); + let mut x = new_columns[i].x.write().unwrap(); + let mut z = new_columns[i].z.write().unwrap(); + x.replace(j, x1); + z.replace(j, z1); + x.replace(j + size, x2); + z.replace(j + size, z2); } }); let mut adjoint_table = CliffordTableau { @@ -244,22 +244,10 @@ impl PropagateClifford for CliffordTableau { fn cx(&mut self, control: IndexType, target: IndexType) -> &mut Self { let n = self.size(); - let (control, target) = match control < target { - true => { - let split = self.pauli_columns.split_at_mut(target); - ( - split.0.get_mut(control).unwrap(), - split.1.get_mut(0).unwrap(), - ) - } - false => { - let split = self.pauli_columns.split_at_mut(control); - ( - split.1.get_mut(0).unwrap(), - split.0.get_mut(target).unwrap(), - ) - } - }; + let [control, target] = self + .pauli_columns + .get_disjoint_mut([control, target]) + .unwrap(); let mut scratch = BitVec::repeat(true, 2 * n); scratch ^= target.x.read().unwrap().as_bitslice(); @@ -356,7 +344,7 @@ mod tests { signs, size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } fn setup_sample_ct() -> CliffordTableau { @@ -469,7 +457,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } #[test] @@ -510,7 +498,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } #[test] @@ -553,7 +541,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } #[test] @@ -596,7 +584,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } #[test] @@ -638,7 +626,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } #[test] @@ -679,7 +667,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } #[test] @@ -720,7 +708,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } #[test] @@ -761,7 +749,7 @@ mod tests { size: ct_size, }; - assert_eq!(clifford_tableau_ref, ct); + assert_eq!(ct, clifford_tableau_ref); } /// This does not generate a valid Clifford Tableau. Only used to check commutation relations @@ -1090,7 +1078,7 @@ mod tests { ref_ct.h(1); ref_ct.cx(1, 0); - assert_eq!(ref_ct, third); + assert_eq!(third, ref_ct); } #[test] @@ -1177,9 +1165,9 @@ mod tests { size: ct_size, }; - assert_eq!(ct_ref, adjoint_ct); + assert_eq!(adjoint_ct, ct_ref); let identity = CliffordTableau::new(2); - assert_eq!(identity, ct * adjoint_ct); + assert_eq!(ct * adjoint_ct, identity); } #[test] @@ -1189,7 +1177,7 @@ mod tests { ct.x(0); let identity = CliffordTableau::new(2); - assert_eq!(identity, ct); + assert_eq!(ct, identity); } #[test] diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index f5b39ba8..f9d005d2 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -1,6 +1,7 @@ use std::{iter::zip, sync::RwLock}; -use bitvec::{order::Lsb0, vec::BitVec}; +use bitvec::vec::BitVec; +use itertools::zip_eq; use super::{pauli_string::PauliString, IndexType, MaskedPropagateClifford, PropagateClifford}; @@ -27,13 +28,13 @@ impl Clone for PauliPolynomial { impl PauliPolynomial { pub fn from_hamiltonian(hamiltonian_representation: Vec<(&str, Angle)>) -> Self { assert!(!hamiltonian_representation.is_empty()); + let terms = hamiltonian_representation.len(); let num_qubits = hamiltonian_representation[0].0.len(); - let mut angles = Vec::::new(); - let mut chain_strings = vec![String::new(); num_qubits]; + let mut angles = Vec::::with_capacity(terms); + let mut chain_strings = vec![String::with_capacity(terms); num_qubits]; //let chains = vec![PauliString::new(); num_qubits]; for (pauli_string, angle) in hamiltonian_representation { - assert!(pauli_string.len() == chain_strings.len()); - zip(chain_strings.iter_mut(), pauli_string.chars()).for_each( + zip_eq(chain_strings.iter_mut(), pauli_string.chars()).for_each( |(chain, pauli_letter)| { chain.push(pauli_letter); }, @@ -71,24 +72,9 @@ impl PauliPolynomial { impl PropagateClifford for PauliPolynomial { fn cx(&mut self, control: IndexType, target: IndexType) -> &mut Self { - let mut bit_mask = BitVec::::repeat(true, self.length()); - - let (control, target) = match control < target { - true => { - let split = self.chains.split_at_mut(target); - ( - split.0.get_mut(control).unwrap(), - split.1.get_mut(0).unwrap(), - ) - } - false => { - let split = self.chains.split_at_mut(control); - ( - split.1.get_mut(0).unwrap(), - split.0.get_mut(target).unwrap(), - ) - } - }; + let mut bit_mask: BitVec = BitVec::repeat(true, self.length()); + + let [control, target] = self.chains.get_disjoint_mut([control, target]).unwrap(); bit_mask ^= control.z.read().unwrap().as_bitslice(); bit_mask ^= target.x.read().unwrap().as_bitslice(); @@ -122,7 +108,7 @@ impl PropagateClifford for PauliPolynomial { let chains_target = self.chains.get_mut(target).unwrap(); chains_target.v(); // Update angles - let y_vec = chains_target.to_owned().y_bitmask(); + let y_vec = chains_target.y_bitmask(); for (angle, flip) in zip(self.angles.write().unwrap().iter_mut(), y_vec.iter()) { if *flip { *angle *= -1.0; @@ -211,7 +197,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -265,7 +251,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -290,7 +276,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -315,7 +301,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -340,7 +326,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -365,7 +351,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } fn setup_sample_two_qubit_pp(pauli_letter: char) -> PauliPolynomial { @@ -414,7 +400,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -440,7 +426,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -466,7 +452,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -492,7 +478,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -519,7 +505,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -545,7 +531,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -571,7 +557,7 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } #[test] @@ -597,6 +583,6 @@ mod tests { angles: RwLock::new(angles_ref), size, }; - assert_eq!(pp_ref, pp); + assert_eq!(pp, pp_ref); } } diff --git a/src/data_structures/pauli_string.rs b/src/data_structures/pauli_string.rs index 368d1109..69a143b8 100644 --- a/src/data_structures/pauli_string.rs +++ b/src/data_structures/pauli_string.rs @@ -32,7 +32,7 @@ impl Clone for PauliString { impl PauliString { /// Constructor for PauliString pub fn new(pauli_x: BitVec, pauli_z: BitVec) -> Self { - assert!(pauli_x.len() == pauli_z.len()); + assert_eq!(pauli_x.len(), pauli_z.len()); PauliString { x: RwLock::new(pauli_x), z: RwLock::new(pauli_z), @@ -77,7 +77,7 @@ impl PauliString { } pub fn pauli(&self, i: usize) -> PauliLetter { - PauliLetter::new(self.x.read().unwrap()[i], self.z.read().unwrap()[i]) + PauliLetter::new(self.x(i), self.z(i)) } pub fn len(&self) -> usize { @@ -94,7 +94,7 @@ impl PauliString { pub(crate) fn masked_s(&self, mask: &BitSlice) { let mut mask = mask.to_owned(); - mask &= self.x.read().unwrap().clone(); + mask &= self.x.read().unwrap().as_bitslice(); *self.z.write().unwrap() ^= &mask; } @@ -110,9 +110,7 @@ impl PauliString { #[allow(dead_code)] pub(crate) fn h(&self) { - let tmp = self.z.read().unwrap().clone(); - *self.z.write().unwrap() = self.x.read().unwrap().clone(); - *self.x.write().unwrap() = tmp; + std::mem::swap(&mut *self.x.write().unwrap(), &mut *self.z.write().unwrap()); } #[allow(dead_code)] @@ -139,13 +137,13 @@ impl PauliString { } pub(crate) fn cx(control: &PauliString, target: &PauliString) { - assert!(control.len() == target.len()); + assert_eq!(control.len(), target.len()); *target.x.write().unwrap() ^= control.x.read().unwrap().as_bitslice(); *control.z.write().unwrap() ^= target.z.read().unwrap().as_bitslice(); } pub(crate) fn masked_cx(control: &PauliString, target: &PauliString, mask: &BitSlice) { - assert!(control.len() == target.len()); + assert_eq!(control.len(), target.len()); let mut x_mask = mask.to_owned(); let mut z_mask = mask.to_owned(); x_mask &= control.x.read().unwrap().as_bitslice(); @@ -311,6 +309,6 @@ mod tests { #[test] fn test_pauli_string_display() { let pauli_string = PauliString::from_text("IXYZI"); - assert_eq!(String::from("I X Y Z I"), pauli_string.to_string()); + assert_eq!(pauli_string.to_string(), String::from("I X Y Z I")); } } diff --git a/src/ir/clifford_tableau/custom_callback.rs b/src/ir/clifford_tableau/custom_callback.rs index 2529107b..8e6a3a50 100644 --- a/src/ir/clifford_tableau/custom_callback.rs +++ b/src/ir/clifford_tableau/custom_callback.rs @@ -100,7 +100,7 @@ where ); } } - let final_permutation = zip(custom_columns.clone(), custom_rows.clone()) + let final_permutation = zip(custom_columns, custom_rows) .sorted_by_key(|a| a.1) .map(|a| a.0) .collect::>(); diff --git a/src/ir/pauli_polynomial/naive.rs b/src/ir/pauli_polynomial/naive.rs index 07f38f9e..234b60c9 100644 --- a/src/ir/pauli_polynomial/naive.rs +++ b/src/ir/pauli_polynomial/naive.rs @@ -33,7 +33,7 @@ where let mut clifford_tableau = std::mem::take(&mut self.clifford_tableau); while !pauli_polynomials.is_empty() { let pauli_polynomial = pauli_polynomials.pop_front().unwrap(); - let num_gadgets: usize = pauli_polynomial.length(); + let num_gadgets = pauli_polynomial.length(); let mask = bitvec![usize, Lsb0; 1; num_gadgets]; push_down_pauli_polynomial_update( &mut pauli_polynomials, diff --git a/tests/clifford_tableau.rs b/tests/clifford_tableau.rs index fff2693e..9ef7a123 100644 --- a/tests/clifford_tableau.rs +++ b/tests/clifford_tableau.rs @@ -221,7 +221,7 @@ fn test_custom_clifford_synthesis_large() { synthesizer.synthesize(clifford_tableau.clone(), &mut mock); let mut ref_ct = parse_clifford_commands(4, mock.commands()); - ref_ct.permute(vec![0, 2, 1, 3]); + ref_ct.permute(&[0, 2, 1, 3]); assert_eq!(clifford_tableau, ref_ct); }