From fbae09fa5cf67801d4b54677ca3c5ce76827d3e0 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 4 Jun 2021 16:08:52 -0700 Subject: [PATCH 1/6] Update Simulator Release to check for entanglement This change adds a new utility to the full state simulator, `is_classical_or_entangled` that returns a pair of bools indicating when the given qubit is classical with regard to the computational basis and whether the qubit is entangled with any other qubits. The former is needed to ensure the state of the qubit is collapsed before release, while the latter is the correct feedback to return from release to indicate whether releasing that qubit had any side effects on other qubits in the wave function. This updates the logic in the C# infrastructure to use the returned bool as the indication of whether or not the release was valid (as opposed to the old check that used a cache of whether or not the last operation on the qubit was a measurement). THIS IS A CHANGE IN BEHAVIOR. Notably, a qubit that is now considered valid for release as long as it is not entangled with any other qubit, regardless of superposition. As a result, the exception name and text for `ReleasedQubitsAreNotInZeroState` is changed to `ReleaseQubitsAreEntangled`. This also fixes QIR simulator should check result of qubit Release #552 by having the FullstateSimulator wrapper in the QIR Runtime check the return value from release and call `quantum__rt__fail_cstr` if the qubit released was entangled. --- .../lib/Simulators/FullstateSimulator.cpp | 8 +- .../FullstateSimulatorTests.cpp | 10 +++ ...State.cs => ReleasedQubitsAreEntangled.cs} | 6 +- src/Simulation/Native/src/simulator/capi.cpp | 4 +- src/Simulation/Native/src/simulator/capi.hpp | 4 +- .../Native/src/simulator/kernels.hpp | 42 ++++++++++ .../Native/src/simulator/local_test.cpp | 78 ++++++++++++++++++- .../Native/src/simulator/simulator.hpp | 14 ++-- .../Native/src/simulator/wavefunction.hpp | 7 ++ .../Circuits/CoreOperations.qs | 4 +- .../QuantumSimulatorTests/QubitReleaseTest.cs | 6 +- .../Simulators.Tests/ToffoliSimulatorTests.cs | 2 +- .../QuantumSimulator/QubitManager.cs | 6 +- .../ToffoliSimulator/ToffoliSimulator.cs | 15 ---- 14 files changed, 167 insertions(+), 39 deletions(-) rename src/Simulation/Common/Exceptions/{ReleasedQubitsAreNotInZeroState.cs => ReleasedQubitsAreEntangled.cs} (64%) diff --git a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp index 6d9103d6779..8d2b93ca3bd 100644 --- a/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp +++ b/src/Qir/Runtime/lib/Simulators/FullstateSimulator.cpp @@ -13,6 +13,7 @@ #include "capi.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" @@ -203,10 +204,13 @@ namespace Quantum 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)); + if (!releaseQubit(this->simulatorId, GetQubitId(q))) + { + quantum__rt__fail_cstr("Released qubits are entangled."); + } } Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override diff --git a/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp b/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp index f9369c87fa6..1c366eeac48 100644 --- a/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp +++ b/src/Qir/Tests/FullstateSimulator/FullstateSimulatorTests.cpp @@ -115,6 +115,9 @@ TEST_CASE("Fullstate simulator: ZZ measure", "[fullstate_simulator]") Result rOne = iqa->Measure(2, paulis, 2, q); REQUIRE(Result_One == sim->GetResultValue(rOne)); + // Disentangle for release. + iqa->ControlledX(1, &q[0], q[1]); + sim->ReleaseQubit(q[0]); sim->ReleaseQubit(q[1]); } @@ -281,6 +284,10 @@ TEST_CASE("Fullstate simulator: exponents", "[fullstate_simulator]") // not crashes? consider it passing REQUIRE(true); + // Disentangle for release. + iqa->ControlledExp(2, qs, 3, paulis, &qs[2], -0.17); + iqa->Exp(2, paulis, qs, -0.42); + for (int i = 0; i < n; i++) { sim->ReleaseQubit(qs[i]); @@ -347,6 +354,9 @@ TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simu REQUIRE(1.0 == Approx(norm).epsilon(0.0001)); norm = 0.0; + // Disentangle to prepare for release. + iqa->ControlledX(1, &qs[0], qs[1]); + for (int i = 0; i < n; i++) { sim->ReleaseQubit(qs[i]); diff --git a/src/Simulation/Common/Exceptions/ReleasedQubitsAreNotInZeroState.cs b/src/Simulation/Common/Exceptions/ReleasedQubitsAreEntangled.cs similarity index 64% rename from src/Simulation/Common/Exceptions/ReleasedQubitsAreNotInZeroState.cs rename to src/Simulation/Common/Exceptions/ReleasedQubitsAreEntangled.cs index 15ee8255d2d..4f379804907 100644 --- a/src/Simulation/Common/Exceptions/ReleasedQubitsAreNotInZeroState.cs +++ b/src/Simulation/Common/Exceptions/ReleasedQubitsAreEntangled.cs @@ -9,10 +9,10 @@ namespace Microsoft.Quantum.Simulation.Simulators.Exceptions { - public class ReleasedQubitsAreNotInZeroState : Exception + public class ReleasedQubitsAreEntangled : Exception { - public ReleasedQubitsAreNotInZeroState() - : base("Released qubits are not in zero state.") + public ReleasedQubitsAreEntangled() + : base("Released qubits are entangled.") { } } 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..87bdf1d4c60 100644 --- a/src/Simulation/Native/src/simulator/capi.hpp +++ b/src/Simulation/Native/src/simulator/capi.hpp @@ -63,14 +63,14 @@ extern "C" MICROSOFT_QUANTUM_DECL bool InjectState( _In_ unsigned sid, _In_ unsigned n, - _In_reads_(n) unsigned* q, // The listed qubits must be unentangled and in state |0> + _In_reads_(n) unsigned* q, // The listed qubits must be disentangled and in state |0> _In_ double* re, // 2^n real parts of the amplitudes of the superposition the listed qubits should be put into _In_ double* im // 2^n imaginary parts of the amplitudes ); // 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/kernels.hpp b/src/Simulation/Native/src/simulator/kernels.hpp index 3311bb27f8c..238a702e279 100644 --- a/src/Simulation/Native/src/simulator/kernels.hpp +++ b/src/Simulation/Native/src/simulator/kernels.hpp @@ -144,6 +144,48 @@ bool isclassical( return true; } +template +std::pair is_classical_or_entangled( + std::vector, A> const& wfn, + std::size_t q, + T eps = 100. * std::numeric_limits::epsilon()) +{ + std::size_t offset = 1ull << q; + bool have0 = false; + bool have1 = false; + bool notentangled = false; + + std::size_t maski = ~(offset - 1); +#ifndef _MSC_VER +#pragma omp parallel for schedule(static) reduction(|| : have0, have1, notentangled) + for (std::intptr_t i = 0; i < static_cast(wfn.size()); i += 2 * offset) + for (std::intptr_t j = 0; j < static_cast(offset); ++j) + { + bool has0 = std::norm(wfn[i + j]) >= eps; + bool has1 = std::norm(wfn[i + j + offset]) >= eps; + have0 = have0 || has0; + have1 = have1 || has1; + if (has0 && has1) + notentangled = notentangled || ((i + j) ^ (i + j + offset)) != 0; + } +#else +#pragma omp parallel for schedule(static) reduction(|| : have0, have1, notentangled) + for (std::intptr_t l = 0; l < static_cast(wfn.size()) / 2; l++) + { + std::intptr_t j = l % offset; + std::intptr_t i = ((l & maski) << 1); + bool has0 = std::norm(wfn[i + j]) >= eps; + bool has1 = std::norm(wfn[i + j + offset]) >= eps; + have0 = have0 || has0; + have1 = have1 || has1; + if (has0 && has1) + notentangled = notentangled || ((i + j) ^ (i + j + offset)) != 0; + } +#endif + + return std::make_pair(have0 ^ have1, have0 && have1 && !notentangled); +} + template double jointprobability(std::vector const& wfn, std::vector const& qs, bool val = true) { diff --git a/src/Simulation/Native/src/simulator/local_test.cpp b/src/Simulation/Native/src/simulator/local_test.cpp index d9641b620ad..35d8e0a66ac 100644 --- a/src/Simulation/Native/src/simulator/local_test.cpp +++ b/src/Simulation/Native/src/simulator/local_test.cpp @@ -569,7 +569,7 @@ TEST_CASE("Should fail to inject state if qubits aren't all |0>", "[local_test]" std::vector amplitudes_sub = {{amp, 0.0}, {amp, 0.0}, {amp, 0.0}, {0.0, 0.0}}; - // unentangled but not |0> + // not entangled but not |0> sim.H(qs[1]); REQUIRE_FALSE(sim.InjectState(qs, amplitudes)); REQUIRE_FALSE(sim.InjectState({qs[0], qs[1]}, amplitudes_sub)); @@ -828,6 +828,82 @@ TEST_CASE("test_multicontrol", "[local_test]") } } +TEST_CASE("test_is_classical_or_entangled", "[local_test]") +{ + SimulatorType sim; + auto qbits = sim.allocate(4); + + CHECK(sim.is_classical_or_entangled(qbits[0]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).second); + CHECK(sim.is_classical_or_entangled(qbits[1]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).second); + CHECK(sim.is_classical_or_entangled(qbits[2]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).second); + + sim.X(qbits[0]); + sim.X(qbits[2]); + CHECK(sim.is_classical_or_entangled(qbits[0]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).second); + CHECK(sim.is_classical_or_entangled(qbits[1]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).second); + CHECK(sim.is_classical_or_entangled(qbits[2]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).second); + + sim.X(qbits[0]); + sim.H(qbits[0]); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).second); + CHECK(sim.is_classical_or_entangled(qbits[1]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).second); + CHECK(sim.is_classical_or_entangled(qbits[2]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).second); + + sim.H(qbits[1]); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).second); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).second); + CHECK(sim.is_classical_or_entangled(qbits[2]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).second); + + sim.H(qbits[1]); + sim.CX(qbits[0], qbits[1]); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).first); + CHECK(sim.is_classical_or_entangled(qbits[0]).second); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).first); + CHECK(sim.is_classical_or_entangled(qbits[1]).second); + CHECK(sim.is_classical_or_entangled(qbits[2]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).second); + + sim.CX(qbits[0], qbits[2]); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).first); + CHECK(sim.is_classical_or_entangled(qbits[0]).second); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).first); + CHECK(sim.is_classical_or_entangled(qbits[1]).second); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).first); + CHECK(sim.is_classical_or_entangled(qbits[2]).second); + + sim.CX(qbits[0], qbits[1]); + sim.CX(qbits[0], qbits[2]); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).second); + CHECK(sim.is_classical_or_entangled(qbits[1]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).second); + CHECK(sim.is_classical_or_entangled(qbits[2]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).second); + + sim.H(qbits[0]); + CHECK(sim.is_classical_or_entangled(qbits[0]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[0]).second); + CHECK(sim.is_classical_or_entangled(qbits[1]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[1]).second); + CHECK(sim.is_classical_or_entangled(qbits[2]).first); + CHECK_FALSE(sim.is_classical_or_entangled(qbits[2]).second); + + sim.release(qbits); + CHECK(sim.num_qubits() == 0); +} + void test_extract_qubits_state_simple(int qubits_number) { SimulatorType sim; diff --git a/src/Simulation/Native/src/simulator/simulator.hpp b/src/Simulation/Native/src/simulator/simulator.hpp index 2a4dc555def..10b68930813 100644 --- a/src/Simulation/Native/src/simulator/simulator.hpp +++ b/src/Simulation/Native/src/simulator/simulator.hpp @@ -71,6 +71,12 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface return psi.isclassical(q); } + std::pair is_classical_or_entangled(logical_qubit_id q) + { + recursive_lock_type l(mutex()); + return psi.is_classical_or_entangled(q); + } + // allocate and release logical_qubit_id allocate() { @@ -108,13 +114,11 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface { recursive_lock_type l(mutex()); flush(); - bool allok = isclassical(q); - if (allok) - allok = (psi.getvalue(q) == false); - else + std::pair allok = is_classical_or_entangled(q); + if (!allok.first) M(q); psi.release(q); - return allok; + return !allok.second; } bool release(std::vector const& qs) diff --git a/src/Simulation/Native/src/simulator/wavefunction.hpp b/src/Simulation/Native/src/simulator/wavefunction.hpp index 4ff2b68c07a..f9179f975a2 100644 --- a/src/Simulation/Native/src/simulator/wavefunction.hpp +++ b/src/Simulation/Native/src/simulator/wavefunction.hpp @@ -672,6 +672,13 @@ class Wavefunction return kernels::isclassical(wfn_, get_qubit_position(q)); } + /// checks both if the qubit is in classical state or entangled with any other qubits + std::pair is_classical_or_entangled(logical_qubit_id q) const + { + flush(); + return kernels::is_classical_or_entangled(wfn_, get_qubit_position(q)); + } + /// returns the classical value of a qubit (if classical) /// \pre the qubit has to be in a classical state in the computational basis bool getvalue(logical_qubit_id q) const diff --git a/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs b/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs index 12d4e4dec65..5eacfcd4122 100644 --- a/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs +++ b/src/Simulation/Simulators.Tests/Circuits/CoreOperations.qs @@ -546,7 +546,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { using (q = Qubit()) { X(q); - // Should raise an exception + // Should not raise an exception } } @@ -581,7 +581,7 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests.Circuits { borrowing (q = Qubit()) { X(q); - // Should raise an exception + // Should not raise an exception } } diff --git a/src/Simulation/Simulators.Tests/QuantumSimulatorTests/QubitReleaseTest.cs b/src/Simulation/Simulators.Tests/QuantumSimulatorTests/QubitReleaseTest.cs index 3e2d78ddf7d..f11099d9a51 100644 --- a/src/Simulation/Simulators.Tests/QuantumSimulatorTests/QubitReleaseTest.cs +++ b/src/Simulation/Simulators.Tests/QuantumSimulatorTests/QubitReleaseTest.cs @@ -14,13 +14,13 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests { public partial class QuantumSimulatorTests { - //test to check that qubit cannot be released if it is not in zero state + //test to check that qubit can be released if it is not entangled [Fact] public async Task ZeroStateQubitReleaseTest() { var sim = new QuantumSimulator(); - await Assert.ThrowsAsync(() => UsingQubitCheck.Run(sim)); + await UsingQubitCheck.Run(sim); } //test to check that qubit can be released if measured @@ -39,7 +39,7 @@ public async Task MeasuredMultipleQubitsReleaseTest() { var sim = new QuantumSimulator(); - await Assert.ThrowsAsync(() => ReleaseMeasureMultipleQubitCheck.Run(sim)); + await Assert.ThrowsAsync(() => ReleaseMeasureMultipleQubitCheck.Run(sim)); } //test to check that qubit that is released and reallocated is in state |0> diff --git a/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs b/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs index ec72438eb1c..aa27afaf437 100644 --- a/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs +++ b/src/Simulation/Simulators.Tests/ToffoliSimulatorTests.cs @@ -165,7 +165,7 @@ public async Task ToffoliUsingCheck() { var sim = new ToffoliSimulator(); - await Assert.ThrowsAsync(() => UsingQubitCheck.Run(sim)); + await UsingQubitCheck.Run(sim); } [Fact] diff --git a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs index b1bcc7b09fa..7936726331e 100644 --- a/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs +++ b/src/Simulation/Simulators/QuantumSimulator/QubitManager.cs @@ -56,10 +56,10 @@ protected override void Release(Qubit qubit, bool wasUsedOnlyForBorrowing) base.Release(qubit, wasUsedOnlyForBorrowing); if (qubit != null) { - bool isReleasedQubitZero = ReleaseOne(this.SimulatorId, (uint)qubit.Id); - if (!(isReleasedQubitZero || qubit.IsMeasured) && throwOnReleasingQubitsNotInZeroState) + bool isReleasedQubitEntangled = !ReleaseOne(this.SimulatorId, (uint)qubit.Id); + if (isReleasedQubitEntangled && throwOnReleasingQubitsNotInZeroState) { - throw new ReleasedQubitsAreNotInZeroState(); + throw new ReleasedQubitsAreEntangled(); } } } diff --git a/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs b/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs index 3f5c95fb88b..d430b3f7bdf 100644 --- a/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs +++ b/src/Simulation/Simulators/ToffoliSimulator/ToffoliSimulator.cs @@ -390,10 +390,6 @@ public TSRelease(ToffoliSimulator m) : base(m) /// The qubit to release. public override void Apply(Qubit q) { - if (simulator.State[q.Id]) - { - throw new ReleasedQubitsAreNotInZeroState(); - } manager.Release(q); } @@ -403,17 +399,6 @@ public override void Apply(Qubit q) /// The qubits to release. public override void Apply(IQArray qubits) { - // Note that we need to handle null array pointers (as opposed to empty arrays) - if (qubits != null) - { - foreach (var q in qubits) - { - if (simulator.State[q.Id]) - { - throw new ReleasedQubitsAreNotInZeroState(); - } - } - } manager.Release(qubits); } } From f4591ccac95ccfda270b92fb7a5190360063c494 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 4 Jun 2021 21:56:45 -0700 Subject: [PATCH 2/6] Bring back old exception as deprecated --- .../ReleasedQubitsAreNotInZeroState.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/Simulation/Common/Exceptions/ReleasedQubitsAreNotInZeroState.cs diff --git a/src/Simulation/Common/Exceptions/ReleasedQubitsAreNotInZeroState.cs b/src/Simulation/Common/Exceptions/ReleasedQubitsAreNotInZeroState.cs new file mode 100644 index 00000000000..f0e91e70bd1 --- /dev/null +++ b/src/Simulation/Common/Exceptions/ReleasedQubitsAreNotInZeroState.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Quantum.Simulation.Simulators.Exceptions +{ + [Obsolete("This class is deprecated and will be removed in a future release.")] + public class ReleasedQubitsAreNotInZeroState : Exception + { + public ReleasedQubitsAreNotInZeroState() + : base("Released qubits are not in zero state.") + { + } + } +} From 15ac878d74b3739624bed90bdecd5f0264d32a82 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sat, 5 Jun 2021 06:59:21 -0700 Subject: [PATCH 3/6] Simplify entanglement check --- src/Simulation/Native/src/simulator/kernels.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Simulation/Native/src/simulator/kernels.hpp b/src/Simulation/Native/src/simulator/kernels.hpp index 238a702e279..061ad9673df 100644 --- a/src/Simulation/Native/src/simulator/kernels.hpp +++ b/src/Simulation/Native/src/simulator/kernels.hpp @@ -165,8 +165,7 @@ std::pair is_classical_or_entangled( bool has1 = std::norm(wfn[i + j + offset]) >= eps; have0 = have0 || has0; have1 = have1 || has1; - if (has0 && has1) - notentangled = notentangled || ((i + j) ^ (i + j + offset)) != 0; + notentangled = notentangled || (has0 && has1); } #else #pragma omp parallel for schedule(static) reduction(|| : have0, have1, notentangled) @@ -178,8 +177,7 @@ std::pair is_classical_or_entangled( bool has1 = std::norm(wfn[i + j + offset]) >= eps; have0 = have0 || has0; have1 = have1 || has1; - if (has0 && has1) - notentangled = notentangled || ((i + j) ^ (i + j + offset)) != 0; + notentangled = notentangled || (has0 && has1); } #endif From 9063bc4542847e24072f6a8bb6ea0c11d7037e46 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sat, 5 Jun 2021 22:48:49 -0700 Subject: [PATCH 4/6] Updates for PR feedback --- .../Native/src/simulator/kernels.hpp | 17 +++++ .../Native/src/simulator/simulator.hpp | 68 +++++++++---------- 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/Simulation/Native/src/simulator/kernels.hpp b/src/Simulation/Native/src/simulator/kernels.hpp index 061ad9673df..dfba8fe1dbd 100644 --- a/src/Simulation/Native/src/simulator/kernels.hpp +++ b/src/Simulation/Native/src/simulator/kernels.hpp @@ -150,12 +150,26 @@ std::pair is_classical_or_entangled( std::size_t q, T eps = 100. * std::numeric_limits::epsilon()) { + // Iterate through the wave function using offstet and mask to check for both whether the qubit + // is classical (in the |0⟩ or |1⟩ state) or is entangled with any other qubit. By checking states + // where the target qubit is the only difference, the "isclassical" check can speed up the iteration + // which must check the whole vector. If the target qubit has a nonzero probability of being measured + // as |0⟩ (variable "have0") AND nonzero probability of being measured as |1⟩ (variable "have1") then + // we know it is not classical with regard to the computational basis. Further, if the target qubit + // is not classical with regard to the computational basis AND all two states where the only difference + // in the states is the target qubit (ie: |101⟩ and |100⟩ for qubit 0) have nonzero probability, then + // the qubit cannot be entangled. std::size_t offset = 1ull << q; bool have0 = false; bool have1 = false; bool notentangled = false; std::size_t maski = ~(offset - 1); + // When iterating below, the entry in the wave function with index `i + j` and the entry with index + // `i + j + offset` represent two states where the only difference is the measured value of the target + // qubit. For example, if the target qubit has id 2 (offset = 4) in wave function of size 4, then for + // i = 0 and j = 0 the two states checked are 0 and 4, or |0000⟩ and |0100⟩. When i = 8 and j = 1, the + // two states are 9 and 13, or |1001⟩ and |1101⟩. #ifndef _MSC_VER #pragma omp parallel for schedule(static) reduction(|| : have0, have1, notentangled) for (std::intptr_t i = 0; i < static_cast(wfn.size()); i += 2 * offset) @@ -181,6 +195,9 @@ std::pair is_classical_or_entangled( } #endif + // isclassical = true IFF have0 XOR have1 + // isentangled = true IFF have0 AND have1 AND for any pair of states where only the target qubit + // differs one of those states has zero probability. return std::make_pair(have0 ^ have1, have0 && have1 && !notentangled); } diff --git a/src/Simulation/Native/src/simulator/simulator.hpp b/src/Simulation/Native/src/simulator/simulator.hpp index 10b68930813..5e5ba51117a 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(this->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(mutex()); + recursive_lock_type l(this->mutex()); 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(this->mutex()); changebasis(bs, qs, true); double p = psi.jointprobability(qs); changebasis(bs, qs, false); @@ -61,26 +61,26 @@ 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(this->mutex()); return psi.inject_state(qubits, amplitudes); } bool isclassical(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); return psi.isclassical(q); } std::pair is_classical_or_entangled(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); return psi.is_classical_or_entangled(q); } // allocate and release logical_qubit_id allocate() { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); return psi.allocate_qubit(); } @@ -88,7 +88,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface { std::vector qubits; qubits.reserve(n); - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); for (unsigned i = 0; i < n; ++i) { @@ -99,20 +99,20 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void allocateQubit(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); psi.allocate_qubit(q); } void allocateQubit(std::vector const& qubits) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); for (auto q : qubits) psi.allocate_qubit(q); } bool release(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); flush(); std::pair allok = is_classical_or_entangled(q); if (!allok.first) @@ -123,7 +123,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool release(std::vector const& qs) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); bool allok = true; for (auto q : qs) allok = release(q) && allok; @@ -135,19 +135,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(this->mutex()); \ 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(this->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(mutex()); \ + recursive_lock_type l(this->mutex()); \ psi.apply_controlled(c, Gates::OP(q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -171,19 +171,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(this->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(mutex()); \ + recursive_lock_type l(this->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(mutex()); \ + recursive_lock_type l(this->mutex()); \ psi.apply_controlled(c, Gates::OP(phi, q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -200,14 +200,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(this->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(mutex()); + recursive_lock_type l(this->mutex()); psi.apply_controlled(c, Gates::R(b, phi, q)); } @@ -223,7 +223,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(this->mutex()); if (bs.size() == 0) CR(Gates::PauliI, -2. * phi, cs, somequbit); else if (bs.size() == 1) @@ -234,7 +234,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(this->mutex()); CExp(bs, phi, std::vector(), qs); } @@ -242,14 +242,14 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool M(logical_qubit_id q) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); return psi.measure(q); } std::vector MultiM(std::vector const& qs) { // ***TODO*** optimized implementation - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); std::vector res; for (auto q : qs) res.push_back(psi.measure(q)); @@ -258,7 +258,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(this->mutex()); removeIdentities(bs, qs); // ***TODO*** optimized kernels changebasis(bs, qs, true); @@ -269,34 +269,34 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void seed(unsigned s) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); psi.seed(s); } void reset() { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); psi.reset(); } unsigned num_qubits() const { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); return psi.num_qubits(); } void flush() { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); psi.flush(); } ComplexType const* data() const { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); return psi.data().data(); } void dump(bool (*callback)(size_t, double, double)) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); flush(); auto wfn = psi.data(); @@ -319,7 +319,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void dumpIds(void (*callback)(logical_qubit_id)) { - recursive_lock_type l(mutex()); + recursive_lock_type l(this->mutex()); flush(); std::vector qubits = psi.get_qubit_ids(); @@ -385,13 +385,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(this->mutex()); 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(this->mutex()); flush(); return psi.subsytemwavefunction(qs, qubitswfn, tolerance); } From 0f467c62a7ea867df05b07401bd2d06bb850f16e Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sat, 5 Jun 2021 22:56:48 -0700 Subject: [PATCH 5/6] Fix explanation in comment --- src/Simulation/Native/src/simulator/kernels.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Simulation/Native/src/simulator/kernels.hpp b/src/Simulation/Native/src/simulator/kernels.hpp index dfba8fe1dbd..6172a7c0a23 100644 --- a/src/Simulation/Native/src/simulator/kernels.hpp +++ b/src/Simulation/Native/src/simulator/kernels.hpp @@ -156,8 +156,8 @@ std::pair is_classical_or_entangled( // which must check the whole vector. If the target qubit has a nonzero probability of being measured // as |0⟩ (variable "have0") AND nonzero probability of being measured as |1⟩ (variable "have1") then // we know it is not classical with regard to the computational basis. Further, if the target qubit - // is not classical with regard to the computational basis AND all two states where the only difference - // in the states is the target qubit (ie: |101⟩ and |100⟩ for qubit 0) have nonzero probability, then + // is not classical with regard to the computational basis AND for any two states where the only difference + // in the states is the target qubit (ie: |101⟩ and |100⟩ for qubit 0) those have nonzero probability, then // the qubit cannot be entangled. std::size_t offset = 1ull << q; bool have0 = false; @@ -196,7 +196,7 @@ std::pair is_classical_or_entangled( #endif // isclassical = true IFF have0 XOR have1 - // isentangled = true IFF have0 AND have1 AND for any pair of states where only the target qubit + // isentangled = true IFF have0 AND have1 AND for all pairs of states where only the target qubit // differs one of those states has zero probability. return std::make_pair(have0 ^ have1, have0 && have1 && !notentangled); } From 5c39a218857a5d8e1423f30ad9811e1526611f8d Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 8 Jun 2021 11:44:56 -0700 Subject: [PATCH 6/6] Update name of local mutex function. --- .../Native/src/simulator/simulator.hpp | 68 +++++++++---------- .../src/simulator/simulatorinterface.hpp | 2 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/Simulation/Native/src/simulator/simulator.hpp b/src/Simulation/Native/src/simulator/simulator.hpp index 5e5ba51117a..33313f78abe 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(this->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(this->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(this->mutex()); + recursive_lock_type l(getMutex()); changebasis(bs, qs, true); double p = psi.jointprobability(qs); changebasis(bs, qs, false); @@ -61,26 +61,26 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool InjectState(const std::vector& qubits, const std::vector& amplitudes) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); return psi.inject_state(qubits, amplitudes); } bool isclassical(logical_qubit_id q) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); return psi.isclassical(q); } std::pair is_classical_or_entangled(logical_qubit_id q) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); return psi.is_classical_or_entangled(q); } // allocate and release logical_qubit_id allocate() { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); return psi.allocate_qubit(); } @@ -88,7 +88,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface { std::vector qubits; qubits.reserve(n); - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); for (unsigned i = 0; i < n; ++i) { @@ -99,20 +99,20 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void allocateQubit(logical_qubit_id q) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); psi.allocate_qubit(q); } void allocateQubit(std::vector const& qubits) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); for (auto q : qubits) psi.allocate_qubit(q); } bool release(logical_qubit_id q) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); flush(); std::pair allok = is_classical_or_entangled(q); if (!allok.first) @@ -123,7 +123,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool release(std::vector const& qs) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); bool allok = true; for (auto q : qs) allok = release(q) && allok; @@ -135,19 +135,19 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface #define GATE1IMPL(OP) \ void OP(logical_qubit_id q) \ { \ - recursive_lock_type l(this->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(this->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(this->mutex()); \ + recursive_lock_type l(getMutex()); \ psi.apply_controlled(c, Gates::OP(q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -171,19 +171,19 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface #define GATE1IMPL(OP) \ void OP(double phi, logical_qubit_id q) \ { \ - recursive_lock_type l(this->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(this->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(this->mutex()); \ + recursive_lock_type l(getMutex()); \ psi.apply_controlled(c, Gates::OP(phi, q)); \ } #define GATE1(OP) GATE1IMPL(OP) GATE1CIMPL(OP) GATE1MCIMPL(OP) @@ -200,14 +200,14 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface // rotations void R(Gates::Basis b, double phi, logical_qubit_id q) { - recursive_lock_type l(this->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(this->mutex()); + recursive_lock_type l(getMutex()); psi.apply_controlled(c, Gates::R(b, phi, q)); } @@ -223,7 +223,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface logical_qubit_id somequbit = qs.front(); removeIdentities(bs, qs); - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); if (bs.size() == 0) CR(Gates::PauliI, -2. * phi, cs, somequbit); else if (bs.size() == 1) @@ -234,7 +234,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void Exp(std::vector const& bs, double phi, std::vector const& qs) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); CExp(bs, phi, std::vector(), qs); } @@ -242,14 +242,14 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool M(logical_qubit_id q) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); return psi.measure(q); } std::vector MultiM(std::vector const& qs) { // ***TODO*** optimized implementation - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); std::vector res; for (auto q : qs) res.push_back(psi.measure(q)); @@ -258,7 +258,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface bool Measure(std::vector bs, std::vector qs) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); removeIdentities(bs, qs); // ***TODO*** optimized kernels changebasis(bs, qs, true); @@ -269,34 +269,34 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void seed(unsigned s) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); psi.seed(s); } void reset() { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); psi.reset(); } unsigned num_qubits() const { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); return psi.num_qubits(); } void flush() { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); psi.flush(); } ComplexType const* data() const { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); return psi.data().data(); } void dump(bool (*callback)(size_t, double, double)) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); flush(); auto wfn = psi.data(); @@ -319,7 +319,7 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface void dumpIds(void (*callback)(logical_qubit_id)) { - recursive_lock_type l(this->mutex()); + recursive_lock_type l(getMutex()); flush(); std::vector qubits = psi.get_qubit_ids(); @@ -385,13 +385,13 @@ class Simulator : public Microsoft::Quantum::Simulator::SimulatorInterface assert(std::accumulate(test.begin(), test.end(), 0u) == table_size); #endif - recursive_lock_type l(this->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(this->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..697b08b1715 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; }