-
Notifications
You must be signed in to change notification settings - Fork 90
Check qubit release/measurement status on release #796
Changes from all commits
7646109
d55b4e7
e311ef4
6293c71
d3c0003
a5d1023
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 UnmarkAsMeasuredSingleQubit(Qubit q) | ||
| { | ||
| isMeasured[GetQubitId(q)] = false; | ||
| } | ||
|
|
||
| void UnmarkAsMeasuredQubitList(long num, Qubit* qubit) | ||
| { | ||
| for (const auto& id : GetQubitIds(num, qubit)) | ||
| { | ||
| isMeasured[id] = false; | ||
| } | ||
| } | ||
|
|
||
| public: | ||
| CFullstateSimulator(uint32_t userProvidedSeed = 0) : handle(LoadQuantumSimulator()) | ||
| { | ||
|
|
@@ -220,16 +234,28 @@ 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<TReleaseQubit>(this->GetProc("release")); | ||
|
|
||
| releaseQubit(this->simulatorId, GetQubitId(q)); // Release qubit in the simulator. | ||
| qubitManager->Release(q); // Release it in the qubit manager. | ||
| // Release qubit in the simulator, checking to make sure that release was valid. | ||
| 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. | ||
| } | ||
|
|
||
| Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override | ||
|
|
@@ -238,6 +264,11 @@ namespace Quantum | |
| typedef unsigned (*TMeasure)(unsigned, unsigned, unsigned*, unsigned*); | ||
| static TMeasure m = reinterpret_cast<TMeasure>(this->GetProc("Measure")); | ||
| std::vector<unsigned> ids = GetQubitIds(numTargets, targets); | ||
| if (ids.size() == 1) | ||
| { | ||
| // If measuring exactly one qubit, mark it as measured for tracking. | ||
swernli marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| isMeasured[ids[0]] = true; | ||
| } | ||
| return reinterpret_cast<Result>( | ||
| m(this->simulatorId, (unsigned)numBases, reinterpret_cast<unsigned*>(bases), ids.data())); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have an impression that only one qubit is marked as measured regardless of the number of qubits being measured.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One classical bit is returned, but that could come from a joint measurement on an arbitrary number of qubits. E.g.:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If multiple qubits are measured it doesn't guarantee that the individual qubit state is known. Only when the length of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks.
kuzminrobin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
@@ -272,71 +303,87 @@ namespace Quantum | |
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("X")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledX(long numControls, Qubit controls[], Qubit target) override | ||
| { | ||
| static TSingleQubitControlledGate op = reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCX")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void Y(Qubit q) override | ||
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("Y")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledY(long numControls, Qubit controls[], Qubit target) override | ||
| { | ||
| static TSingleQubitControlledGate op = reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCY")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void Z(Qubit q) override | ||
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("Z")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledZ(long numControls, Qubit controls[], Qubit target) override | ||
| { | ||
| static TSingleQubitControlledGate op = reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCZ")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void H(Qubit q) override | ||
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("H")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledH(long numControls, Qubit controls[], Qubit target) override | ||
| { | ||
| static TSingleQubitControlledGate op = reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCH")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void S(Qubit q) override | ||
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("S")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledS(long numControls, Qubit controls[], Qubit target) override | ||
| { | ||
| static TSingleQubitControlledGate op = reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCS")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void AdjointS(Qubit q) override | ||
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("AdjS")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledAdjointS(long numControls, Qubit controls[], Qubit target) override | ||
|
|
@@ -345,25 +392,31 @@ namespace Quantum | |
| reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCAdjS")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void T(Qubit q) override | ||
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("T")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledT(long numControls, Qubit controls[], Qubit target) override | ||
| { | ||
| static TSingleQubitControlledGate op = reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCT")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void AdjointT(Qubit q) override | ||
| { | ||
| static TSingleQubitGate op = reinterpret_cast<TSingleQubitGate>(this->GetProc("AdjT")); | ||
| op(this->simulatorId, GetQubitId(q)); | ||
| UnmarkAsMeasuredSingleQubit(q); | ||
| } | ||
|
|
||
| void ControlledAdjointT(long numControls, Qubit controls[], Qubit target) override | ||
|
|
@@ -372,6 +425,8 @@ namespace Quantum | |
| reinterpret_cast<TSingleQubitControlledGate>(this->GetProc("MCAdjT")); | ||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| op(this->simulatorId, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void R(PauliId axis, Qubit target, double theta) override | ||
|
|
@@ -380,6 +435,7 @@ namespace Quantum | |
| static TR r = reinterpret_cast<TR>(this->GetProc("R")); | ||
|
|
||
| r(this->simulatorId, GetBasis(axis), theta, GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| } | ||
|
|
||
| void ControlledR(long numControls, Qubit controls[], PauliId axis, Qubit target, double theta) override | ||
|
|
@@ -389,6 +445,8 @@ namespace Quantum | |
|
|
||
| std::vector<unsigned> ids = GetQubitIds(numControls, controls); | ||
| cr(this->simulatorId, GetBasis(axis), theta, (unsigned)numControls, ids.data(), GetQubitId(target)); | ||
| UnmarkAsMeasuredSingleQubit(target); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) override | ||
|
|
@@ -397,6 +455,7 @@ namespace Quantum | |
| static TExp exp = reinterpret_cast<TExp>(this->GetProc("Exp")); | ||
| std::vector<unsigned> ids = GetQubitIds(numTargets, targets); | ||
| exp(this->simulatorId, (unsigned)numTargets, reinterpret_cast<unsigned*>(paulis), theta, ids.data()); | ||
| UnmarkAsMeasuredQubitList(numTargets, targets); | ||
| } | ||
|
|
||
| void ControlledExp(long numControls, Qubit controls[], long numTargets, PauliId paulis[], Qubit targets[], | ||
|
|
@@ -408,6 +467,8 @@ namespace Quantum | |
| std::vector<unsigned> idsControls = GetQubitIds(numControls, controls); | ||
| cexp(this->simulatorId, (unsigned)numTargets, reinterpret_cast<unsigned*>(paulis), theta, | ||
| (unsigned)numControls, idsControls.data(), idsTargets.data()); | ||
| UnmarkAsMeasuredQubitList(numTargets, targets); | ||
| UnmarkAsMeasuredQubitList(numControls, controls); | ||
| } | ||
|
|
||
| bool Assert(long numTargets, PauliId* bases, Qubit* targets, Result result, const char* failureMessage) override | ||
|
|
@@ -436,6 +497,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<bool>` is already specialized to use an underlying bitfied to save space. | ||
swernli marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // See: https://www.cplusplus.com/reference/vector/vector-bool/ | ||
| std::vector<bool> isMeasured; | ||
|
|
||
| private: | ||
| TDumpToLocationCallback const dumpToLocationCallback = [](size_t idx, double re, double im, | ||
| TDumpLocation location) -> bool { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.