From 3bfaaa04e8e27b0f85fd9410c3aa053abe9e5abd Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 23 Mar 2021 12:09:30 -0700 Subject: [PATCH 1/2] Remove BitStates.hpp BitStates.hpp defined a custom implementation for tracking vectors of bits. However, `vector` from the STL already is a specialization of `vector` designed to save space and use a single bit for each index. Since we don't want to support the custom type in our API nor do we really need one internally, it was removed and all instances replaced with `vector`. Fixes #577 --- .../lib/Simulators/ToffoliSimulator.cpp | 20 ++--- src/QirRuntime/public/BitStates.hpp | 83 ------------------- .../test/unittests/QirRuntimeTests.cpp | 45 ++++++---- 3 files changed, 39 insertions(+), 109 deletions(-) delete mode 100644 src/QirRuntime/public/BitStates.hpp diff --git a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp b/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp index db992d24ba3..28c7f63ed0e 100644 --- a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp +++ b/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp @@ -8,8 +8,6 @@ #include "QSharpSimApi_I.hpp" #include "SimFactory.hpp" -#include "BitStates.hpp" - namespace Microsoft { namespace Quantum @@ -24,7 +22,7 @@ namespace Quantum // State of a qubit is represented by a bit in states indexed by qubit's id, // bits 0 and 1 correspond to |0> and |1> states respectively. - BitStates states; + std::vector states; // The clients should never attempt to derefenece the Result, so we'll use fake // pointers to avoid allocation and deallocation. @@ -67,7 +65,7 @@ namespace Quantum Qubit AllocateQubit() override { this->lastUsedId++; - this->states.ExtendToInclude(this->lastUsedId); + this->states.emplace_back(); return reinterpret_cast(this->lastUsedId); } @@ -75,13 +73,15 @@ namespace Quantum { const long id = GetQubitId(qubit); assert(id <= this->lastUsedId); - assert(!this->states.IsBitSetAt(id)); + assert(!this->states.at(id)); + this->lastUsedId--; + this->states.pop_back(); } std::string QubitToString(Qubit qubit) override { const long id = GetQubitId(qubit); - return std::to_string(id) + ":" + (this->states.IsBitSetAt(id) ? "1" : "0"); + return std::to_string(id) + ":" + (this->states.at(id) ? "1" : "0"); } /// @@ -120,7 +120,7 @@ namespace Quantum /// void X(Qubit qubit) override { - this->states.FlipBitAt(GetQubitId(qubit)); + this->states.at(GetQubitId(qubit)).flip(); } void ControlledX(long numControls, Qubit* const controls, Qubit qubit) override @@ -128,7 +128,7 @@ namespace Quantum bool allControlsSet = true; for (long i = 0; i < numControls; i++) { - if (!this->states.IsBitSetAt(GetQubitId(controls[i]))) + if (!this->states.at(GetQubitId(controls[i]))) { allControlsSet = false; break; @@ -137,7 +137,7 @@ namespace Quantum if (allControlsSet) { - this->states.FlipBitAt(GetQubitId(qubit)); + this->states.at(GetQubitId(qubit)).flip(); } } @@ -153,7 +153,7 @@ namespace Quantum } if (bases[i] == PauliId_Z) { - odd ^= (this->states.IsBitSetAt(GetQubitId(targets[i]))); + odd ^= (this->states.at(GetQubitId(targets[i]))); } } return odd ? one : zero; diff --git a/src/QirRuntime/public/BitStates.hpp b/src/QirRuntime/public/BitStates.hpp deleted file mode 100644 index 671a5742e36..00000000000 --- a/src/QirRuntime/public/BitStates.hpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#pragma once - -#include -#include - -#include "CoreTypes.hpp" - -namespace Microsoft -{ -namespace Quantum -{ - /*============================================================================== - Provides dynamically extendable storage for packed bits - ==============================================================================*/ - struct QIR_SHARED_API BitStates - { - typedef uint64_t TSLOT; - static constexpr int slotSizeBits = sizeof(TSLOT) * 8; - - std::vector slots; - - static long GetSlotIndex(long bitIndex) - { - return (bitIndex / (slotSizeBits)); - } - static long GetIndexInSlot(long bitIndex) - { - return (bitIndex & (slotSizeBits - 1)); - } - - void ExtendToInclude(long index) - { - long slotIndex = GetSlotIndex(index); - for (long i = this->slots.size(); i < slotIndex + 1; i++) - { - this->slots.push_back(0); - } - } - - void Clear() - { - this->slots.clear(); - } - - void SetBitAt(long index) - { - const long slotIndex = GetSlotIndex(index); - const long bitIndex = GetIndexInSlot(index); - this->slots[slotIndex] |= (static_cast(1) << bitIndex); - } - - void FlipBitAt(long index) - { - const long slotIndex = GetSlotIndex(index); - const long bitIndex = GetIndexInSlot(index); - this->slots[slotIndex] ^= (static_cast(1) << bitIndex); - } - - bool IsBitSetAt(long index) const - { - const long slotIndex = GetSlotIndex(index); - const long bitIndex = GetIndexInSlot(index); - return this->slots[slotIndex] & (static_cast(1) << bitIndex); - } - - bool IsAny() const - { - for (long i = 0; i < this->slots.size(); i++) - { - if (this->slots[i] != 0) - { - return true; - } - } - return false; - } - }; - -} // namespace Quantum -} // namespace Microsoft \ No newline at end of file diff --git a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp b/src/QirRuntime/test/unittests/QirRuntimeTests.cpp index d47c26fafcb..ebfb9890f76 100644 --- a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp +++ b/src/QirRuntime/test/unittests/QirRuntimeTests.cpp @@ -14,7 +14,6 @@ #include "qsharp__core__qis.hpp" #include "QirRuntime.hpp" -#include "BitStates.hpp" #include "QirContext.hpp" #include "SimulatorStub.hpp" @@ -22,9 +21,9 @@ using namespace Microsoft::Quantum; struct ResultsReferenceCountingTestQAPI : public SimulatorStub { - int lastId = 1; + int lastId = -1; const int maxResults; - BitStates allocated; + std::vector allocated; static int GetResultId(Result r) { @@ -32,16 +31,16 @@ struct ResultsReferenceCountingTestQAPI : public SimulatorStub } ResultsReferenceCountingTestQAPI(int maxResults) - : maxResults(maxResults + 2) + : maxResults(maxResults) { - allocated.ExtendToInclude(maxResults); + allocated = std::vector(maxResults); } Result Measure(long, PauliId[], long, Qubit[]) override { assert(this->lastId < this->maxResults); this->lastId++; - this->allocated.SetBitAt(this->lastId); + this->allocated.at(this->lastId) = true;; return reinterpret_cast(this->lastId); } Result UseZero() override @@ -56,8 +55,8 @@ struct ResultsReferenceCountingTestQAPI : public SimulatorStub { const int id = GetResultId(result); INFO(id); - REQUIRE(this->allocated.IsBitSetAt(id)); - this->allocated.FlipBitAt(id); + REQUIRE(this->allocated.at(id)); + this->allocated.at(id).flip(); } bool AreEqualResults(Result r1, Result r2) override { @@ -66,7 +65,14 @@ struct ResultsReferenceCountingTestQAPI : public SimulatorStub bool HaveResultsInFlight() const { - return this->allocated.IsAny(); + for (const auto& b : this->allocated) + { + if (b) + { + return true; + } + } + return false; } }; TEST_CASE("Results: comparison and reference counting", "[qir_support]") @@ -693,7 +699,7 @@ struct QubitTestQAPI : public SimulatorStub { int lastId = -1; const int maxQubits; - BitStates allocated; + std::vector allocated; static int GetQubitId(Qubit q) { @@ -703,21 +709,21 @@ struct QubitTestQAPI : public SimulatorStub QubitTestQAPI(int maxQubits) : maxQubits(maxQubits) { - allocated.ExtendToInclude(maxQubits); + allocated = std::vector(maxQubits); } Qubit AllocateQubit() override { assert(this->lastId < this->maxQubits); this->lastId++; - this->allocated.SetBitAt(this->lastId); + this->allocated.at(this->lastId) = true; return reinterpret_cast(this->lastId); } void ReleaseQubit(Qubit qubit) override { const int id = GetQubitId(qubit); INFO(id); - REQUIRE(this->allocated.IsBitSetAt(id)); - this->allocated.FlipBitAt(id); + REQUIRE(this->allocated.at(id)); + this->allocated.at(id).flip(); } std::string QubitToString(Qubit qubit) override { @@ -735,12 +741,19 @@ struct QubitTestQAPI : public SimulatorStub bool HaveQubitsInFlight() const { - return this->allocated.IsAny(); + for (const auto& b : this->allocated) + { + if (b) + { + return true; + } + } + return false; } }; TEST_CASE("Qubits: allocate, release, dump", "[qir_support]") { - std::unique_ptr qapi = std::make_unique(3); + std::unique_ptr qapi = std::make_unique(4); QirContextScope qirctx(qapi.get()); QirString* qstr = nullptr; From a1de729b85a0f0eb79c8b893864c0f7685f9a1ee Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 23 Mar 2021 16:13:09 -0700 Subject: [PATCH 2/2] CR feedback --- src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp | 2 +- src/QirRuntime/test/unittests/QirRuntimeTests.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp b/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp index 28c7f63ed0e..bc3c94c3de4 100644 --- a/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp +++ b/src/QirRuntime/lib/Simulators/ToffoliSimulator.cpp @@ -65,7 +65,7 @@ namespace Quantum Qubit AllocateQubit() override { this->lastUsedId++; - this->states.emplace_back(); + this->states.emplace_back(false); return reinterpret_cast(this->lastUsedId); } diff --git a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp b/src/QirRuntime/test/unittests/QirRuntimeTests.cpp index ebfb9890f76..f149f388e8d 100644 --- a/src/QirRuntime/test/unittests/QirRuntimeTests.cpp +++ b/src/QirRuntime/test/unittests/QirRuntimeTests.cpp @@ -31,9 +31,9 @@ struct ResultsReferenceCountingTestQAPI : public SimulatorStub } ResultsReferenceCountingTestQAPI(int maxResults) - : maxResults(maxResults) + : maxResults(maxResults), + allocated(maxResults, false) { - allocated = std::vector(maxResults); } Result Measure(long, PauliId[], long, Qubit[]) override @@ -707,10 +707,11 @@ struct QubitTestQAPI : public SimulatorStub } QubitTestQAPI(int maxQubits) - : maxQubits(maxQubits) + : maxQubits(maxQubits), + allocated(maxQubits, false) { - allocated = std::vector(maxQubits); } + Qubit AllocateQubit() override { assert(this->lastId < this->maxQubits);