From 7646109ab2e44a052f6c17f486ec1f54ddf314ac Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 13 Aug 2021 16:14:10 -0700 Subject: [PATCH 1/3] Check qubit release/measurement status on release This mimicks the same behavior in the QIR Runtime wrapper for the fullstate simulator as what we have for C#, namely that a qubit is falid for release if and only if it is either in the ground state or the last operation on that qubit was measure. This fixes #552, and supercedes #710. --- .../lib/Simulators/FullstateSimulator.cpp | 67 ++++++++++++++++++- .../FullstateSimulatorTests.cpp | 31 +++++++++ .../qsharp/qir-test-simulator.qs | 17 +++++ .../QIR-dynamic/qsharp/qir-test-assert.qs | 61 +++++++++++------ src/Simulation/Native/src/simulator/capi.cpp | 4 +- src/Simulation/Native/src/simulator/capi.hpp | 2 +- .../Native/src/simulator/simulator.hpp | 66 +++++++++--------- .../src/simulator/simulatorinterface.hpp | 2 +- 8 files changed, 190 insertions(+), 60 deletions(-) diff --git a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp index 74fd47ef266..68f1fd4ac88 100644 --- a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp +++ b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp @@ -24,6 +24,7 @@ #include "FloatUtils.hpp" #include "QirTypes.hpp" // TODO: Consider removing dependency on this file. +#include "QirRuntime.hpp" #include "QirRuntimeApi_I.hpp" #include "QSharpSimApi_I.hpp" #include "SimFactory.hpp" @@ -164,6 +165,19 @@ namespace Quantum return proc; } + void UnmarkSingleQubit(Qubit q) + { + isMeasured[GetQubitId(q)] = false; + } + + void UnmarkQubitList(long num, Qubit* qubit) + { + for (const auto& id : GetQubitIds(num ,qubit)) + { + isMeasured[id] = false; + } + } + public: CFullstateSimulator(uint32_t userProvidedSeed = 0) : handle(LoadQuantumSimulator()) { @@ -220,15 +234,24 @@ namespace Quantum Qubit q = qubitManager->Allocate(); // Allocate qubit in qubit manager. unsigned id = GetQubitId(q); // Get its id. allocateQubit(this->simulatorId, id); // Allocate it in the simulator. + if (isMeasured.size() < id + 1) + { + isMeasured.resize(id + 1, false); + } return q; } void ReleaseQubit(Qubit q) override { - typedef void (*TReleaseQubit)(unsigned, unsigned); + typedef bool (*TReleaseQubit)(unsigned, unsigned); static TReleaseQubit releaseQubit = reinterpret_cast(this->GetProc("release")); - releaseQubit(this->simulatorId, GetQubitId(q)); // Release qubit in the simulator. + // Release qubit in the simulator, checking to make sure that release was valid. + auto id = GetQubitId(q); + if (!releaseQubit(this->simulatorId, id) && !isMeasured[id]) + { + quantum__rt__fail_cstr("Released qubit neither measured nor in ground state."); + } qubitManager->Release(q); // Release it in the qubit manager. } @@ -238,6 +261,11 @@ namespace Quantum typedef unsigned (*TMeasure)(unsigned, unsigned, unsigned*, unsigned*); static TMeasure m = reinterpret_cast(this->GetProc("Measure")); std::vector ids = GetQubitIds(numTargets, targets); + if (ids.size() == 1) + { + // If measuring exactly one qubit, mark it as measured for tracking. + isMeasured[ids[0]] = true; + } return reinterpret_cast( m(this->simulatorId, (unsigned)numBases, reinterpret_cast(bases), ids.data())); } @@ -272,6 +300,7 @@ namespace Quantum { static TSingleQubitGate op = reinterpret_cast(this->GetProc("X")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledX(long numControls, Qubit controls[], Qubit target) override @@ -279,12 +308,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCX")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void Y(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("Y")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledY(long numControls, Qubit controls[], Qubit target) override @@ -292,12 +324,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCY")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void Z(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("Z")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledZ(long numControls, Qubit controls[], Qubit target) override @@ -305,12 +340,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCZ")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void H(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("H")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledH(long numControls, Qubit controls[], Qubit target) override @@ -318,12 +356,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCH")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void S(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("S")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledS(long numControls, Qubit controls[], Qubit target) override @@ -331,12 +372,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCS")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void AdjointS(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("AdjS")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledAdjointS(long numControls, Qubit controls[], Qubit target) override @@ -345,12 +389,15 @@ namespace Quantum reinterpret_cast(this->GetProc("MCAdjS")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void T(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("T")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledT(long numControls, Qubit controls[], Qubit target) override @@ -358,12 +405,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCT")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void AdjointT(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("AdjT")); op(this->simulatorId, GetQubitId(q)); + UnmarkSingleQubit(q); } void ControlledAdjointT(long numControls, Qubit controls[], Qubit target) override @@ -372,6 +422,8 @@ namespace Quantum reinterpret_cast(this->GetProc("MCAdjT")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void R(PauliId axis, Qubit target, double theta) override @@ -380,6 +432,7 @@ namespace Quantum static TR r = reinterpret_cast(this->GetProc("R")); r(this->simulatorId, GetBasis(axis), theta, GetQubitId(target)); + UnmarkSingleQubit(target); } void ControlledR(long numControls, Qubit controls[], PauliId axis, Qubit target, double theta) override @@ -389,6 +442,8 @@ namespace Quantum std::vector ids = GetQubitIds(numControls, controls); cr(this->simulatorId, GetBasis(axis), theta, (unsigned)numControls, ids.data(), GetQubitId(target)); + UnmarkSingleQubit(target); + UnmarkQubitList(numControls, controls); } void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) override @@ -397,6 +452,7 @@ namespace Quantum static TExp exp = reinterpret_cast(this->GetProc("Exp")); std::vector ids = GetQubitIds(numTargets, targets); exp(this->simulatorId, (unsigned)numTargets, reinterpret_cast(paulis), theta, ids.data()); + UnmarkQubitList(numTargets, targets); } void ControlledExp(long numControls, Qubit controls[], long numTargets, PauliId paulis[], Qubit targets[], @@ -408,6 +464,8 @@ namespace Quantum std::vector idsControls = GetQubitIds(numControls, controls); cexp(this->simulatorId, (unsigned)numTargets, reinterpret_cast(paulis), theta, (unsigned)numControls, idsControls.data(), idsTargets.data()); + UnmarkQubitList(numTargets, targets); + UnmarkQubitList(numControls, controls); } bool Assert(long numTargets, PauliId* bases, Qubit* targets, Result result, const char* failureMessage) override @@ -436,6 +494,11 @@ namespace Quantum void GetStateTo(TDumpLocation location, TDumpToLocationCallback callback); bool GetRegisterTo(TDumpLocation location, TDumpToLocationCallback callback, const QirArray* qubits); + // This bit std::vector tracks whether the last operation on a given qubit was Measure. + // Note that `std::vector` is already specialized to use an underlying bitfied to save space. + // See: https://www.cplusplus.com/reference/vector/vector-bool/ + std::vector isMeasured; + private: TDumpToLocationCallback const dumpToLocationCallback = [](size_t idx, double re, double im, TDumpLocation location) -> bool { diff --git a/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp b/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp index a7b87737f8c..45b05c750a1 100644 --- a/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp +++ b/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp @@ -145,6 +145,10 @@ TEST_CASE("Fullstate simulator: ZZ measure", "[fullstate_simulator]") Result rOne = iqa->Measure(2, paulis, 2, q); REQUIRE(Result_One == sim->GetResultValue(rOne)); + iqa->X(q[1]); + iqa->ControlledX(1, &q[0], q[1]); + iqa->H(q[0]); + sim->ReleaseQubit(q[0]); sim->ReleaseQubit(q[1]); } @@ -173,6 +177,8 @@ TEST_CASE("Fullstate simulator: assert probability", "[fullstate_simulator]") REQUIRE(!idig->Assert(2, xi, qs, sim->UseZero(), "")); REQUIRE(!idig->Assert(2, xi, qs, sim->UseOne(), "")); + iqa->X(qs[0]); + sim->ReleaseQubit(qs[0]); sim->ReleaseQubit(qs[1]); } @@ -196,6 +202,9 @@ TEST_CASE("Fullstate simulator: toffoli", "[fullstate_simulator]") iqa->ControlledX(2, qs, qs[2]); REQUIRE(Result_One == sim->GetResultValue(MZ(iqa, qs[2]))); + iqa->X(qs[1]); + iqa->X(qs[0]); + for (int i = 0; i < 3; i++) { sim->ReleaseQubit(qs[i]); @@ -307,6 +316,8 @@ TEST_CASE("Fullstate simulator: exponents", "[fullstate_simulator]") PauliId paulis[3] = {PauliId_X, PauliId_Y, PauliId_Z}; iqa->Exp(2, paulis, qs, 0.42); iqa->ControlledExp(2, qs, 3, paulis, &qs[2], 0.17); + iqa->ControlledExp(2, qs, 3, paulis, &qs[2], -0.17); + iqa->Exp(2, paulis, qs, -0.42); // not crashes? consider it passing REQUIRE(true); @@ -377,12 +388,32 @@ TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simu REQUIRE(1.0 == Approx(norm).epsilon(0.0001)); norm = 0.0; + iqa->Y(qs[2]); + iqa->ControlledX(1, &qs[0], qs[1]); + iqa->H(qs[0]); + for (int i = 0; i < n; i++) { sim->ReleaseQubit(qs[i]); } } +extern "C" int Microsoft__Quantum__Testing__QIR__InvalidRelease__Interop(); // NOLINT +TEST_CASE("QIR: Simulator rejects unmeasured, non-zero release", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + QirExecutionContext::Scoped qirctx(sim.get(), true /*trackAllocatedObjects*/); + REQUIRE_THROWS(Microsoft__Quantum__Testing__QIR__InvalidRelease__Interop()); +} + +extern "C" int Microsoft__Quantum__Testing__QIR__MeasureRelease__Interop(); // NOLINT +TEST_CASE("QIR: Simulator accepts measured release", "[fullstate_simulator]") +{ + std::unique_ptr sim = CreateFullstateSimulator(); + QirExecutionContext::Scoped qirctx(sim.get(), true /*trackAllocatedObjects*/); + REQUIRE_NOTHROW(Microsoft__Quantum__Testing__QIR__MeasureRelease__Interop()); +} + extern "C" int Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__Interop(); // NOLINT TEST_CASE("QIR: invoke all standard Q# gates against the fullstate simulator", "[fullstate_simulator]") { diff --git a/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.qs b/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.qs index bb97857e50c..95060828d74 100644 --- a/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.qs +++ b/src/Qir/Tests/FullstateSimulator/qsharp/qir-test-simulator.qs @@ -71,6 +71,7 @@ namespace Microsoft.Quantum.Testing.QIR H(ctls[0]); H(ctls[1]); if (M(targets[0]) != Zero) { set res = 2; } + ResetAll(targets + ctls); } if (res != 0) { return 70 + res; } @@ -79,7 +80,23 @@ namespace Microsoft.Quantum.Testing.QIR H(qs[0]); H(qs[2]); if (Measure([PauliX, PauliZ, PauliX], qs) != Zero) { set res = 80; } + ResetAll(qs); } return res; } + + @EntryPoint() + operation InvalidRelease() : Unit { + use q = Qubit(); + let _ = M(q); + X(q); + } + + @EntryPoint() + operation MeasureRelease() : Unit { + use qs = Qubit[2]; + X(qs[0]); + let _ = Measure([PauliX], [qs[1]]); + let _ = M(qs[0]); + } } diff --git a/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs index aa9a84ff95f..81ecafe51a0 100644 --- a/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs +++ b/src/Qir/Tests/QIR-dynamic/qsharp/qir-test-assert.qs @@ -82,10 +82,13 @@ namespace Microsoft.Quantum.Testing.QIR { AssertMeasurement( [PauliZ], [qubit], Zero, "0: Newly allocated qubit must be in the |0> state."); AssertMeasurementProbability([PauliZ], [qubit], Zero, 1.0, "1: Newly allocated qubit must be in the |0> state.", 1e-10); - X(qubit); // |0> -> |1> - - AssertMeasurement( [PauliZ], [qubit], One, "2: Newly allocated qubit after X() must be in the |1> state."); - AssertMeasurementProbability([PauliZ], [qubit], One, 1.0, "3: Newly allocated qubit after X() must be in the |1> state.", 1e-10); + within { + X(qubit); // |0> -> |1> + } + apply { + AssertMeasurement( [PauliZ], [qubit], One, "2: Newly allocated qubit after X() must be in the |1> state."); + AssertMeasurementProbability([PauliZ], [qubit], One, 1.0, "3: Newly allocated qubit after X() must be in the |1> state.", 1e-10); + } } @EntryPoint() @@ -119,14 +122,18 @@ namespace Microsoft.Quantum.Testing.QIR { } //H(qubit); // Back to |0> let str2 = "Newly allocated qubit after x() followed by H() must be in the |-> state"; - X(qubit); // |1> - H(qubit); // |-> - AssertMeasurement( [PauliX], [qubit], One, str2); - // 50% probability in other Pauli bases: - AssertMeasurementProbability([PauliZ], [qubit], Zero, 0.5, str2, 1e-10); - AssertMeasurementProbability([PauliZ], [qubit], One, 0.5, str2, 1e-10); - AssertMeasurementProbability([PauliY], [qubit], Zero, 0.5, str2, 1e-10); - AssertMeasurementProbability([PauliY], [qubit], One, 0.5, str2, 1e-10); + within { + X(qubit); // |1> + H(qubit); // |-> + } + apply { + AssertMeasurement( [PauliX], [qubit], One, str2); + // 50% probability in other Pauli bases: + AssertMeasurementProbability([PauliZ], [qubit], Zero, 0.5, str2, 1e-10); + AssertMeasurementProbability([PauliZ], [qubit], One, 0.5, str2, 1e-10); + AssertMeasurementProbability([PauliY], [qubit], Zero, 0.5, str2, 1e-10); + AssertMeasurementProbability([PauliY], [qubit], One, 0.5, str2, 1e-10); + } } // (|0> + i|1>) / SQRT(2) = SH|0> = S|+> @@ -146,15 +153,19 @@ namespace Microsoft.Quantum.Testing.QIR { AssertMeasurementProbability([PauliX], [qubit], One, 0.5, "4: Call failed", 1e-10); } // Adjoint S(qubit); // Back to |+> // H(qubit); // Back to |0> - X(qubit); // |1> - H(qubit); // |-> - S(qubit); // (|0> - i|1>) / SQRT(2) - AssertMeasurement( [PauliY], [qubit], One, "5: Call failed"); - // 50% probability in other Pauli bases: - AssertMeasurementProbability([PauliZ], [qubit], Zero, 0.5, "6: Call failed", 1e-10); - AssertMeasurementProbability([PauliZ], [qubit], One, 0.5, "7: Call failed", 1e-10); - AssertMeasurementProbability([PauliX], [qubit], Zero, 0.5, "8: Call failed", 1e-10); - AssertMeasurementProbability([PauliX], [qubit], One, 0.5, "9: Call failed", 1e-10); + within { + X(qubit); // |1> + H(qubit); // |-> + S(qubit); // (|0> - i|1>) / SQRT(2) + } + apply { + AssertMeasurement( [PauliY], [qubit], One, "5: Call failed"); + // 50% probability in other Pauli bases: + AssertMeasurementProbability([PauliZ], [qubit], Zero, 0.5, "6: Call failed", 1e-10); + AssertMeasurementProbability([PauliZ], [qubit], One, 0.5, "7: Call failed", 1e-10); + AssertMeasurementProbability([PauliX], [qubit], Zero, 0.5, "8: Call failed", 1e-10); + AssertMeasurementProbability([PauliX], [qubit], One, 0.5, "9: Call failed", 1e-10); + } } @@ -212,6 +223,9 @@ namespace Microsoft.Quantum.Testing.QIR { AssertMeasurementProbability([PauliZ, PauliZ], [left, right], One, 0.5, "I: Call failed", 1E-05); AssertMeasurementProbability([PauliY, PauliY], [left, right], Zero, 0.5, "J: Call failed", 1E-05); AssertMeasurementProbability([PauliY, PauliY], [left, right], One, 0.5, "K: Call failed", 1E-05); + + Reset(right); + Reset(left); } // Task 3. |0000>+|1111> or |0011>+|1100> ? @@ -236,6 +250,8 @@ namespace Microsoft.Quantum.Testing.QIR { AssertMeasurementProbability([PauliZ, PauliZ], [qubitIds[0], qubitIds[1]], Zero, 1.0, "3: Call failed", 1E-05); // |00> or |11> AssertMeasurementProbability([PauliZ, PauliZ], [qubitIds[1], qubitIds[2]], One, 1.0, "4: Call failed", 1E-05); // |01> or |10> AssertMeasurementProbability([PauliZ, PauliZ], [qubitIds[2], qubitIds[3]], Zero, 1.0, "5: Call failed", 1E-05); // |00> or |11> + + ResetAll(qubitIds); } // Bell states (superposition of |00> and |11>, `(|10> + |01>) / SQRT(2)`): @@ -305,6 +321,9 @@ namespace Microsoft.Quantum.Testing.QIR { AssertMeasurement( [PauliX, PauliZ], [left, right], Zero, "Error: Measuring (|0+> + |1->)/SQRT(2) must return Zero in 𝑋𝑍-basis" ); AssertMeasurementProbability([PauliX, PauliZ], [left, right], Zero, 1.0, "Error: Measuring (|0+> + |1->)/SQRT(2) must return Zero always in 𝑋𝑍-basis", 1E-05); AssertMeasurementProbability([PauliX, PauliZ], [left, right], One, 0.0, "Error: Measuring (|0+> + |1->)/SQRT(2) must not return One in 𝑋𝑍-basis" , 1E-05); + + Reset(right); + Reset(left); } diff --git a/src/Simulation/Native/src/simulator/capi.cpp b/src/Simulation/Native/src/simulator/capi.cpp index da95a1754d2..e8dff5d9104 100644 --- a/src/Simulation/Native/src/simulator/capi.cpp +++ b/src/Simulation/Native/src/simulator/capi.cpp @@ -69,9 +69,9 @@ extern "C" Microsoft::Quantum::Simulator::get(id)->allocateQubit(q); } - MICROSOFT_QUANTUM_DECL void release(_In_ unsigned id, _In_ unsigned q) + MICROSOFT_QUANTUM_DECL bool release(_In_ unsigned id, _In_ unsigned q) { - Microsoft::Quantum::Simulator::get(id)->release(q); + return Microsoft::Quantum::Simulator::get(id)->release(q); } MICROSOFT_QUANTUM_DECL unsigned num_qubits(_In_ unsigned id) diff --git a/src/Simulation/Native/src/simulator/capi.hpp b/src/Simulation/Native/src/simulator/capi.hpp index e0d4b25d0c6..2c33478b56b 100644 --- a/src/Simulation/Native/src/simulator/capi.hpp +++ b/src/Simulation/Native/src/simulator/capi.hpp @@ -70,7 +70,7 @@ extern "C" // allocate and release MICROSOFT_QUANTUM_DECL void allocateQubit(_In_ unsigned sid, _In_ unsigned qid); // NOLINT - MICROSOFT_QUANTUM_DECL void release(_In_ unsigned sid, _In_ unsigned q); // NOLINT + MICROSOFT_QUANTUM_DECL bool release(_In_ unsigned sid, _In_ unsigned q); // NOLINT MICROSOFT_QUANTUM_DECL unsigned num_qubits(_In_ unsigned sid); // NOLINT // single-qubit gates diff --git a/src/Simulation/Native/src/simulator/simulator.hpp b/src/Simulation/Native/src/simulator/simulator.hpp index 2a4dc555def..7dca3718c02 100644 --- a/src/Simulation/Native/src/simulator/simulator.hpp +++ b/src/Simulation/Native/src/simulator/simulator.hpp @@ -32,7 +32,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface std::size_t random(std::vector const& d) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); std::discrete_distribution dist(d.begin(), d.end()); return dist(psi.rng()); } @@ -40,7 +40,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface std::size_t random(std::size_t n, double* d) { std::discrete_distribution dist(d, d + n); - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); return dist(psi.rng()); } @@ -52,7 +52,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface return 0.0; } - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); changebasis(bs, qs, true); double p = psi.jointprobability(qs); changebasis(bs, qs, false); @@ -61,20 +61,20 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool InjectState(const std::vector& qubits, const std::vector& amplitudes) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); return psi.inject_state(qubits, amplitudes); } bool isclassical(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); return psi.isclassical(q); } // allocate and release logical_qubit_id allocate() { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); return psi.allocate_qubit(); } @@ -82,7 +82,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface { std::vector qubits; qubits.reserve(n); - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); for (unsigned i = 0; i < n; ++i) { @@ -93,20 +93,20 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void allocateQubit(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); psi.allocate_qubit(q); } void allocateQubit(std::vector const& qubits) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); for (auto q : qubits) psi.allocate_qubit(q); } bool release(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); flush(); bool allok = isclassical(q); if (allok) @@ -119,7 +119,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool release(std::vector const& qs) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); bool allok = true; for (auto q : qs) allok = release(q) && allok; @@ -131,19 +131,19 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface #define GATE1IMPL(OP) \ void OP(logical_qubit_id q) \ { \ - recursive_lock_type l(mutex()); \ + recursive_lock_type l(getmutex()); \ psi.apply(Gates::OP(q)); \ } #define GATE1CIMPL(OP) \ void C##OP(logical_qubit_id c, logical_qubit_id q) \ { \ - recursive_lock_type l(mutex()); \ + recursive_lock_type l(getmutex()); \ psi.apply_controlled(c, Gates::OP(q)); \ } #define GATE1MCIMPL(OP) \ void C##OP(std::vector const& c, logical_qubit_id q) \ { \ - recursive_lock_type l(mutex()); \ + recursive_lock_type l(getmutex()); \ psi.apply_controlled(c, Gates::OP(q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -167,19 +167,19 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface #define GATE1IMPL(OP) \ void OP(double phi, logical_qubit_id q) \ { \ - recursive_lock_type l(mutex()); \ + recursive_lock_type l(getmutex()); \ psi.apply(Gates::OP(phi, q)); \ } #define GATE1CIMPL(OP) \ void C##OP(double phi, logical_qubit_id c, logical_qubit_id q) \ { \ - recursive_lock_type l(mutex()); \ + recursive_lock_type l(getmutex()); \ psi.apply_controlled(c, Gates::OP(phi, q)); \ } #define GATE1MCIMPL(OP) \ void C##OP(double phi, std::vector const& c, logical_qubit_id q) \ { \ - recursive_lock_type l(mutex()); \ + recursive_lock_type l(getmutex()); \ psi.apply_controlled(c, Gates::OP(phi, q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -196,14 +196,14 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface // rotations void R(Gates::Basis b, double phi, logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); psi.apply(Gates::R(b, phi, q)); } // multi-controlled rotations void CR(Gates::Basis b, double phi, std::vector const& c, logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); psi.apply_controlled(c, Gates::R(b, phi, q)); } @@ -219,7 +219,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface logical_qubit_id somequbit = qs.front(); removeIdentities(bs, qs); - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); if (bs.size() == 0) CR(Gates::PauliI, -2. * phi, cs, somequbit); else if (bs.size() == 1) @@ -230,7 +230,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void Exp(std::vector const& bs, double phi, std::vector const& qs) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); CExp(bs, phi, std::vector(), qs); } @@ -238,14 +238,14 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool M(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); return psi.measure(q); } std::vector MultiM(std::vector const& qs) { // ***TODO*** optimized implementation - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); std::vector res; for (auto q : qs) res.push_back(psi.measure(q)); @@ -254,7 +254,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool Measure(std::vector bs, std::vector qs) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); removeIdentities(bs, qs); // ***TODO*** optimized kernels changebasis(bs, qs, true); @@ -265,34 +265,34 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void seed(unsigned s) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); psi.seed(s); } void reset() { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); psi.reset(); } unsigned num_qubits() const { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); return psi.num_qubits(); } void flush() { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); psi.flush(); } ComplexType const* data() const { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); return psi.data().data(); } void dump(bool (*callback)(size_t, double, double)) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); flush(); auto wfn = psi.data(); @@ -315,7 +315,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void dumpIds(void (*callback)(logical_qubit_id)) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); flush(); std::vector qubits = psi.get_qubit_ids(); @@ -381,13 +381,13 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface assert(std::accumulate(test.begin(), test.end(), 0u) == table_size); #endif - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); psi.permute_basis(qs, table_size, permutation_table, adjoint); } bool subsytemwavefunction(std::vector const& qs, WavefunctionStorage& qubitswfn, double tolerance) { - recursive_lock_type l(mutex()); + recursive_lock_type l(getmutex()); flush(); return psi.subsytemwavefunction(qs, qubitswfn, tolerance); } diff --git a/src/Simulation/Native/src/simulator/simulatorinterface.hpp b/src/Simulation/Native/src/simulator/simulatorinterface.hpp index 6d3bff907b9..7a85d65aef6 100644 --- a/src/Simulation/Native/src/simulator/simulatorinterface.hpp +++ b/src/Simulation/Native/src/simulator/simulatorinterface.hpp @@ -124,7 +124,7 @@ class SimulatorInterface throw std::runtime_error("this simulator does not support permutation oracle emulation"); }; - recursive_mutex_type& mutex() const + recursive_mutex_type& getmutex() const { return *mutex_ptr; } From e311ef42067649283d656d4492a9f4e4d639b5f6 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 16 Aug 2021 20:37:36 -0700 Subject: [PATCH 2/3] CR feedback --- .../lib/Simulators/FullstateSimulator.cpp | 71 ++++++++++--------- src/Simulation/Native/src/simulator/capi.cpp | 2 + 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp index 68f1fd4ac88..61797ceb832 100644 --- a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp +++ b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp @@ -165,14 +165,14 @@ namespace Quantum return proc; } - void UnmarkSingleQubit(Qubit q) + void UnmarkAsMeasuredSingleQubit(Qubit q) { isMeasured[GetQubitId(q)] = false; } - void UnmarkQubitList(long num, Qubit* qubit) + void UnmarkAsMeasuredQubitList(long num, Qubit* qubit) { - for (const auto& id : GetQubitIds(num ,qubit)) + for (const auto& id : GetQubitIds(num, qubit)) { isMeasured[id] = false; } @@ -250,9 +250,12 @@ namespace Quantum auto id = GetQubitId(q); if (!releaseQubit(this->simulatorId, id) && !isMeasured[id]) { + // We reject the release of a qubit that is not in the ground state (releaseQubit returns false), + // and was not recently measured (ie: the last operation was not measurement). This means the + // state is not well known, and therefore the safety of release is not guaranteed. quantum__rt__fail_cstr("Released qubit neither measured nor in ground state."); } - qubitManager->Release(q); // Release it in the qubit manager. + qubitManager->Release(q); // Release it in the qubit manager. } Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override @@ -300,7 +303,7 @@ namespace Quantum { static TSingleQubitGate op = reinterpret_cast(this->GetProc("X")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledX(long numControls, Qubit controls[], Qubit target) override @@ -308,15 +311,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCX")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void Y(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("Y")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledY(long numControls, Qubit controls[], Qubit target) override @@ -324,15 +327,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCY")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void Z(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("Z")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledZ(long numControls, Qubit controls[], Qubit target) override @@ -340,15 +343,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCZ")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void H(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("H")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledH(long numControls, Qubit controls[], Qubit target) override @@ -356,15 +359,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCH")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void S(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("S")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledS(long numControls, Qubit controls[], Qubit target) override @@ -372,15 +375,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCS")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void AdjointS(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("AdjS")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledAdjointS(long numControls, Qubit controls[], Qubit target) override @@ -389,15 +392,15 @@ namespace Quantum reinterpret_cast(this->GetProc("MCAdjS")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void T(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("T")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledT(long numControls, Qubit controls[], Qubit target) override @@ -405,15 +408,15 @@ namespace Quantum static TSingleQubitControlledGate op = reinterpret_cast(this->GetProc("MCT")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void AdjointT(Qubit q) override { static TSingleQubitGate op = reinterpret_cast(this->GetProc("AdjT")); op(this->simulatorId, GetQubitId(q)); - UnmarkSingleQubit(q); + UnmarkAsMeasuredSingleQubit(q); } void ControlledAdjointT(long numControls, Qubit controls[], Qubit target) override @@ -422,8 +425,8 @@ namespace Quantum reinterpret_cast(this->GetProc("MCAdjT")); std::vector ids = GetQubitIds(numControls, controls); op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void R(PauliId axis, Qubit target, double theta) override @@ -432,7 +435,7 @@ namespace Quantum static TR r = reinterpret_cast(this->GetProc("R")); r(this->simulatorId, GetBasis(axis), theta, GetQubitId(target)); - UnmarkSingleQubit(target); + UnmarkAsMeasuredSingleQubit(target); } void ControlledR(long numControls, Qubit controls[], PauliId axis, Qubit target, double theta) override @@ -442,8 +445,8 @@ namespace Quantum std::vector ids = GetQubitIds(numControls, controls); cr(this->simulatorId, GetBasis(axis), theta, (unsigned)numControls, ids.data(), GetQubitId(target)); - UnmarkSingleQubit(target); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredSingleQubit(target); + UnmarkAsMeasuredQubitList(numControls, controls); } void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) override @@ -452,7 +455,7 @@ namespace Quantum static TExp exp = reinterpret_cast(this->GetProc("Exp")); std::vector ids = GetQubitIds(numTargets, targets); exp(this->simulatorId, (unsigned)numTargets, reinterpret_cast(paulis), theta, ids.data()); - UnmarkQubitList(numTargets, targets); + UnmarkAsMeasuredQubitList(numTargets, targets); } void ControlledExp(long numControls, Qubit controls[], long numTargets, PauliId paulis[], Qubit targets[], @@ -464,8 +467,8 @@ namespace Quantum std::vector idsControls = GetQubitIds(numControls, controls); cexp(this->simulatorId, (unsigned)numTargets, reinterpret_cast(paulis), theta, (unsigned)numControls, idsControls.data(), idsTargets.data()); - UnmarkQubitList(numTargets, targets); - UnmarkQubitList(numControls, controls); + UnmarkAsMeasuredQubitList(numTargets, targets); + UnmarkAsMeasuredQubitList(numControls, controls); } bool Assert(long numTargets, PauliId* bases, Qubit* targets, Result result, const char* failureMessage) override diff --git a/src/Simulation/Native/src/simulator/capi.cpp b/src/Simulation/Native/src/simulator/capi.cpp index e8dff5d9104..827351f2ee1 100644 --- a/src/Simulation/Native/src/simulator/capi.cpp +++ b/src/Simulation/Native/src/simulator/capi.cpp @@ -71,6 +71,8 @@ extern "C" MICROSOFT_QUANTUM_DECL bool release(_In_ unsigned id, _In_ unsigned q) { + // The underlying simulator function will return True if and only if the qubit being released + // was in the ground state prior to release. return Microsoft::Quantum::Simulator::get(id)->release(q); } From 6293c7112d59eeaa60324a9e2884478868ed9bb8 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 16 Aug 2021 20:37:49 -0700 Subject: [PATCH 3/3] Revert mutex change --- .../Native/src/simulator/simulator.hpp | 66 +++++++++---------- .../src/simulator/simulatorinterface.hpp | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Simulation/Native/src/simulator/simulator.hpp b/src/Simulation/Native/src/simulator/simulator.hpp index 7dca3718c02..2a4dc555def 100644 --- a/src/Simulation/Native/src/simulator/simulator.hpp +++ b/src/Simulation/Native/src/simulator/simulator.hpp @@ -32,7 +32,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface std::size_t random(std::vector const& d) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); std::discrete_distribution dist(d.begin(), d.end()); return dist(psi.rng()); } @@ -40,7 +40,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface std::size_t random(std::size_t n, double* d) { std::discrete_distribution dist(d, d + n); - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); return dist(psi.rng()); } @@ -52,7 +52,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface return 0.0; } - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); changebasis(bs, qs, true); double p = psi.jointprobability(qs); changebasis(bs, qs, false); @@ -61,20 +61,20 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool InjectState(const std::vector& qubits, const std::vector& amplitudes) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); return psi.inject_state(qubits, amplitudes); } bool isclassical(logical_qubit_id q) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); return psi.isclassical(q); } // allocate and release logical_qubit_id allocate() { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); return psi.allocate_qubit(); } @@ -82,7 +82,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface { std::vector qubits; qubits.reserve(n); - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); for (unsigned i = 0; i < n; ++i) { @@ -93,20 +93,20 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void allocateQubit(logical_qubit_id q) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); psi.allocate_qubit(q); } void allocateQubit(std::vector const& qubits) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); for (auto q : qubits) psi.allocate_qubit(q); } bool release(logical_qubit_id q) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); flush(); bool allok = isclassical(q); if (allok) @@ -119,7 +119,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool release(std::vector const& qs) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); bool allok = true; for (auto q : qs) allok = release(q) && allok; @@ -131,19 +131,19 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface #define GATE1IMPL(OP) \ void OP(logical_qubit_id q) \ { \ - recursive_lock_type l(getmutex()); \ + recursive_lock_type l(mutex()); \ psi.apply(Gates::OP(q)); \ } #define GATE1CIMPL(OP) \ void C##OP(logical_qubit_id c, logical_qubit_id q) \ { \ - recursive_lock_type l(getmutex()); \ + recursive_lock_type l(mutex()); \ psi.apply_controlled(c, Gates::OP(q)); \ } #define GATE1MCIMPL(OP) \ void C##OP(std::vector const& c, logical_qubit_id q) \ { \ - recursive_lock_type l(getmutex()); \ + recursive_lock_type l(mutex()); \ psi.apply_controlled(c, Gates::OP(q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -167,19 +167,19 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface #define GATE1IMPL(OP) \ void OP(double phi, logical_qubit_id q) \ { \ - recursive_lock_type l(getmutex()); \ + recursive_lock_type l(mutex()); \ psi.apply(Gates::OP(phi, q)); \ } #define GATE1CIMPL(OP) \ void C##OP(double phi, logical_qubit_id c, logical_qubit_id q) \ { \ - recursive_lock_type l(getmutex()); \ + recursive_lock_type l(mutex()); \ psi.apply_controlled(c, Gates::OP(phi, q)); \ } #define GATE1MCIMPL(OP) \ void C##OP(double phi, std::vector const& c, logical_qubit_id q) \ { \ - recursive_lock_type l(getmutex()); \ + recursive_lock_type l(mutex()); \ psi.apply_controlled(c, Gates::OP(phi, q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -196,14 +196,14 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface // rotations void R(Gates::Basis b, double phi, logical_qubit_id q) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); psi.apply(Gates::R(b, phi, q)); } // multi-controlled rotations void CR(Gates::Basis b, double phi, std::vector const& c, logical_qubit_id q) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); psi.apply_controlled(c, Gates::R(b, phi, q)); } @@ -219,7 +219,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface logical_qubit_id somequbit = qs.front(); removeIdentities(bs, qs); - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); if (bs.size() == 0) CR(Gates::PauliI, -2. * phi, cs, somequbit); else if (bs.size() == 1) @@ -230,7 +230,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void Exp(std::vector const& bs, double phi, std::vector const& qs) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); CExp(bs, phi, std::vector(), qs); } @@ -238,14 +238,14 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool M(logical_qubit_id q) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); return psi.measure(q); } std::vector MultiM(std::vector const& qs) { // ***TODO*** optimized implementation - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); std::vector res; for (auto q : qs) res.push_back(psi.measure(q)); @@ -254,7 +254,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool Measure(std::vector bs, std::vector qs) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); removeIdentities(bs, qs); // ***TODO*** optimized kernels changebasis(bs, qs, true); @@ -265,34 +265,34 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void seed(unsigned s) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); psi.seed(s); } void reset() { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); psi.reset(); } unsigned num_qubits() const { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); return psi.num_qubits(); } void flush() { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); psi.flush(); } ComplexType const* data() const { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); return psi.data().data(); } void dump(bool (*callback)(size_t, double, double)) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); flush(); auto wfn = psi.data(); @@ -315,7 +315,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void dumpIds(void (*callback)(logical_qubit_id)) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); flush(); std::vector qubits = psi.get_qubit_ids(); @@ -381,13 +381,13 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface assert(std::accumulate(test.begin(), test.end(), 0u) == table_size); #endif - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); psi.permute_basis(qs, table_size, permutation_table, adjoint); } bool subsytemwavefunction(std::vector const& qs, WavefunctionStorage& qubitswfn, double tolerance) { - recursive_lock_type l(getmutex()); + recursive_lock_type l(mutex()); flush(); return psi.subsytemwavefunction(qs, qubitswfn, tolerance); } diff --git a/src/Simulation/Native/src/simulator/simulatorinterface.hpp b/src/Simulation/Native/src/simulator/simulatorinterface.hpp index 7a85d65aef6..6d3bff907b9 100644 --- a/src/Simulation/Native/src/simulator/simulatorinterface.hpp +++ b/src/Simulation/Native/src/simulator/simulatorinterface.hpp @@ -124,7 +124,7 @@ class SimulatorInterface throw std::runtime_error("this simulator does not support permutation oracle emulation"); }; - recursive_mutex_type& getmutex() const + recursive_mutex_type& mutex() const { return *mutex_ptr; }