diff --git a/zixy/src/container/word_iters/_word_iters.rs b/zixy/src/container/word_iters/_word_iters.rs index 45ae010..d9a3995 100644 --- a/zixy/src/container/word_iters/_word_iters.rs +++ b/zixy/src/container/word_iters/_word_iters.rs @@ -567,7 +567,7 @@ pub mod test_defs { } #[cfg(test)] -pub mod tests { +mod tests { use crate::container::quicksort::QuickSortNoCoeffs; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; diff --git a/zixy/src/container/word_iters/term_set.rs b/zixy/src/container/word_iters/term_set.rs index b567d05..f4ffa01 100644 --- a/zixy/src/container/word_iters/term_set.rs +++ b/zixy/src/container/word_iters/term_set.rs @@ -761,7 +761,7 @@ pub mod test_defs { } #[cfg(test)] -pub mod tests { +mod tests { use super::test_defs::StringCmpnts; use crate::container::{ traits::EmptyFrom, diff --git a/zixy/src/qubit/traits.rs b/zixy/src/qubit/traits.rs index c88e585..a4a4703 100644 --- a/zixy/src/qubit/traits.rs +++ b/zixy/src/qubit/traits.rs @@ -190,11 +190,7 @@ pub trait PauliWordRef: QubitsBased + Display { fn get_pauli_unchecked(&self, i_mode: usize) -> PauliMatrix; /// Return the Pauli matrix at `i_mode`, or `OutOfBounds` if `i_mode` is invalid. fn get_pauli(&self, i_mode: usize) -> Result { - OutOfBounds::check( - i_mode, - self.get_container().qubits().len(), - Dimension::Cmpnt, - )?; + OutOfBounds::check(i_mode, self.get_container().qubits().len(), Dimension::Mode)?; Ok(self.get_pauli_unchecked(i_mode)) } @@ -508,3 +504,246 @@ pub trait PauliWordMutRef: QubitsBased { } } } + +#[cfg(test)] +mod tests { + use core::fmt; + + use super::*; + + #[derive(Clone)] + struct TestContainer { + qubits: Qubits, + calls: Vec<&'static str>, + } + + impl TestContainer { + fn new(qubits: Qubits) -> Self { + Self { + qubits, + calls: vec![], + } + } + + fn new_from_count(n: usize) -> Self { + Self::new(Qubits::from_count(n)) + } + + fn new_from_offset(i: usize, n: usize) -> Self { + Self::new(Qubits::from_offset(i, n)) + } + } + + impl QubitsBased for TestContainer { + fn qubits(&self) -> &Qubits { + &self.qubits + } + } + + impl proj::ToOwned for TestContainer { + type OwnedType = Self; + fn to_owned(&self) -> Self { + self.clone() + } + } + + impl QubitsStandardized for TestContainer {} + + impl QubitsStandardize for TestContainer { + fn general_standardize(&mut self, n_qubit: usize) { + self.calls.push("general"); + self.qubits = Qubits::from_count(n_qubit); + } + + fn resize_standardize(&mut self, n_qubit: usize) { + self.calls.push("resize"); + self.qubits = Qubits::from_count(n_qubit); + } + } + + impl QubitsRelabel for TestContainer { + fn qubits_mut(&mut self) -> &mut Qubits { + &mut self.qubits + } + } + + struct TestPauliWord { + qubits: Qubits, + paulis: Vec, + } + + impl TestPauliWord { + fn new(paulis: Vec) -> Self { + Self { + qubits: Qubits::from_count(paulis.len()), + paulis, + } + } + } + + impl QubitsBased for TestPauliWord { + fn qubits(&self) -> &Qubits { + &self.qubits + } + } + + impl PauliWordMutRef for TestPauliWord { + fn set_pauli_unchecked(&mut self, i_mode: usize, pauli: PauliMatrix) { + self.paulis[i_mode] = pauli; + } + + fn get_pauli_unchecked(&self, i_mode: usize) -> PauliMatrix { + self.paulis[i_mode] + } + } + + impl fmt::Display for TestPauliWord { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "TestPauliWord with qubits {:?} and paulis {:?}", + self.qubits, self.paulis + ) + } + } + + impl PauliWordRef for TestPauliWord { + type T = Self; + fn get_container(&self) -> &Self::T { + self + } + + fn get_pauli_unchecked(&self, i_mode: usize) -> PauliMatrix { + self.paulis[i_mode] + } + + fn count(&self, pauli: PauliMatrix) -> usize { + self.paulis.iter().filter(|&&p| p == pauli).count() + } + } + + #[test] + fn test_standardize_calls() { + let mut test = TestContainer::new_from_count(2); + + test.standardize(5); + assert_eq!(test.calls, vec!["resize"]); + assert_eq!(test.qubits, Qubits::from_count(5)); + } + + #[test] + fn test_standardize_uses_general() { + let mut test = TestContainer::new_from_offset(2, 3); + + test.standardize(3); + assert_eq!(test.calls, vec!["general"]); + assert_eq!(test.qubits, Qubits::from_count(3)); + } + + #[test] + fn test_standardize_no_op() { + let mut test = TestContainer::new_from_count(3); + + test.standardize(3); + assert!(test.calls.is_empty()); + assert_eq!(test.qubits, Qubits::from_count(3)); + } + + #[test] + fn test_general_standardized() { + let test = TestContainer::new_from_count(3); + + let standardized = test.general_standardized(4); + assert!(test.calls.is_empty()); + assert_eq!(standardized.calls, vec!["general"]); + assert_eq!(standardized.qubits, Qubits::from_count(4)); + } + + #[test] + fn test_resize_standardized() { + let test = TestContainer::new_from_count(3); + let standardized = test.resize_standardized(2); + assert!(test.calls.is_empty()); + assert_eq!(standardized.calls, vec!["resize"]); + assert_eq!(standardized.qubits, Qubits::from_count(2)); + assert_eq!(test.qubits, Qubits::from_count(3)); + } + + #[test] + fn test_push_standardized() { + let test = TestContainer::new_from_count(3); + let standardized = test.push_standardized(); + assert!(test.calls.is_empty()); + assert_eq!(standardized.calls, vec!["resize"]); + assert_eq!(standardized.qubits, Qubits::from_count(4)); + assert_eq!(test.qubits, Qubits::from_count(3)); + } + + #[test] + fn test_relabelled() -> Result<(), BasisError> { + let mut test = TestContainer::new_from_count(3); + test.relabel(Qubits::from_offset(4, 3))?; + assert_eq!(test.qubits, Qubits::from_offset(4, 3)); + Ok(()) + } + + #[test] + fn test_relabel_invalid() { + let mut test = TestContainer::new_from_count(3); + let result = test.relabel(Qubits::from_count(4)); + assert!(matches!(result, Err(BasisError::Counts(_)))); + assert_eq!(test.qubits, Qubits::from_count(3)); + } + + #[test] + fn test_pauliword_clear() { + let mut test = TestPauliWord::new(vec![ + PauliMatrix::X, + PauliMatrix::Y, + PauliMatrix::Z, + PauliMatrix::I, + ]); + test.clear(); + assert_eq!(test.paulis, vec![PauliMatrix::I; 4]); + } + + #[test] + fn test_pauliword_map() { + let test = TestPauliWord::new(vec![ + PauliMatrix::X, + PauliMatrix::Y, + PauliMatrix::I, + PauliMatrix::X, + PauliMatrix::I, + ]); + let map = test.get_pauli_map(); + assert_eq!(map.len(), 3); + assert_eq!(map[&0], PauliMatrix::X); + assert_eq!(map[&3], PauliMatrix::X); + assert_eq!(map[&1], PauliMatrix::Y); + } + + #[test] + fn test_setpaulimap() -> Result<(), OutOfBounds> { + let mut test = TestPauliWord::new(vec![PauliMatrix::I; 3]); + let mut map = HashMap::new(); + map.insert(1, PauliMatrix::X); + map.insert(2, PauliMatrix::Y); + test.set_pauli_map(map)?; + assert_eq!( + test.paulis, + vec![PauliMatrix::I, PauliMatrix::X, PauliMatrix::Y] + ); + Ok(()) + } + + #[test] + fn test_setpaulimap_invalid() { + let mut test = TestPauliWord::new(vec![PauliMatrix::I; 3]); + let mut map = HashMap::new(); + map.insert(100, PauliMatrix::Y); // invalid for word of length 3 + let result = test.set_pauli_map(map); + assert!(result.is_err()); + assert_eq!(test.paulis, vec![PauliMatrix::I; 3]); + } +}