diff --git a/src/Simulation/Simulators.Tests/Circuits/ExpTest.qs b/src/Simulation/Simulators.Tests/Circuits/ExpTest.qs index 430bbd0ccdd..e45a9e70adb 100644 --- a/src/Simulation/Simulators.Tests/Circuits/ExpTest.qs +++ b/src/Simulation/Simulators.Tests/Circuits/ExpTest.qs @@ -4,7 +4,8 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { open Microsoft.Quantum.Intrinsic; - + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Math; // At some point, this was causing the simulator to crash. @@ -26,7 +27,31 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { ResetAll(qubits); } } - + + /// Verify that Exp behaves as expected by using it in two decompositions: SWAP and CNOT. + operation VerifyExpUsingDecompositions() : Unit { + AssertOperationsEqualReferenced(2, (qs => SwapFromExp(qs[0], qs[1])), (qs => SWAP(qs[0], qs[1]))); + AssertOperationsEqualReferenced(2, (qs => CnotFromExp(qs[0], qs[1])), (qs => CNOT(qs[0], qs[1]))); + } + + /// This decomposition only holds if the magnitude of the angle used in the Exp rotation is correct. + operation SwapFromExp(q0 : Qubit, q1 : Qubit) : Unit is Adj { + let qs = [q0, q1]; + let theta = PI() / 4.0; + Exp([PauliX, PauliX], theta, qs); + Exp([PauliY, PauliY], theta, qs); + Exp([PauliZ, PauliZ], theta, qs); + } + + /// This decomposition only holds if the magnitude of the angle used in Exp is correct and if the + /// sign convention between Rx, Rz, and Exp is consistent. + operation CnotFromExp(q0 : Qubit, q1 : Qubit) : Unit is Adj { + let qs = [q0, q1]; + let theta = PI() / 4.0; + Rx(-2.0 * theta, q1); + Rz(-2.0 * theta, q0); + Adjoint Exp([PauliZ, PauliX], theta, qs); + } } diff --git a/src/Simulation/Simulators.Tests/QuantumSimulatorTests/VerifyGates.cs b/src/Simulation/Simulators.Tests/QuantumSimulatorTests/VerifyGates.cs index f01ed172cfa..41455c4b9e7 100644 --- a/src/Simulation/Simulators.Tests/QuantumSimulatorTests/VerifyGates.cs +++ b/src/Simulation/Simulators.Tests/QuantumSimulatorTests/VerifyGates.cs @@ -560,6 +560,20 @@ public void QSimVerifyExpX() VerifyExp(Pauli.PauliX); } + [Fact] + public void QSimVerifyExpUsingDecompositions() + { + var simulators = new CommonNativeSimulator[] { + new QuantumSimulator(), + new SparseSimulator() + }; + + foreach (var sim in simulators) + { + VerifyExpUsingDecompositions.Run(sim).Wait(); + } + } + [Fact] public void QSimVerifyExpFrac() { diff --git a/src/Simulation/Simulators.Type1.Tests/Tests.Microsoft.Quantum.Simulators.Type1.csproj b/src/Simulation/Simulators.Type1.Tests/Tests.Microsoft.Quantum.Simulators.Type1.csproj index 197bdb2173d..5f1c4583cf7 100644 --- a/src/Simulation/Simulators.Type1.Tests/Tests.Microsoft.Quantum.Simulators.Type1.csproj +++ b/src/Simulation/Simulators.Type1.Tests/Tests.Microsoft.Quantum.Simulators.Type1.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Simulation/Simulators.Type2.Tests/Tests.Microsoft.Quantum.Simulators.Type2.csproj b/src/Simulation/Simulators.Type2.Tests/Tests.Microsoft.Quantum.Simulators.Type2.csproj index 18f70718414..4fab0d44a49 100644 --- a/src/Simulation/Simulators.Type2.Tests/Tests.Microsoft.Quantum.Simulators.Type2.csproj +++ b/src/Simulation/Simulators.Type2.Tests/Tests.Microsoft.Quantum.Simulators.Type2.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Simulation/Simulators.Type3.Tests/Tests.Microsoft.Quantum.Simulators.Type3.csproj b/src/Simulation/Simulators.Type3.Tests/Tests.Microsoft.Quantum.Simulators.Type3.csproj index 0df36c4db25..30416f0148c 100644 --- a/src/Simulation/Simulators.Type3.Tests/Tests.Microsoft.Quantum.Simulators.Type3.csproj +++ b/src/Simulation/Simulators.Type3.Tests/Tests.Microsoft.Quantum.Simulators.Type3.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Simulation/Simulators/CommonNativeSimulator/IsingXX.cs b/src/Simulation/Simulators/CommonNativeSimulator/IsingXX.cs index 5f114db803a..ee02e94e7cb 100644 --- a/src/Simulation/Simulators/CommonNativeSimulator/IsingXX.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/IsingXX.cs @@ -15,7 +15,7 @@ void IIntrinsicIsingXX.Body(double angle, Qubit target1, Qubit target2) CheckAngle(angle); this.CheckQubits(targets); - Exp((uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); + Exp((uint)targets.Length, paulis, angle / -2.0, targets.GetIds()); } void IIntrinsicIsingXX.AdjointBody(double angle, Qubit target1, Qubit target2) @@ -36,7 +36,7 @@ void IIntrinsicIsingXX.ControlledBody(IQArray controls, double angle, Qub CheckAngle(angle); this.CheckQubits(QArray.Add(controls, targets)); - MCExp((uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); + MCExp((uint)targets.Length, paulis, angle / -2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); } } diff --git a/src/Simulation/Simulators/CommonNativeSimulator/IsingYY.cs b/src/Simulation/Simulators/CommonNativeSimulator/IsingYY.cs index 1aa000ec554..377eb1992cf 100644 --- a/src/Simulation/Simulators/CommonNativeSimulator/IsingYY.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/IsingYY.cs @@ -15,7 +15,7 @@ void IIntrinsicIsingYY.Body(double angle, Qubit target1, Qubit target2) CheckAngle(angle); this.CheckQubits(targets); - Exp((uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); + Exp((uint)targets.Length, paulis, angle / -2.0, targets.GetIds()); } void IIntrinsicIsingYY.AdjointBody(double angle, Qubit target1, Qubit target2) @@ -36,7 +36,7 @@ void IIntrinsicIsingYY.ControlledBody(IQArray controls, double angle, Qub CheckAngle(angle); this.CheckQubits(QArray.Add(controls, targets)); - MCExp((uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); + MCExp((uint)targets.Length, paulis, angle / -2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); } } diff --git a/src/Simulation/Simulators/CommonNativeSimulator/IsingZZ.cs b/src/Simulation/Simulators/CommonNativeSimulator/IsingZZ.cs index ffdef477228..862792910eb 100644 --- a/src/Simulation/Simulators/CommonNativeSimulator/IsingZZ.cs +++ b/src/Simulation/Simulators/CommonNativeSimulator/IsingZZ.cs @@ -15,7 +15,7 @@ void IIntrinsicIsingZZ.Body(double angle, Qubit target1, Qubit target2) CheckAngle(angle); this.CheckQubits(targets); - Exp((uint)targets.Length, paulis, angle * 2.0, targets.GetIds()); + Exp((uint)targets.Length, paulis, angle / -2.0, targets.GetIds()); } void IIntrinsicIsingZZ.AdjointBody(double angle, Qubit target1, Qubit target2) @@ -36,7 +36,7 @@ void IIntrinsicIsingZZ.ControlledBody(IQArray controls, double angle, Qub CheckAngle(angle); this.CheckQubits(QArray.Add(controls, targets)); - MCExp((uint)targets.Length, paulis, angle * 2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); + MCExp((uint)targets.Length, paulis, angle / -2.0, (uint)controls.Length, controls.GetIds(), targets.GetIds()); } } diff --git a/src/Simulation/TargetDefinitions/Decompositions/ExpUtilFromIsing.qs b/src/Simulation/TargetDefinitions/Decompositions/ExpUtilFromIsing.qs index ebc50d9aca4..0840705a66f 100644 --- a/src/Simulation/TargetDefinitions/Decompositions/ExpUtilFromIsing.qs +++ b/src/Simulation/TargetDefinitions/Decompositions/ExpUtilFromIsing.qs @@ -14,11 +14,11 @@ namespace Microsoft.Quantum.Intrinsic { } apply { if (paulis[0] == PauliX) { - IsingXX(theta / 2.0, qubits[0], qubits[1]); + IsingXX(-2.0 * theta , qubits[0], qubits[1]); } elif (paulis[0] == PauliY) { - IsingYY(theta / 2.0, qubits[0], qubits[1]); + IsingYY(-2.0 * theta, qubits[0], qubits[1]); } elif (paulis[0] == PauliZ) { - IsingZZ(theta / 2.0, qubits[0], qubits[1]); + IsingZZ(-2.0 * theta, qubits[0], qubits[1]); } else { fail "Type2 decompositions do not support PauliI as an input to Exp"; } @@ -35,7 +35,7 @@ namespace Microsoft.Quantum.Intrinsic { SpreadZ(qubits[1], qubits[2 .. Length(qubits) - 1]); } apply { - IsingZZ(theta / 2.0, qubits[0], qubits[1]); + IsingZZ(-2.0 * theta, qubits[0], qubits[1]); } } }