Check qubit release/measurement status on release (#796)
* Check qubit release/measurement status on release This mimics the same behavior in the QIR Runtime wrapper for the fullstate simulator as what we have for C#, namely that a qubit is valid 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 supersedes #710. * CR feedback * Revert mutex change
This commit is contained in:
Родитель
292976c8b9
Коммит
ec491fee57
|
@ -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.
|
||||
isMeasured[ids[0]] = true;
|
||||
}
|
||||
return reinterpret_cast<Result>(
|
||||
m(this->simulatorId, (unsigned)numBases, reinterpret_cast<unsigned*>(bases), ids.data()));
|
||||
}
|
||||
|
@ -272,6 +303,7 @@ 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
|
||||
|
@ -279,12 +311,15 @@ namespace Quantum
|
|||
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
|
||||
|
@ -292,12 +327,15 @@ namespace Quantum
|
|||
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
|
||||
|
@ -305,12 +343,15 @@ namespace Quantum
|
|||
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
|
||||
|
@ -318,12 +359,15 @@ namespace Quantum
|
|||
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
|
||||
|
@ -331,12 +375,15 @@ namespace Quantum
|
|||
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,12 +392,15 @@ 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
|
||||
|
@ -358,12 +408,15 @@ namespace Quantum
|
|||
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.
|
||||
// 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 {
|
||||
|
|
|
@ -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<IRuntimeDriver> 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<IRuntimeDriver> 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]")
|
||||
{
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -69,9 +69,11 @@ 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);
|
||||
// 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);
|
||||
}
|
||||
|
||||
MICROSOFT_QUANTUM_DECL unsigned num_qubits(_In_ unsigned id)
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче