From 809a077699c57985d2a408d49016653b80f85b22 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Wed, 1 Jan 2025 22:42:37 -0800 Subject: [PATCH] Fix `Exp` on qubit arrays larger than 2 with single `PauliI` This fixes a bug in the decomposition for `Exp` that would cause a runtime failure if an array of more than two qubits was used and a single `PauliI` was passed in the Pauli array. The decomposition ignores `PauliI` by calling the `RemovePauliI` helper function, but then incorrectly uses the original arrays when rather than the filtered arrays in the rest of the operation. This adds a test to confirm the fix (without the fix the test triggers a runtime failure in `MapPauli`). --- library/src/tests/intrinsic.rs | 33 ++++++++++++++++++++++++++++++++ library/std/src/Std/Intrinsic.qs | 6 +++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/library/src/tests/intrinsic.rs b/library/src/tests/intrinsic.rs index f58223c883..df9224cbf9 100644 --- a/library/src/tests/intrinsic.rs +++ b/library/src/tests/intrinsic.rs @@ -3009,6 +3009,39 @@ fn test_exp() { .assert_eq(&dump); } +#[test] +fn test_exp_mixed_paulis() { + let dump = test_expression( + indoc! {r#" + { + open Std.Math; + open Std.Diagnostics; + use qs = Qubit[3]; + for q in qs { + H(q); + } + Exp([PauliX, PauliI, PauliY], PI() / 7.0, qs); + DumpMachine(); + ResetAll(qs); + } + "#}, + &Value::unit(), + ); + + expect![[r#" + STATE: + |000⟩: 0.4719+0.0000𝑖 + |001⟩: 0.1651+0.0000𝑖 + |010⟩: 0.4719+0.0000𝑖 + |011⟩: 0.1651+0.0000𝑖 + |100⟩: 0.4719+0.0000𝑖 + |101⟩: 0.1651+0.0000𝑖 + |110⟩: 0.4719+0.0000𝑖 + |111⟩: 0.1651+0.0000𝑖 + "#]] + .assert_eq(&dump); +} + #[test] fn test_apply_unitary_with_h_matrix() { let dump = test_expression( diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs index 67465050f9..949587b642 100644 --- a/library/std/src/Std/Intrinsic.qs +++ b/library/std/src/Std/Intrinsic.qs @@ -143,14 +143,14 @@ operation CNOT(control : Qubit, target : Qubit) : Unit is Adj + Ctl { operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl { body ... { Fact(Length(paulis) == Length(qubits), "Arrays 'pauli' and 'qubits' must have the same length"); - let (newPaulis, newQubits) = RemovePauliI(paulis, qubits); + let (paulis, qubits) = RemovePauliI(paulis, qubits); let angle = -2.0 * theta; - let len = Length(newPaulis); + let len = Length(paulis); if len == 0 { ApplyGlobalPhase(theta); } elif len == 1 { - R(newPaulis[0], angle, qubits[0]); + R(paulis[0], angle, qubits[0]); } elif len == 2 { within { MapPauli(qubits[1], paulis[0], paulis[1]);