From 42bb9fc9bea47935a3b4f30ace81736bab42c8f5 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 9 Mar 2021 16:11:55 +0000 Subject: [PATCH 1/3] Rename and refactor QIR interfaces --- src/QirRuntime/lib/QIR/context.cpp | 14 +- src/QirRuntime/lib/QIR/delegated.cpp | 20 +- src/QirRuntime/lib/QSharpCore/intrinsics.cpp | 52 ++--- .../lib/Simulators/FullstateSimulator.cpp | 23 +-- .../lib/Simulators/ToffoliSimulator.cpp | 58 +++--- src/QirRuntime/lib/Simulators/setup.cpp | 2 +- src/QirRuntime/lib/Tracer/tracer.cpp | 2 +- src/QirRuntime/lib/Tracer/tracer.hpp | 22 +- src/QirRuntime/public/BitStates.hpp | 3 + src/QirRuntime/public/CoreTypes.hpp | 3 + .../{QuantumApi_I.hpp => QSharpSimApi_I.hpp} | 189 ++++++++---------- src/QirRuntime/public/QirContext.hpp | 10 +- src/QirRuntime/public/QirRuntimeApi_I.hpp | 36 ++++ src/QirRuntime/public/SimFactory.hpp | 9 +- src/QirRuntime/public/TracerTypes.hpp | 1 + .../FullstateSimulatorTests.cpp | 92 +++++---- src/QirRuntime/test/QIR-static/qir-driver.cpp | 2 +- .../test/QIR-static/qir-test-conditionals.cpp | 2 +- .../test/QIR-tracer/tracer-config.cpp | 2 +- src/QirRuntime/test/SimulatorStub.hpp | 17 +- .../test/unittests/QirRuntimeTests.cpp | 8 +- .../test/unittests/ToffoliTests.cpp | 56 +++--- 22 files changed, 305 insertions(+), 318 deletions(-) rename src/QirRuntime/public/{QuantumApi_I.hpp => QSharpSimApi_I.hpp} (65%) create mode 100644 src/QirRuntime/public/QirRuntimeApi_I.hpp diff --git a/src/QirRuntime/lib/QIR/context.cpp b/src/QirRuntime/lib/QIR/context.cpp index ff166a76f19..23625950d6e 100644 --- a/src/QirRuntime/lib/QIR/context.cpp +++ b/src/QirRuntime/lib/QIR/context.cpp @@ -6,7 +6,7 @@ #include "QirContext.hpp" #include "CoreTypes.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "allocationsTracker.hpp" // These two globals are used in QIR _directly_ so have to define them outside of the context. @@ -20,15 +20,15 @@ namespace Quantum thread_local std::unique_ptr g_context = nullptr; std::unique_ptr& GlobalContext() { return g_context; } - void InitializeQirContext(ISimulator* sim, bool trackAllocatedObjects) + void InitializeQirContext(IRuntimeDriver* sim, bool trackAllocatedObjects) { assert(g_context == nullptr); g_context = std::make_unique(sim, trackAllocatedObjects); - if (g_context->simulator != nullptr) + if (g_context->driver != nullptr) { - ResultOne = g_context->simulator->UseOne(); - ResultZero = g_context->simulator->UseZero(); + ResultOne = g_context->driver->UseOne(); + ResultZero = g_context->driver->UseZero(); } else { @@ -51,8 +51,8 @@ namespace Quantum g_context.reset(nullptr); } - QirExecutionContext::QirExecutionContext(ISimulator* sim, bool trackAllocatedObjects) - : simulator(sim) + QirExecutionContext::QirExecutionContext(IRuntimeDriver* sim, bool trackAllocatedObjects) + : driver(sim) , trackAllocatedObjects(trackAllocatedObjects) { if (this->trackAllocatedObjects) diff --git a/src/QirRuntime/lib/QIR/delegated.cpp b/src/QirRuntime/lib/QIR/delegated.cpp index e85264f6a72..7100fcef9aa 100644 --- a/src/QirRuntime/lib/QIR/delegated.cpp +++ b/src/QirRuntime/lib/QIR/delegated.cpp @@ -6,7 +6,7 @@ #include "QirRuntime.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "SimFactory.hpp" #include "QirContext.hpp" #include "QirTypes.hpp" @@ -29,22 +29,22 @@ extern "C" { Result quantum__rt__result_zero() { - return Microsoft::Quantum::g_context->simulator->UseZero(); + return Microsoft::Quantum::g_context->driver->UseZero(); } Result quantum__rt__result_one() { - return Microsoft::Quantum::g_context->simulator->UseOne(); + return Microsoft::Quantum::g_context->driver->UseOne(); } QUBIT* quantum__rt__qubit_allocate() // NOLINT { - return Microsoft::Quantum::g_context->simulator->AllocateQubit(); + return Microsoft::Quantum::g_context->driver->AllocateQubit(); } void quantum__rt__qubit_release(QUBIT* qubit) // NOLINT { - Microsoft::Quantum::g_context->simulator->ReleaseQubit(qubit); + Microsoft::Quantum::g_context->driver->ReleaseQubit(qubit); } void quantum__rt__result_update_reference_count(RESULT* r, int32_t increment) @@ -76,7 +76,7 @@ extern "C" if (rit == trackedResults.end()) { assert(increment == -1); - Microsoft::Quantum::g_context->simulator->ReleaseResult(r); + Microsoft::Quantum::g_context->driver->ReleaseResult(r); } else { @@ -85,7 +85,7 @@ extern "C" if (newRefcount == 0) { trackedResults.erase(rit); - Microsoft::Quantum::g_context->simulator->ReleaseResult(r); + Microsoft::Quantum::g_context->driver->ReleaseResult(r); } else { @@ -101,13 +101,13 @@ extern "C" { return true; } - return Microsoft::Quantum::g_context->simulator->AreEqualResults(r1, r2); + return Microsoft::Quantum::g_context->driver->AreEqualResults(r1, r2); } // Returns a string representation of the result. QirString* quantum__rt__result_to_string(RESULT* result) // NOLINT { - ResultValue rv = Microsoft::Quantum::g_context->simulator->GetResultValue(result); + ResultValue rv = Microsoft::Quantum::g_context->driver->GetResultValue(result); assert(rv != Result_Pending); return (rv == Result_Zero) ? quantum__rt__string_create("Zero") : quantum__rt__string_create("One"); @@ -116,6 +116,6 @@ extern "C" // Returns a string representation of the qubit. QirString* quantum__rt__qubit_to_string(QUBIT* qubit) // NOLINT { - return quantum__rt__string_create(Microsoft::Quantum::g_context->simulator->QubitToString(qubit).c_str()); + return quantum__rt__string_create(Microsoft::Quantum::g_context->driver->QubitToString(qubit).c_str()); } } \ No newline at end of file diff --git a/src/QirRuntime/lib/QSharpCore/intrinsics.cpp b/src/QirRuntime/lib/QSharpCore/intrinsics.cpp index 38fd66aa31e..9936ca85622 100644 --- a/src/QirRuntime/lib/QSharpCore/intrinsics.cpp +++ b/src/QirRuntime/lib/QSharpCore/intrinsics.cpp @@ -4,14 +4,15 @@ /*============================================================================= QIR assumes a single global execution context. To support the dispatch over the qir-bridge, the clients must register their - Microsoft::Quantum::ISimulator* first. + Microsoft::Quantum::IRuntimeDriver* first. =============================================================================*/ #include #include #include "qsharp__core__qis.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" #include "QirContext.hpp" #include "QirTypes.hpp" @@ -29,6 +30,11 @@ static std::vector ExtractPauliIds(QirArray* paulis) return pauliIds; } +static Microsoft::Quantum::IQuantumGateSet* GateSet() +{ + return dynamic_cast(Microsoft::Quantum::GlobalContext()->driver); +} + extern "C" { void quantum__qis__exp__body(QirArray* paulis, double angle, QirArray* qubits) @@ -36,7 +42,7 @@ extern "C" assert(paulis->count == qubits->count); std::vector pauliIds = ExtractPauliIds(paulis); - return Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->Exp( + return GateSet()->Exp( paulis->count, reinterpret_cast(pauliIds.data()), reinterpret_cast(qubits->buffer), angle); } @@ -51,7 +57,7 @@ extern "C" assert(paulis->count == qubits->count); std::vector pauliIds = ExtractPauliIds(paulis); - return Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledExp( + return GateSet()->ControlledExp( ctls->count, reinterpret_cast(ctls->buffer), paulis->count, reinterpret_cast(pauliIds.data()), reinterpret_cast(qubits->buffer), angle); } @@ -63,12 +69,12 @@ extern "C" void quantum__qis__h__body(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->H(qubit); + GateSet()->H(qubit); } void quantum__qis__h__ctl(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledH( + GateSet()->ControlledH( ctls->count, reinterpret_cast(ctls->buffer), qubit); } @@ -78,13 +84,13 @@ extern "C" assert(count == paulis->count); std::vector pauliIds = ExtractPauliIds(paulis); - return Microsoft::Quantum::GlobalContext()->simulator->Measure( + return GateSet()->Measure( count, reinterpret_cast(pauliIds.data()), count, reinterpret_cast(qubits->buffer)); } void quantum__qis__r__body(PauliId axis, double angle, QUBIT* qubit) { - return Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->R(axis, qubit, angle); + return GateSet()->R(axis, qubit, angle); } void quantum__qis__r__adj(PauliId axis, double angle, QUBIT* qubit) @@ -94,7 +100,7 @@ extern "C" void quantum__qis__r__ctl(QirArray* ctls, PauliId axis, double angle, QUBIT* qubit) { - return Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledR( + return GateSet()->ControlledR( ctls->count, reinterpret_cast(ctls->buffer), axis, qubit, angle); } @@ -105,78 +111,78 @@ extern "C" void quantum__qis__s__body(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->S(qubit); + GateSet()->S(qubit); } void quantum__qis__s__adj(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->AdjointS(qubit); + GateSet()->AdjointS(qubit); } void quantum__qis__s__ctl(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledS( + GateSet()->ControlledS( ctls->count, reinterpret_cast(ctls->buffer), qubit); } void quantum__qis__s__ctladj(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledAdjointS( + GateSet()->ControlledAdjointS( ctls->count, reinterpret_cast(ctls->buffer), qubit); } void quantum__qis__t__body(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->T(qubit); + GateSet()->T(qubit); } void quantum__qis__t__adj(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->AdjointT(qubit); + GateSet()->AdjointT(qubit); } void quantum__qis__t__ctl(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledT( + GateSet()->ControlledT( ctls->count, reinterpret_cast(ctls->buffer), qubit); } void quantum__qis__t__ctladj(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledAdjointT( + GateSet()->ControlledAdjointT( ctls->count, reinterpret_cast(ctls->buffer), qubit); } void quantum__qis__x__body(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->X(qubit); + GateSet()->X(qubit); } void quantum__qis__x__ctl(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledX( + GateSet()->ControlledX( ctls->count, reinterpret_cast(ctls->buffer), qubit); } void quantum__qis__y__body(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->Y(qubit); + GateSet()->Y(qubit); } void quantum__qis__y__ctl(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledY( + GateSet()->ControlledY( ctls->count, reinterpret_cast(ctls->buffer), qubit); } void quantum__qis__z__body(Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->Z(qubit); + GateSet()->Z(qubit); } void quantum__qis__z__ctl(QirArray* ctls, Qubit qubit) { - Microsoft::Quantum::GlobalContext()->simulator->AsQuantumGateSet()->ControlledZ( + GateSet()->ControlledZ( ctls->count, reinterpret_cast(ctls->buffer), qubit); } } \ No newline at end of file diff --git a/src/QirRuntime/lib/Simulators/FullstateSimulator.cpp b/src/QirRuntime/lib/Simulators/FullstateSimulator.cpp index 60355b78b72..3172e5372f2 100644 --- a/src/QirRuntime/lib/Simulators/FullstateSimulator.cpp +++ b/src/QirRuntime/lib/Simulators/FullstateSimulator.cpp @@ -9,7 +9,8 @@ #include #include -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" #include "SimFactory.hpp" using namespace std; @@ -78,7 +79,7 @@ namespace Microsoft namespace Quantum { // TODO: is it OK to load/unload the dll for each simulator instance? - class CFullstateSimulator : public ISimulator, public IQuantumGateSet, public IDiagnostics + class CFullstateSimulator : public IRuntimeDriver, public IQuantumGateSet, public IDiagnostics { typedef void (*TSingleQubitGate)(unsigned /*simulator id*/, unsigned /*qubit id*/); typedef void (*TSingleQubitControlledGate)( @@ -170,15 +171,6 @@ namespace Quantum } } - IQuantumGateSet* AsQuantumGateSet() override - { - return this; - } - IDiagnostics* AsDiagnostics() override - { - return this; - } - void GetState(TGetStateCallback callback) override { typedef bool (*TDump)(unsigned, TGetStateCallback); @@ -210,13 +202,6 @@ namespace Quantum releaseQubit(this->simulatorId, GetQubitId(q)); } - Result M(Qubit q) override - { - typedef unsigned (*TM)(unsigned, unsigned); - static TM m = reinterpret_cast(this->GetProc("M")); - return reinterpret_cast(m(this->simulatorId, GetQubitId(q))); - } - Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override { assert(numBases == numTargets); @@ -425,7 +410,7 @@ namespace Quantum } }; - std::unique_ptr CreateFullstateSimulator() + std::unique_ptr CreateFullstateSimulator() { return std::make_unique(); } diff --git a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp b/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp index 59a03c8a0db..db992d24ba3 100644 --- a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp +++ b/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp @@ -4,7 +4,8 @@ #include #include -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" #include "SimFactory.hpp" #include "BitStates.hpp" @@ -17,7 +18,7 @@ namespace Quantum CToffoliSimulator Simulator for reversible classical logic. ==============================================================================*/ - class CToffoliSimulator final : public ISimulator, public IQuantumGateSet, public IDiagnostics + class CToffoliSimulator final : public IRuntimeDriver, public IQuantumGateSet, public IDiagnostics { long lastUsedId = -1; @@ -40,39 +41,8 @@ namespace Quantum ~CToffoliSimulator() = default; /// - /// Implementation of ISimulator + /// Implementation of IRuntimeDriver /// - IQuantumGateSet* AsQuantumGateSet() override - { - return this; - } - IDiagnostics* AsDiagnostics() override - { - return this; - } - - Result M(Qubit qubit) override - { - return (this->states.IsBitSetAt(GetQubitId(qubit)) ? one : zero); - } - - Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override - { - bool odd = false; - for (long i = 0; i < numBases; i++) - { - if (bases[i] == PauliId_X || bases[i] == PauliId_Y) - { - throw std::runtime_error("Toffoli simulator only supports measurements in Z basis"); - } - if (bases[i] == PauliId_Z) - { - odd ^= (this->states.IsBitSetAt(GetQubitId(targets[i]))); - } - } - return odd ? one : zero; - } - void ReleaseResult(Result result) override {} bool AreEqualResults(Result r1, Result r2) override @@ -172,6 +142,24 @@ namespace Quantum } + Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override + { + bool odd = false; + for (long i = 0; i < numBases; i++) + { + if (bases[i] == PauliId_X || bases[i] == PauliId_Y) + { + throw std::runtime_error("Toffoli simulator only supports measurements in Z basis"); + } + if (bases[i] == PauliId_Z) + { + odd ^= (this->states.IsBitSetAt(GetQubitId(targets[i]))); + } + } + return odd ? one : zero; + } + + // // The rest of the gate set Toffoli simulator doesn't support // @@ -255,7 +243,7 @@ namespace Quantum } }; - std::unique_ptr CreateToffoliSimulator() + std::unique_ptr CreateToffoliSimulator() { return std::make_unique(); } diff --git a/src/QirRuntime/lib/Simulators/setup.cpp b/src/QirRuntime/lib/Simulators/setup.cpp index 7d5800b596c..3de3f4e545b 100644 --- a/src/QirRuntime/lib/Simulators/setup.cpp +++ b/src/QirRuntime/lib/Simulators/setup.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "SimFactory.hpp" #include "QirContext.hpp" #include "QirTypes.hpp" diff --git a/src/QirRuntime/lib/Tracer/tracer.cpp b/src/QirRuntime/lib/Tracer/tracer.cpp index 02afaeafb4d..352dc1dae5c 100644 --- a/src/QirRuntime/lib/Tracer/tracer.cpp +++ b/src/QirRuntime/lib/Tracer/tracer.cpp @@ -37,7 +37,7 @@ namespace Quantum } //------------------------------------------------------------------------------------------------------------------ - // CTracer's ISimulator implementation + // CTracer's IRuntimeDriver implementation //------------------------------------------------------------------------------------------------------------------ Qubit CTracer::AllocateQubit() { diff --git a/src/QirRuntime/lib/Tracer/tracer.hpp b/src/QirRuntime/lib/Tracer/tracer.hpp index 59a2a8e7c9c..35f242f1ecc 100644 --- a/src/QirRuntime/lib/Tracer/tracer.hpp +++ b/src/QirRuntime/lib/Tracer/tracer.hpp @@ -9,7 +9,7 @@ #include #include "CoreTypes.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "TracerTypes.hpp" namespace Microsoft @@ -60,7 +60,7 @@ namespace Quantum /*================================================================================================================== The tracer implements resource estimation. See readme in this folder for details. ==================================================================================================================*/ - class QIR_SHARED_API CTracer : public ISimulator + class QIR_SHARED_API CTracer : public IRuntimeDriver { // For now the tracer assumes no reuse of qubits. std::vector qubits; @@ -141,29 +141,13 @@ namespace Quantum } // ------------------------------------------------------------------------------------------------------------- - // ISimulator interface + // IRuntimeDriver interface // ------------------------------------------------------------------------------------------------------------- Qubit AllocateQubit() override; void ReleaseQubit(Qubit qubit) override; std::string QubitToString(Qubit qubit) override; void ReleaseResult(Result result) override; - IQuantumGateSet* AsQuantumGateSet() override - { - throw std::logic_error("Not supported: all intrinsics must be converted to tracing operations"); - } - IDiagnostics* AsDiagnostics() override - { - return nullptr; - } - Result M(Qubit target) override - { - throw std::logic_error("Not supported: all measurements must be converted to tracing operations"); - } - Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override - { - throw std::logic_error("Not supported: all measurements must be converted to tracing operations"); - } bool AreEqualResults(Result r1, Result r2) override { throw std::logic_error("Cannot compare results while tracing!"); diff --git a/src/QirRuntime/public/BitStates.hpp b/src/QirRuntime/public/BitStates.hpp index f95d0ce6719..671a5742e36 100644 --- a/src/QirRuntime/public/BitStates.hpp +++ b/src/QirRuntime/public/BitStates.hpp @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + #pragma once #include diff --git a/src/QirRuntime/public/CoreTypes.hpp b/src/QirRuntime/public/CoreTypes.hpp index 57f38a993e9..399d9d27993 100644 --- a/src/QirRuntime/public/CoreTypes.hpp +++ b/src/QirRuntime/public/CoreTypes.hpp @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + #pragma once #include diff --git a/src/QirRuntime/public/QuantumApi_I.hpp b/src/QirRuntime/public/QSharpSimApi_I.hpp similarity index 65% rename from src/QirRuntime/public/QuantumApi_I.hpp rename to src/QirRuntime/public/QSharpSimApi_I.hpp index 74b35c49d94..f99d846a960 100644 --- a/src/QirRuntime/public/QuantumApi_I.hpp +++ b/src/QirRuntime/public/QSharpSimApi_I.hpp @@ -1,108 +1,81 @@ -#pragma once - -#include - -#include "CoreTypes.hpp" - -namespace Microsoft -{ -namespace Quantum -{ - struct QIR_SHARED_API IQuantumGateSet - { - virtual ~IQuantumGateSet() {} - - // Elementary operatons - virtual void X(Qubit target) = 0; - virtual void Y(Qubit target) = 0; - virtual void Z(Qubit target) = 0; - virtual void H(Qubit target) = 0; - virtual void S(Qubit target) = 0; - virtual void T(Qubit target) = 0; - virtual void R(PauliId axis, Qubit target, double theta) = 0; - virtual void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) = 0; - - // Multicontrolled operations - virtual void ControlledX(long numControls, Qubit controls[], Qubit target) = 0; - virtual void ControlledY(long numControls, Qubit controls[], Qubit target) = 0; - virtual void ControlledZ(long numControls, Qubit controls[], Qubit target) = 0; - virtual void ControlledH(long numControls, Qubit controls[], Qubit target) = 0; - virtual void ControlledS(long numControls, Qubit controls[], Qubit target) = 0; - virtual void ControlledT(long numControls, Qubit controls[], Qubit target) = 0; - virtual void ControlledR(long numControls, Qubit controls[], PauliId axis, Qubit target, double theta) = 0; - virtual void ControlledExp( - long numControls, - Qubit controls[], - long numTargets, - PauliId paulis[], - Qubit targets[], - double theta) = 0; - - // Adjoint operations - virtual void AdjointS(Qubit target) = 0; - virtual void AdjointT(Qubit target) = 0; - virtual void ControlledAdjointS(long numControls, Qubit controls[], Qubit target) = 0; - virtual void ControlledAdjointT(long numControls, Qubit controls[], Qubit target) = 0; - }; - - struct QIR_SHARED_API IDiagnostics - { - virtual ~IDiagnostics() {} - - // The callback should be invoked on each basis vector (in the standard computational basis) in little-endian - // order until it returns `false` or the state is fully dumped. - typedef bool (*TGetStateCallback)(size_t /*basis vector*/, double /* amplitude Re*/, double /* amplitude Im*/); - virtual void GetState(TGetStateCallback callback) = 0; - - // Both Assert methods return `true`, if the assert holds, `false` otherwise. - virtual bool Assert( - long numTargets, - PauliId bases[], - Qubit targets[], - Result result, - const char* failureMessage) = 0; - - virtual bool AssertProbability( - long numTargets, - PauliId bases[], - Qubit targets[], - double probabilityOfZero, - double precision, - const char* failureMessage) = 0; - }; - - struct QIR_SHARED_API ISimulator - { - virtual ~ISimulator() {} - - // The caller is responsible for never accessing the returned pointer beyond the lifetime of the source - // ISimulator instance. - virtual IQuantumGateSet* AsQuantumGateSet() = 0; - - // Might return nullptr if the simulator doesn't support diagnostics. The caller is responsible for never - // accessing the returned pointer beyond the lifetime of the source ISimulator instance. - virtual IDiagnostics* AsDiagnostics() = 0; - - // Doesn't necessarily provide insight into the state of the qubit (for that look at IDiagnostics) - virtual std::string QubitToString(Qubit qubit) = 0; - - // Qubit management - virtual Qubit AllocateQubit() = 0; - virtual void ReleaseQubit(Qubit qubit) = 0; - - // Results - virtual Result M(Qubit target) = 0; - virtual Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) = 0; - - virtual void ReleaseResult(Result result) = 0; - virtual bool AreEqualResults(Result r1, Result r2) = 0; - virtual ResultValue GetResultValue(Result result) = 0; - // The caller *should not* release results obtained via these two methods. The - // results are guaranteed to be finalized to the corresponding ResultValue, but - // it's not required from the runtime to return same Result on subsequent calls. - virtual Result UseZero() = 0; - virtual Result UseOne() = 0; - }; - -} // namespace Quantum -} // namespace Microsoft +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "CoreTypes.hpp" + +namespace Microsoft +{ +namespace Quantum +{ + struct QIR_SHARED_API IQuantumGateSet + { + virtual ~IQuantumGateSet() {} + + // Elementary operatons + virtual void X(Qubit target) = 0; + virtual void Y(Qubit target) = 0; + virtual void Z(Qubit target) = 0; + virtual void H(Qubit target) = 0; + virtual void S(Qubit target) = 0; + virtual void T(Qubit target) = 0; + virtual void R(PauliId axis, Qubit target, double theta) = 0; + virtual void Exp(long numTargets, PauliId paulis[], Qubit targets[], double theta) = 0; + + // Multicontrolled operations + virtual void ControlledX(long numControls, Qubit controls[], Qubit target) = 0; + virtual void ControlledY(long numControls, Qubit controls[], Qubit target) = 0; + virtual void ControlledZ(long numControls, Qubit controls[], Qubit target) = 0; + virtual void ControlledH(long numControls, Qubit controls[], Qubit target) = 0; + virtual void ControlledS(long numControls, Qubit controls[], Qubit target) = 0; + virtual void ControlledT(long numControls, Qubit controls[], Qubit target) = 0; + virtual void ControlledR(long numControls, Qubit controls[], PauliId axis, Qubit target, double theta) = 0; + virtual void ControlledExp( + long numControls, + Qubit controls[], + long numTargets, + PauliId paulis[], + Qubit targets[], + double theta) = 0; + + // Adjoint operations + virtual void AdjointS(Qubit target) = 0; + virtual void AdjointT(Qubit target) = 0; + virtual void ControlledAdjointS(long numControls, Qubit controls[], Qubit target) = 0; + virtual void ControlledAdjointT(long numControls, Qubit controls[], Qubit target) = 0; + + // Results + virtual Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) = 0; + }; + + struct QIR_SHARED_API IDiagnostics + { + virtual ~IDiagnostics() {} + + // The callback should be invoked on each basis vector (in the standard computational basis) in little-endian + // order until it returns `false` or the state is fully dumped. + typedef bool (*TGetStateCallback)(size_t /*basis vector*/, double /* amplitude Re*/, double /* amplitude Im*/); + virtual void GetState(TGetStateCallback callback) = 0; + + // Both Assert methods return `true`, if the assert holds, `false` otherwise. + virtual bool Assert( + long numTargets, + PauliId bases[], + Qubit targets[], + Result result, + const char* failureMessage) = 0; + + virtual bool AssertProbability( + long numTargets, + PauliId bases[], + Qubit targets[], + double probabilityOfZero, + double precision, + const char* failureMessage) = 0; + }; + +} +} \ No newline at end of file diff --git a/src/QirRuntime/public/QirContext.hpp b/src/QirRuntime/public/QirContext.hpp index 2fe786455cd..7ed5761f908 100644 --- a/src/QirRuntime/public/QirContext.hpp +++ b/src/QirRuntime/public/QirContext.hpp @@ -11,18 +11,18 @@ namespace Microsoft { namespace Quantum { - struct ISimulator; + struct IRuntimeDriver; struct AllocationsTracker; - QIR_SHARED_API void InitializeQirContext(ISimulator* sim, bool trackAllocatedObjects = false); + QIR_SHARED_API void InitializeQirContext(IRuntimeDriver* driver, bool trackAllocatedObjects = false); QIR_SHARED_API void ReleaseQirContext(); struct QIR_SHARED_API QirExecutionContext { - ISimulator* simulator = nullptr; + IRuntimeDriver* driver = nullptr; bool trackAllocatedObjects = false; std::unique_ptr allocationsTracker; - QirExecutionContext(ISimulator* sim, bool trackAllocatedObjects); + QirExecutionContext(IRuntimeDriver* sim, bool trackAllocatedObjects); ~QirExecutionContext(); }; extern thread_local std::unique_ptr g_context; @@ -30,7 +30,7 @@ namespace Quantum struct QIR_SHARED_API QirContextScope { - QirContextScope(ISimulator* sim, bool trackAllocatedObjects = false) + QirContextScope(IRuntimeDriver* sim, bool trackAllocatedObjects = false) { InitializeQirContext(sim, trackAllocatedObjects); } diff --git a/src/QirRuntime/public/QirRuntimeApi_I.hpp b/src/QirRuntime/public/QirRuntimeApi_I.hpp new file mode 100644 index 00000000000..a6a80d6d5bf --- /dev/null +++ b/src/QirRuntime/public/QirRuntimeApi_I.hpp @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "CoreTypes.hpp" + +namespace Microsoft +{ +namespace Quantum +{ + struct QIR_SHARED_API IRuntimeDriver + { + virtual ~IRuntimeDriver() {} + + // Doesn't necessarily provide insight into the state of the qubit (for that look at IDiagnostics) + virtual std::string QubitToString(Qubit qubit) = 0; + + // Qubit management + virtual Qubit AllocateQubit() = 0; + virtual void ReleaseQubit(Qubit qubit) = 0; + + virtual void ReleaseResult(Result result) = 0; + virtual bool AreEqualResults(Result r1, Result r2) = 0; + virtual ResultValue GetResultValue(Result result) = 0; + // The caller *should not* release results obtained via these two methods. The + // results are guaranteed to be finalized to the corresponding ResultValue, but + // it's not required from the runtime to return same Result on subsequent calls. + virtual Result UseZero() = 0; + virtual Result UseOne() = 0; + }; + +} // namespace Quantum +} // namespace Microsoft diff --git a/src/QirRuntime/public/SimFactory.hpp b/src/QirRuntime/public/SimFactory.hpp index f29f790c5b5..f8ab837443e 100644 --- a/src/QirRuntime/public/SimFactory.hpp +++ b/src/QirRuntime/public/SimFactory.hpp @@ -1,19 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + #pragma once #include #include -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" namespace Microsoft { namespace Quantum { // Toffoli Simulator - QIR_SHARED_API std::unique_ptr CreateToffoliSimulator(); + QIR_SHARED_API std::unique_ptr CreateToffoliSimulator(); // Full State Simulator - QIR_SHARED_API std::unique_ptr CreateFullstateSimulator(); + QIR_SHARED_API std::unique_ptr CreateFullstateSimulator(); QIR_SHARED_API std::ostream& SetOutputStream(std::ostream& newOStream); } // namespace Quantum diff --git a/src/QirRuntime/public/TracerTypes.hpp b/src/QirRuntime/public/TracerTypes.hpp index 82e5655fd82..0dd5fbd9424 100644 --- a/src/QirRuntime/public/TracerTypes.hpp +++ b/src/QirRuntime/public/TracerTypes.hpp @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + #pragma once #include diff --git a/src/QirRuntime/test/FullstateSimulator/FullstateSimulatorTests.cpp b/src/QirRuntime/test/FullstateSimulator/FullstateSimulatorTests.cpp index 477be7ce06a..2e9bc0fb351 100644 --- a/src/QirRuntime/test/FullstateSimulator/FullstateSimulatorTests.cpp +++ b/src/QirRuntime/test/FullstateSimulator/FullstateSimulatorTests.cpp @@ -8,7 +8,8 @@ #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file #include "catch.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" #include "SimFactory.hpp" #include "QirContext.hpp" @@ -22,9 +23,16 @@ unsigned GetQubitId(Qubit q) return static_cast(reinterpret_cast(q)); } +static Result MZ(IQuantumGateSet* iqa, Qubit q) +{ + PauliId pauliZ[1] = {PauliId_Z}; + Qubit qs[1] = {q}; + return iqa->Measure(1, pauliZ, 1, qs); +} + TEST_CASE("Fullstate simulator: allocate qubits", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); + std::unique_ptr sim = CreateFullstateSimulator(); Qubit q0 = sim->AllocateQubit(); Qubit q1 = sim->AllocateQubit(); @@ -36,10 +44,10 @@ TEST_CASE("Fullstate simulator: allocate qubits", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: multiple instances", "[fullstate_simulator]") { - std::unique_ptr sim1 = CreateFullstateSimulator(); + std::unique_ptr sim1 = CreateFullstateSimulator(); Qubit q1 = sim1->AllocateQubit(); - std::unique_ptr sim2 = CreateFullstateSimulator(); + std::unique_ptr sim2 = CreateFullstateSimulator(); Qubit q2 = sim2->AllocateQubit(); REQUIRE(GetQubitId(q1) == 0); @@ -51,16 +59,16 @@ TEST_CASE("Fullstate simulator: multiple instances", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: X and measure", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q = sim->AllocateQubit(); - Result r1 = sim->M(q); + Result r1 = MZ(iqa, q); REQUIRE(Result_Zero == sim->GetResultValue(r1)); REQUIRE(sim->AreEqualResults(r1, sim->UseZero())); iqa->X(q); - Result r2 = sim->M(q); + Result r2 = MZ(iqa, q); REQUIRE(Result_One == sim->GetResultValue(r2)); REQUIRE(sim->AreEqualResults(r2, sim->UseOne())); @@ -71,8 +79,8 @@ TEST_CASE("Fullstate simulator: X and measure", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: measure Bell state", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q1 = sim->AllocateQubit(); Qubit q2 = sim->AllocateQubit(); @@ -80,8 +88,8 @@ TEST_CASE("Fullstate simulator: measure Bell state", "[fullstate_simulator]") iqa->H(q1); iqa->ControlledX(1, &q1, q2); - Result r1 = sim->M(q1); - Result r2 = sim->M(q2); + Result r1 = MZ(iqa, q1); + Result r2 = MZ(iqa, q2); REQUIRE(sim->AreEqualResults(r1, r2)); sim->ReleaseQubit(q1); @@ -90,8 +98,8 @@ TEST_CASE("Fullstate simulator: measure Bell state", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: ZZ measure", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q[2]; PauliId paulis[2] = {PauliId_Z, PauliId_Z}; @@ -100,11 +108,11 @@ TEST_CASE("Fullstate simulator: ZZ measure", "[fullstate_simulator]") q[1] = sim->AllocateQubit(); iqa->H(q[0]); iqa->ControlledX(1, &q[0], q[1]); - Result rZero = sim->Measure(2, paulis, 2, q); + Result rZero = iqa->Measure(2, paulis, 2, q); REQUIRE(Result_Zero == sim->GetResultValue(rZero)); iqa->X(q[1]); - Result rOne = sim->Measure(2, paulis, 2, q); + Result rOne = iqa->Measure(2, paulis, 2, q); REQUIRE(Result_One == sim->GetResultValue(rOne)); sim->ReleaseQubit(q[0]); @@ -113,8 +121,8 @@ TEST_CASE("Fullstate simulator: ZZ measure", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: assert probability", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit qs[2]; qs[0] = sim->AllocateQubit(); @@ -125,7 +133,7 @@ TEST_CASE("Fullstate simulator: assert probability", "[fullstate_simulator]") PauliId iz[2] = {PauliId_I, PauliId_Z}; PauliId xi[2] = {PauliId_X, PauliId_I}; - IDiagnostics* idig = sim->AsDiagnostics(); + IDiagnostics* idig = dynamic_cast(sim.get()); REQUIRE(idig->AssertProbability(2, zz, qs, 0.0, 1e-10, "")); REQUIRE(idig->AssertProbability(2, iz, qs, 1.0, 1e-10, "")); REQUIRE(idig->AssertProbability(2, xi, qs, 0.5, 1e-10, "")); @@ -141,8 +149,8 @@ TEST_CASE("Fullstate simulator: assert probability", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: toffoli", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit qs[3]; for (int i = 0; i < 3; i++) @@ -152,11 +160,11 @@ TEST_CASE("Fullstate simulator: toffoli", "[fullstate_simulator]") iqa->X(qs[0]); iqa->ControlledX(2, qs, qs[2]); - REQUIRE(Result_Zero == sim->GetResultValue(sim->M(qs[2]))); + REQUIRE(Result_Zero == sim->GetResultValue(MZ(iqa, qs[2]))); iqa->X(qs[1]); iqa->ControlledX(2, qs, qs[2]); - REQUIRE(Result_One == sim->GetResultValue(sim->M(qs[2]))); + REQUIRE(Result_One == sim->GetResultValue(MZ(iqa, qs[2]))); for (int i = 0; i < 3; i++) { @@ -166,8 +174,8 @@ TEST_CASE("Fullstate simulator: toffoli", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: SSZ=Id", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q = sim->AllocateQubit(); @@ -179,7 +187,7 @@ TEST_CASE("Fullstate simulator: SSZ=Id", "[fullstate_simulator]") iqa->S(q); iqa->Z(q); iqa->H(q); - identitySSZ = (Result_Zero == sim->GetResultValue(sim->M(q))); + identitySSZ = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); } REQUIRE(identitySSZ); @@ -188,8 +196,8 @@ TEST_CASE("Fullstate simulator: SSZ=Id", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: TTSAdj=Id", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q = sim->AllocateQubit(); @@ -201,7 +209,7 @@ TEST_CASE("Fullstate simulator: TTSAdj=Id", "[fullstate_simulator]") iqa->T(q); iqa->AdjointS(q); iqa->H(q); - identityTTSAdj = (Result_Zero == sim->GetResultValue(sim->M(q))); + identityTTSAdj = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); } REQUIRE(identityTTSAdj); @@ -210,8 +218,8 @@ TEST_CASE("Fullstate simulator: TTSAdj=Id", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: TTAdj=Id", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q = sim->AllocateQubit(); @@ -222,7 +230,7 @@ TEST_CASE("Fullstate simulator: TTAdj=Id", "[fullstate_simulator]") iqa->T(q); iqa->AdjointT(q); iqa->H(q); - identityTTadj = (Result_Zero == sim->GetResultValue(sim->M(q))); + identityTTadj = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); } REQUIRE(identityTTadj); @@ -232,8 +240,8 @@ TEST_CASE("Fullstate simulator: TTAdj=Id", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: R", "[fullstate_simulator]") { constexpr double pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q = sim->AllocateQubit(); bool identity = true; @@ -247,7 +255,7 @@ TEST_CASE("Fullstate simulator: R", "[fullstate_simulator]") iqa->R(PauliId_Y, q, -0.17); iqa->R(PauliId_X, q, -0.42); iqa->H(q); - identity = (Result_Zero == sim->GetResultValue(sim->M(q))); + identity = (Result_Zero == sim->GetResultValue(MZ(iqa, q))); } REQUIRE(identity); @@ -256,8 +264,8 @@ TEST_CASE("Fullstate simulator: R", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: exponents", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); const int n = 5; Qubit qs[n]; @@ -281,8 +289,8 @@ TEST_CASE("Fullstate simulator: exponents", "[fullstate_simulator]") TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateFullstateSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); const int n = 3; static double norm = 0.0; @@ -297,7 +305,7 @@ TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simu iqa->ControlledX(1, &qs[0], qs[1]); // 1/sqrt(2)(|00> + |11>)x|0> - sim->AsDiagnostics()->GetState([](size_t idx, double re, double im) { + dynamic_cast(sim.get())->GetState([](size_t idx, double re, double im) { norm += re * re + im * im; REQUIRE(idx < 4); switch (idx) @@ -320,7 +328,7 @@ TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simu iqa->Y(qs[2]); // 1/sqrt(2)(|00> + |11>)xi|1> - sim->AsDiagnostics()->GetState([](size_t idx, double re, double im) { + dynamic_cast(sim.get())->GetState([](size_t idx, double re, double im) { norm += re * re + im * im; switch (idx) { @@ -348,7 +356,7 @@ TEST_CASE("Fullstate simulator: get qubit state of Bell state", "[fullstate_simu extern "C" int Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body(); // NOLINT TEST_CASE("QIR: invoke all standard Q# gates against the fullstate simulator", "[fullstate_simulator]") { - std::unique_ptr sim = CreateFullstateSimulator(); + std::unique_ptr sim = CreateFullstateSimulator(); QirContextScope qirctx(sim.get(), true /*trackAllocatedObjects*/); REQUIRE(0 == Microsoft__Quantum__Testing__QIR__Test_Simulator_QIS__body()); diff --git a/src/QirRuntime/test/QIR-static/qir-driver.cpp b/src/QirRuntime/test/QIR-static/qir-driver.cpp index 558b1c3b150..f0c34c84d5a 100644 --- a/src/QirRuntime/test/QIR-static/qir-driver.cpp +++ b/src/QirRuntime/test/QIR-static/qir-driver.cpp @@ -11,7 +11,7 @@ #include "CoreTypes.hpp" #include "QirContext.hpp" #include "QirTypes.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "SimFactory.hpp" #include "SimulatorStub.hpp" #include "QirRuntime.hpp" diff --git a/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp b/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp index 556f63d12d6..a1269ef83ed 100644 --- a/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp +++ b/src/QirRuntime/test/QIR-static/qir-test-conditionals.cpp @@ -10,7 +10,7 @@ #include "CoreTypes.hpp" #include "QirContext.hpp" #include "QirTypes.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "SimulatorStub.hpp" using namespace std; diff --git a/src/QirRuntime/test/QIR-tracer/tracer-config.cpp b/src/QirRuntime/test/QIR-tracer/tracer-config.cpp index b47f1c70ba9..2e58fd225dc 100644 --- a/src/QirRuntime/test/QIR-tracer/tracer-config.cpp +++ b/src/QirRuntime/test/QIR-tracer/tracer-config.cpp @@ -6,7 +6,7 @@ #include -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "tracer-config.hpp" namespace TracerUser diff --git a/src/QirRuntime/test/SimulatorStub.hpp b/src/QirRuntime/test/SimulatorStub.hpp index f6c4c9f1b20..6f3d198f4e9 100644 --- a/src/QirRuntime/test/SimulatorStub.hpp +++ b/src/QirRuntime/test/SimulatorStub.hpp @@ -2,22 +2,15 @@ #include -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" namespace Microsoft { namespace Quantum { - struct SimulatorStub : public ISimulator, public IQuantumGateSet + struct SimulatorStub : public IRuntimeDriver, public IQuantumGateSet { - IQuantumGateSet* AsQuantumGateSet() override - { - return this; - } - IDiagnostics* AsDiagnostics() override - { - return nullptr; - } Qubit AllocateQubit() override { throw std::logic_error("not_implemented"); @@ -116,10 +109,6 @@ namespace Quantum { throw std::logic_error("not_implemented"); } - Result M(Qubit target) override - { - throw std::logic_error("not_implemented"); - } Result Measure(long numBases, PauliId bases[], long numTargets, Qubit targets[]) override { throw std::logic_error("not_implemented"); diff --git a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp b/src/QirRuntime/test/unittests/QirRuntimeTests.cpp index b59b88d8828..d47c26fafcb 100644 --- a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp +++ b/src/QirRuntime/test/unittests/QirRuntimeTests.cpp @@ -37,7 +37,7 @@ struct ResultsReferenceCountingTestQAPI : public SimulatorStub allocated.ExtendToInclude(maxResults); } - Result M(Qubit) override + Result Measure(long, PauliId[], long, Qubit[]) override { assert(this->lastId < this->maxResults); this->lastId++; @@ -74,8 +74,8 @@ TEST_CASE("Results: comparison and reference counting", "[qir_support]") std::unique_ptr qapi = std::make_unique(3); QirContextScope qirctx(qapi.get()); - Result r1 = qapi->M(nullptr); // we don't need real qubits for this test - Result r2 = qapi->M(nullptr); + Result r1 = qapi->Measure(0, nullptr, 0, nullptr); // we don't need real qubits for this test + Result r2 = qapi->Measure(0, nullptr, 0, nullptr); REQUIRE(quantum__rt__result_equal(r1, r1)); REQUIRE(!quantum__rt__result_equal(r1, r2)); @@ -85,7 +85,7 @@ TEST_CASE("Results: comparison and reference counting", "[qir_support]") // share a result a few times quantum__rt__result_update_reference_count(r1, 2); - Result r3 = qapi->M(nullptr); + Result r3 = qapi->Measure(0, nullptr, 0, nullptr); // release shared result, the test QAPI will verify double release quantum__rt__result_update_reference_count(r1, -3); // one release for shared and for the original allocation diff --git a/src/QirRuntime/test/unittests/ToffoliTests.cpp b/src/QirRuntime/test/unittests/ToffoliTests.cpp index 83fa07d05eb..84777cacf77 100644 --- a/src/QirRuntime/test/unittests/ToffoliTests.cpp +++ b/src/QirRuntime/test/unittests/ToffoliTests.cpp @@ -5,15 +5,23 @@ #include "catch.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" +#include "QSharpSimApi_I.hpp" #include "SimFactory.hpp" using namespace Microsoft::Quantum; +static Result MZ(IQuantumGateSet* iqa, Qubit q) +{ + PauliId pauliZ[1] = {PauliId_Z}; + Qubit qs[1] = {q}; + return iqa->Measure(1, pauliZ, 1, qs); +} + TEST_CASE("Basis vector", "[toffoli]") { - std::unique_ptr sim = CreateToffoliSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateToffoliSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); constexpr int n = 1000; std::vector qubits; @@ -31,7 +39,7 @@ TEST_CASE("Basis vector", "[toffoli]") long sum = 0; for (Qubit q : qubits) { - if (sim->GetResultValue(sim->M(q)) == Result_One) + if (sim->GetResultValue(MZ(iqa, q)) == Result_One) { sum++; } @@ -41,8 +49,8 @@ TEST_CASE("Basis vector", "[toffoli]") TEST_CASE("Controlled X", "[toffoli]") { - std::unique_ptr sim = CreateToffoliSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateToffoliSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); Qubit q[4]; q[0] = sim->AllocateQubit(); @@ -52,41 +60,41 @@ TEST_CASE("Controlled X", "[toffoli]") // qubits state: |0000> iqa->ControlledX(1, &q[0], q[1]); - REQUIRE(sim->GetResultValue(sim->M(q[1])) == Result_Zero); + REQUIRE(sim->GetResultValue(MZ(iqa, q[1])) == Result_Zero); iqa->ControlledX(2, &q[0], q[2]); - REQUIRE(sim->GetResultValue(sim->M(q[2])) == Result_Zero); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); iqa->ControlledX(3, &q[0], q[3]); - REQUIRE(sim->GetResultValue(sim->M(q[2])) == Result_Zero); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); iqa->X(q[0]); // qubits state: |1000> iqa->ControlledX(2, &q[0], q[2]); - REQUIRE(sim->GetResultValue(sim->M(q[2])) == Result_Zero); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_Zero); iqa->ControlledX(3, &q[0], q[3]); - REQUIRE(sim->GetResultValue(sim->M(q[3])) == Result_Zero); + REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_Zero); iqa->ControlledX(1, &q[0], q[2]); - REQUIRE(sim->GetResultValue(sim->M(q[2])) == Result_One); + REQUIRE(sim->GetResultValue(MZ(iqa, q[2])) == Result_One); // qubits state: |1010> iqa->ControlledX(3, &q[0], q[3]); - REQUIRE(sim->GetResultValue(sim->M(q[3])) == Result_Zero); + REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_Zero); iqa->X(q[1]); // qubits state: |1110> iqa->ControlledX(2, &q[1], q[3]); - REQUIRE(sim->GetResultValue(sim->M(q[3])) == Result_One); + REQUIRE(sim->GetResultValue(MZ(iqa, q[3])) == Result_One); // qubits state: |1111> iqa->ControlledX(3, &q[1], q[0]); - REQUIRE(sim->GetResultValue(sim->M(q[0])) == Result_Zero); + REQUIRE(sim->GetResultValue(MZ(iqa, q[0])) == Result_Zero); } TEST_CASE("Measure and assert probability", "[toffoli]") { - std::unique_ptr sim = CreateToffoliSimulator(); - IQuantumGateSet* iqa = sim->AsQuantumGateSet(); + std::unique_ptr sim = CreateToffoliSimulator(); + IQuantumGateSet* iqa = dynamic_cast(sim.get()); const int count = 3; Qubit qs[count]; @@ -99,24 +107,24 @@ TEST_CASE("Measure and assert probability", "[toffoli]") PauliId ziz[count] = {PauliId_Z, PauliId_I, PauliId_Z}; // initial state is |000> - IDiagnostics* idig = sim->AsDiagnostics(); - REQUIRE(sim->GetResultValue(sim->Measure(count, zzz, count, qs)) == Result_Zero); - REQUIRE(sim->GetResultValue(sim->Measure(count, ziz, count, qs)) == Result_Zero); + IDiagnostics* idig = dynamic_cast(sim.get()); + REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_Zero); + REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); REQUIRE(idig->Assert(count, zzz, qs, sim->UseZero(), "")); REQUIRE(idig->AssertProbability(count, zzz, qs, 1.0, 0.01, "")); // set state to: |010> iqa->X(qs[1]); - REQUIRE(sim->GetResultValue(sim->Measure(count, zzz, count, qs)) == Result_One); - REQUIRE(sim->GetResultValue(sim->Measure(count, ziz, count, qs)) == Result_Zero); + REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_One); + REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); REQUIRE(idig->Assert(count, zzz, qs, sim->UseOne(), "")); REQUIRE(idig->AssertProbability(count, ziz, qs, 1.0, 0.01, "")); // set state to: |111> iqa->X(qs[0]); iqa->X(qs[2]); - REQUIRE(sim->GetResultValue(sim->Measure(count, zzz, count, qs)) == Result_One); - REQUIRE(sim->GetResultValue(sim->Measure(count, ziz, count, qs)) == Result_Zero); + REQUIRE(sim->GetResultValue(iqa->Measure(count, zzz, count, qs)) == Result_One); + REQUIRE(sim->GetResultValue(iqa->Measure(count, ziz, count, qs)) == Result_Zero); REQUIRE(idig->Assert(count, ziz, qs, sim->UseZero(), "")); REQUIRE(idig->AssertProbability(count, zzz, qs, 0.0, 0.01, "")); } \ No newline at end of file From f96ab9899e5b6d13d58a2169d30de60cca758375 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Wed, 10 Mar 2021 07:37:45 +0000 Subject: [PATCH 2/3] Fixup samples --- .../samples/StandaloneInputReference/qir-driver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp b/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp index 843b7cf1830..ee1d07a7cde 100644 --- a/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp +++ b/src/QirRuntime/samples/StandaloneInputReference/qir-driver.cpp @@ -13,7 +13,7 @@ #include "CoreTypes.hpp" #include "QirContext.hpp" #include "QirTypes.hpp" -#include "QuantumApi_I.hpp" +#include "QirRuntimeApi_I.hpp" #include "SimFactory.hpp" #include "QirRuntime.hpp" @@ -101,7 +101,7 @@ int main(int argc, char* argv[]) CLI::App app("QIR Standalone Entry Point Inputs Reference"); // Initialize simulator. - unique_ptr sim = CreateFullstateSimulator(); + unique_ptr sim = CreateFullstateSimulator(); QirContextScope qirctx(sim.get(), false /*trackAllocatedObjects*/); RuntimeResultZero = sim->UseZero(); RuntimeResultOne = sim->UseOne(); From 065589a3492580c0682ff40ef31eb873558fb581 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Wed, 10 Mar 2021 23:14:41 +0000 Subject: [PATCH 3/3] Fix Windows folder to "win" instead of "win32" --- src/QirRuntime/build-qir-runtime.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QirRuntime/build-qir-runtime.ps1 b/src/QirRuntime/build-qir-runtime.ps1 index 639fb235876..402d9fd9071 100644 --- a/src/QirRuntime/build-qir-runtime.ps1 +++ b/src/QirRuntime/build-qir-runtime.ps1 @@ -72,7 +72,7 @@ if ($LastExitCode -ne 0) { Write-Host "##vso[task.logissue type=error;]Failed to build QIR Runtime." } -$os = "win32" +$os = "win" $pattern = "*.dll" if ($IsMacOS) { $os = "osx"