From a87b784973669f12efa30655b2ccd4fd62d53cc7 Mon Sep 17 00:00:00 2001 From: Thomas Germain Date: Fri, 15 Mar 2024 15:13:00 -0400 Subject: [PATCH 1/7] rng to MeasurementBase with setSeed() --- .../src/measurements/MeasurementsBase.hpp | 19 +++++++++++++++++++ .../measurements/MeasurementsGPU.hpp | 4 ++-- .../measurements/MeasurementsLQubit.hpp | 12 ++++++------ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index f67d625ad7..ded6192d17 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -17,6 +17,7 @@ */ #pragma once +#include #include #include @@ -55,6 +56,7 @@ template class MeasurementsBase { #else const StateVectorT &_statevector; #endif + std::mt19937 rng; public: #ifdef _ENABLE_PLGPU @@ -65,6 +67,23 @@ template class MeasurementsBase { : _statevector{statevector} {}; #endif + /** + * @brief Set the seed of the internal random generator + * + * @param seed Seed + */ + void setSeed(const size_t seed) { rng.seed(seed); } + + /** + * @brief Randomly set the seed of the internal random generator + * + * @param seed Seed + */ + void setRandomSeed() { + std::random_device rd; + setSeed(rd()); + } + /** * @brief Calculate the expectation value for a general Observable. * diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp index f6b73fca90..fca0175177 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -224,10 +224,10 @@ class Measurements final data_type = CUDA_C_32F; } - std::mt19937 gen(std::random_device{}()); + this->setRandomSeed(); std::uniform_real_distribution dis(0.0, 1.0); for (size_t n = 0; n < num_samples; n++) { - rand_nums[n] = dis(gen); + rand_nums[n] = dis(this->rng); } std::vector samples(num_samples * num_qubits, 0); std::unordered_map cache; diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp index 744286740f..0e74849964 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -466,11 +466,10 @@ class Measurements final generate_samples_metropolis(const std::string &kernelname, size_t num_burnin, size_t num_samples) { size_t num_qubits = this->_statevector.getNumQubits(); - std::random_device rd; - std::mt19937 gen(rd()); std::uniform_real_distribution distrib(0.0, 1.0); std::vector samples(num_samples * num_qubits, 0); std::unordered_map cache; + this->setRandomSeed(); TransitionKernelType transition_kernel = TransitionKernelType::Local; if (kernelname == "NonZeroRandom") { @@ -484,13 +483,14 @@ class Measurements final // Burn In for (size_t i = 0; i < num_burnin; i++) { - idx = metropolis_step(this->_statevector, tk, gen, distrib, + idx = metropolis_step(this->_statevector, tk, this->rng, distrib, idx); // Burn-in. } // Sample for (size_t i = 0; i < num_samples; i++) { - idx = metropolis_step(this->_statevector, tk, gen, distrib, idx); + idx = metropolis_step(this->_statevector, tk, this->rng, distrib, + idx); if (cache.contains(idx)) { size_t cache_id = cache[idx]; @@ -562,9 +562,9 @@ class Measurements final auto &&probabilities = probs(); std::vector samples(num_samples * num_qubits, 0); - std::mt19937 generator(std::random_device{}()); std::uniform_real_distribution distribution(0.0, 1.0); std::unordered_map cache; + this->setRandomSeed(); const size_t N = probabilities.size(); std::vector bucket(N); @@ -611,7 +611,7 @@ class Measurements final // Pick samples for (size_t i = 0; i < num_samples; i++) { - PrecisionT pct = distribution(generator) * N; + PrecisionT pct = distribution(this->rng) * N; auto idx = static_cast(pct); if (pct - idx > bucket[idx]) { idx = bucket_partner[idx]; From d10da24b584ec3205e18c528e0b28e2ab3995157 Mon Sep 17 00:00:00 2001 From: Thomas Germain Date: Fri, 15 Mar 2024 15:17:35 -0400 Subject: [PATCH 2/7] collapse() and normalize() in StateVector --- .github/CHANGELOG.md | 5 +- .../lightning_qubit/StateVectorLQubit.hpp | 51 ++++++++++++++++++- .../tests/Test_StateVectorLQubit.cpp | 35 +++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index cb2ca1fd6f..bb9ff6706c 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* `lightning.qubit` supports mid-circuit measurements. + [(#621)](https://github.com/PennyLaneAI/pennylane-lightning/pull/621) + * Add two new python classes (LightningStateVector and LightningMeasurements) to support `lightning.qubit2`. [(#613)](https://github.com/PennyLaneAI/pennylane-lightning/pull/613) @@ -32,7 +35,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux +Ali Asadi, Amintor Dusko, Thomas Germain, Vincent Michaud-Rioux --- diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubit.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubit.hpp index afcfb080ec..c7e8002eb6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubit.hpp @@ -36,6 +36,7 @@ namespace { using Pennylane::LightningQubit::Util::Threading; using Pennylane::Util::CPUMemoryModel; using Pennylane::Util::exp2; +using Pennylane::Util::squaredNorm; using namespace Pennylane::LightningQubit::Gates; } // namespace /// @endcond @@ -632,5 +633,53 @@ class StateVectorLQubit : public StateVectorBase { applyMatrix(matrix.data(), wires, inverse); } + + /** + * @brief Collapse the state vector as after having measured one of the + * qubits. + * + * The branch parameter imposes the measurement result on the given wire. + * + * @param wire Wire to collapse. + * @param branch Branch 0 or 1. + */ + void collapse(const std::size_t wire, const bool branch) { + auto *arr = this->getData(); + const size_t stride = pow(2, this->num_qubits_ - (1 + wire)); + const size_t vec_size = pow(2, this->num_qubits_); + const auto section_size = vec_size / stride; + const auto half_section_size = section_size / 2; + + // zero half the entries + // the "half" entries depend on the stride + // *_*_*_*_ for stride 1 + // **__**__ for stride 2 + // ****____ for stride 4 + const size_t k = branch ? 0 : 1; + for (size_t idx = 0; idx < half_section_size; idx++) { + const size_t offset = stride * (k + 2 * idx); + for (size_t ids = 0; ids < stride; ids++) { + arr[offset + ids] = {0., 0.}; + } + } + + normalize(); + } + + /** + * @brief Normalize vector (to have norm 1). + */ + void normalize() { + auto *arr = this->getData(); + PrecisionT norm = std::sqrt(squaredNorm(arr, this->getLength())); + + PL_ABORT_IF(norm < std::numeric_limits::epsilon() * 1e2, + "vector has norm close to zero and can't be normalized"); + + std::complex inv_norm = 1. / norm; + for (size_t k = 0; k < this->getLength(); k++) { + arr[k] *= inv_norm; + } + } }; -} // namespace Pennylane::LightningQubit \ No newline at end of file +} // namespace Pennylane::LightningQubit diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp index 66ac1fd87f..310cb4cb68 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp @@ -216,3 +216,38 @@ TEMPLATE_PRODUCT_TEST_CASE("StateVectorLQubit::applyOperations", LightningException, "must all be equal"); // invalid parameters } } + +TEMPLATE_PRODUCT_TEST_CASE("StateVectorLQubit::collapse", "[StateVectorLQubit]", + (StateVectorLQubitManaged, StateVectorLQubitRaw), + (float, double)) { + using StateVectorT = TestType; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = typename StateVectorT::ComplexT; + using TestVectorT = TestVector; + + const std::size_t num_qubits = 3; + + SECTION("Collapse the state vector as after having measured one of the " + "qubits.") { + TestVectorT init_state = createPlusState(num_qubits); + + const ComplexT coef{0.5, PrecisionT{0.0}}; + const ComplexT zero{PrecisionT{0.0}, PrecisionT{0.0}}; + + std::vector>> expected_state = { + {{coef, coef, coef, coef, zero, zero, zero, zero}, + {coef, coef, zero, zero, coef, coef, zero, zero}, + {coef, zero, coef, zero, coef, zero, coef, zero}}, + {{zero, zero, zero, zero, coef, coef, coef, coef}, + {zero, zero, coef, coef, zero, zero, coef, coef}, + {zero, coef, zero, coef, zero, coef, zero, coef}}, + }; + + std::size_t wire = GENERATE(0, 1, 2); + std::size_t branch = GENERATE(0, 1); + StateVectorLQubitManaged sv(init_state); + sv.collapse(wire, branch); + + REQUIRE(sv.getDataVector() == approx(expected_state[branch][wire])); + } +} From 9d311a7bc53118ee2a2dd6e900cf0f63145eb8a2 Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Fri, 15 Mar 2024 19:23:55 +0000 Subject: [PATCH 3/7] Auto update version --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index ea4384e017..f95ce9d020 100644 --- a/pennylane_lightning/core/_version.py +++ b/pennylane_lightning/core/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.36.0-dev9" +__version__ = "0.36.0-dev10" From c1fe8902fac0f474f91c2750a183c8a8486a8c95 Mon Sep 17 00:00:00 2001 From: Thomas Germain Date: Fri, 15 Mar 2024 15:31:50 -0400 Subject: [PATCH 4/7] trigger ci From ca0844436546e652b544be9d5dd7fd8a14166e2b Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Mon, 18 Mar 2024 12:08:15 +0000 Subject: [PATCH 5/7] Auto update version --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index f95ce9d020..5bc57662cf 100644 --- a/pennylane_lightning/core/_version.py +++ b/pennylane_lightning/core/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.36.0-dev10" +__version__ = "0.36.0-dev11" From 468f15672bb03a269fc5bb6028e7967164056e56 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Mon, 18 Mar 2024 08:17:40 -0400 Subject: [PATCH 6/7] trigger ci From 40229104c4a3f2acae45eb0763d7001cdf88279d Mon Sep 17 00:00:00 2001 From: Thomas Germain <115888357+tomlqc@users.noreply.github.com> Date: Mon, 18 Mar 2024 08:53:12 -0400 Subject: [PATCH 7/7] CHANGELOG.md Co-authored-by: Vincent Michaud-Rioux --- .github/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index aaebce5c2e..0daad04b2b 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,8 +2,8 @@ ### New features since last release -* `lightning.qubit` supports mid-circuit measurements. - [(#621)](https://github.com/PennyLaneAI/pennylane-lightning/pull/621) +* Add `collapse` and `normalize` methods to the `StateVectorLQubit` classes, enabling "branching" of the wavefunction. Add methods to create and seed an RNG in the `Measurements` modules. + [(#645)](https://github.com/PennyLaneAI/pennylane-lightning/pull/645) * Add two new python classes (LightningStateVector and LightningMeasurements) to support `lightning.qubit2`. [(#613)](https://github.com/PennyLaneAI/pennylane-lightning/pull/613)