diff --git a/sparsesim/src/lib.rs b/sparsesim/src/lib.rs index c6421d8c..c2b8ec3b 100644 --- a/sparsesim/src/lib.rs +++ b/sparsesim/src/lib.rs @@ -974,29 +974,40 @@ impl QuantumSim { } else { self.mcx(ctls, target); } - // Rx/Ry are different from X/Y by a global phase of -i, so apply that here for mathematical correctness. + // Rx/Ry are different from X/Y by a global phase of -i, so apply that here when indicated by m01, + // for mathematical correctness. let (_, ctls) = self.resolve_and_check_qubits(target, ctls); - self.state = - self.state - .drain() - .fold(SparseState::default(), |mut accum, (index, value)| { - if ctls.iter().all(|c| index.bit(*c)) { - accum.insert(index, value * -Complex64::i()); - } - accum - }); + let factor = m01 + * if sign_flip { + Complex64::i() + } else { + Complex64::one() + }; + if factor != Complex64::one() { + self.state = + self.state + .drain() + .fold(SparseState::default(), |mut accum, (index, value)| { + if ctls.iter().all(|c| index.bit(*c)) { + accum.insert(index, value * factor); + } + accum + }); + } } else if m01.is_nearly_zero() { - // This is just identity, so we can effectively no-op and just add a phase of -1. - let (_, ctls) = self.resolve_and_check_qubits(target, ctls); - self.state = - self.state - .drain() - .fold(SparseState::default(), |mut accum, (index, value)| { - if ctls.iter().all(|c| index.bit(*c)) { - accum.insert(index, value * -Complex64::one()); - } - accum - }); + // This is just identity, so we can effectively no-op, and just add a phase of -1 as indicated by m00. + if m00 == -Complex64::one() { + let (_, ctls) = self.resolve_and_check_qubits(target, ctls); + self.state = + self.state + .drain() + .fold(SparseState::default(), |mut accum, (index, value)| { + if ctls.iter().all(|c| index.bit(*c)) { + accum.insert(index, value * -Complex64::one()); + } + accum + }); + } } else { let (target, ctls) = self.resolve_and_check_qubits(target, ctls); let mut new_state = SparseState::default(); diff --git a/sparsesim/src/matrix_testing.rs b/sparsesim/src/matrix_testing.rs index 2828817f..626ab731 100644 --- a/sparsesim/src/matrix_testing.rs +++ b/sparsesim/src/matrix_testing.rs @@ -603,6 +603,45 @@ mod tests { ); } + #[test] + fn test_rx_zero() { + assert_operation_equal_referenced( + |sim, qs| { + sim.rx(0.0, qs[0]); + }, + |sim, qs| { + sim.apply(&adjoint(&rx(0.0)), &[qs[0]], None); + }, + 1, + ); + } + + #[test] + fn test_rx_3pi() { + assert_operation_equal_referenced( + |sim, qs| { + sim.rx(3.0 * PI, qs[0]); + }, + |sim, qs| { + sim.apply(&adjoint(&rx(3.0 * PI)), &[qs[0]], None); + }, + 1, + ); + } + + #[test] + fn test_rx_4pi() { + assert_operation_equal_referenced( + |sim, qs| { + sim.rx(4.0 * PI, qs[0]); + }, + |sim, qs| { + sim.apply(&adjoint(&rx(4.0 * PI)), &[qs[0]], None); + }, + 1, + ); + } + #[test] fn test_ry() { assert_operation_equal_referenced( @@ -642,6 +681,45 @@ mod tests { ); } + #[test] + fn test_ry_zero() { + assert_operation_equal_referenced( + |sim, qs| { + sim.ry(0.0, qs[0]); + }, + |sim, qs| { + sim.apply(&adjoint(&ry(0.0)), &[qs[0]], None); + }, + 1, + ); + } + + #[test] + fn test_ry_3pi() { + assert_operation_equal_referenced( + |sim, qs| { + sim.ry(3.0 * PI, qs[0]); + }, + |sim, qs| { + sim.apply(&adjoint(&ry(3.0 * PI)), &[qs[0]], None); + }, + 1, + ); + } + + #[test] + fn test_ry_4pi() { + assert_operation_equal_referenced( + |sim, qs| { + sim.ry(4.0 * PI, qs[0]); + }, + |sim, qs| { + sim.apply(&adjoint(&ry(4.0 * PI)), &[qs[0]], None); + }, + 1, + ); + } + #[test] fn test_mcri() { assert_operation_equal_referenced(