From 8b6161682ec871a7f8f335486ca51dd945e8cc09 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 7 Nov 2023 09:27:00 -0500 Subject: [PATCH 01/76] init commit with PauliX,Y,Z, Hardmard support --- .../measurements/MeasurementsLQubit.hpp | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) 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 534e00d112..a59c15f15b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -268,6 +268,47 @@ class Measurements final return result; } + /** + * @brief Expectation value for a Observable with shots + * + * @param ob Observable + * @param shots Vector of shot number to measurement + * @return Floating point expected value of the observable. + */ + + auto expval(const Observable &ob, size_t &num_shots, + std::vector &shot_range, size_t &bin_size) + -> PrecisionT { + auto name = ob.getObsName(); + auto wires = ob.getWires(); + const size_t num_qubits = this->_statevector.getNumQubits(); + std::vector full_samples = generate_samples(num_shots); + std::vector sub_full_samples; + std::vector obs_samples(num_shots, 0); + + PrecisionT result = 0; + + if (shot_range.empty()) { + sub_full_samples = full_samples; + } else { + // Get a slice of samples based on the shot_range vector + for (auto &i : shot_range) { + for (int j = i * num_qubits; j < (i + 1) * num_qubits; j++) { + sub_full_samples.push_back(full_samples[j]); + } + } + } + + if (name == "PauliX" || name == "PauliY" || name == "PauliZ" || + name == "Hadamard") { + for (int i = 0; i < num_shots; i++) { + result += 1 - 2 * sub_full_samples[i * num_qubits + wires[0]]; + } + } + + return result / num_shots; + } + /** * @brief Variance value for a general Observable * From fba922139a0a0aff3bacb2f2d707cda317126892 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 7 Nov 2023 19:20:24 -0500 Subject: [PATCH 02/76] add unit tests & sample --- .../measurements/MeasurementsLQubit.hpp | 124 ++++++++++++++---- .../tests/Test_MeasurementsLQubit.cpp | 15 +++ 2 files changed, 114 insertions(+), 25 deletions(-) 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 a59c15f15b..36866c306a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -44,6 +44,16 @@ using namespace Pennylane::Measures; using namespace Pennylane::Observables; using Pennylane::LightningQubit::StateVectorLQubitManaged; using Pennylane::LightningQubit::Util::innerProdC; + +/* +auto sample_to_str(std::vector &sample) -> std::string { + std::string str; + for (auto &element : sample) { + str += std::to_string(element); + } + return str; +} +*/ } // namespace /// @endcond @@ -277,36 +287,19 @@ class Measurements final */ auto expval(const Observable &ob, size_t &num_shots, - std::vector &shot_range, size_t &bin_size) + std::vector &shot_range) -> PrecisionT { - auto name = ob.getObsName(); - auto wires = ob.getWires(); - const size_t num_qubits = this->_statevector.getNumQubits(); - std::vector full_samples = generate_samples(num_shots); - std::vector sub_full_samples; - std::vector obs_samples(num_shots, 0); - PrecisionT result = 0; + std::vector short_range = {}; + auto obs_samples = _samples(ob, num_shots, shot_range); - if (shot_range.empty()) { - sub_full_samples = full_samples; - } else { - // Get a slice of samples based on the shot_range vector - for (auto &i : shot_range) { - for (int j = i * num_qubits; j < (i + 1) * num_qubits; j++) { - sub_full_samples.push_back(full_samples[j]); - } - } - } - - if (name == "PauliX" || name == "PauliY" || name == "PauliZ" || - name == "Hadamard") { - for (int i = 0; i < num_shots; i++) { - result += 1 - 2 * sub_full_samples[i * num_qubits + wires[0]]; - } + size_t num_elements = 0; + for (auto element : obs_samples) { + result += element; + num_elements++; } - return result / num_shots; + return result / num_elements; } /** @@ -688,5 +681,86 @@ class Measurements final } return init_idx; } + + /** + * @brief Return samples of a observable + * + * @param obs The observable to sample + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. If it's empty, all samples + * are used. + * @param bin_size Divides the shot range into bins of size ``bin_size``, + * and returns the measurement statistic separately over each bin. + * @param counts Whether count("True") or raw samples ("False") should be + * retruned + * + * @return std::vector samples in std::vector + */ + auto _samples(const Observable &ob, size_t &num_shots, + std::vector &shot_range, [[maybe_unused]] size_t bin_size = 0, + [[maybe_unused]] bool counts = false) { + auto name = ob.getObsName(); + auto wires = ob.getWires(); + const size_t num_qubits = this->_statevector.getNumQubits(); + std::vector samples = generate_samples(num_shots); + std::vector sub_samples; + std::vector obs_samples(num_shots * wires.size(), 0); + + if (shot_range.empty()) { + sub_samples = samples; + } else { + // Get a slice of samples based on the shot_range vector + for (auto &i : shot_range) { + for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { + sub_samples.push_back(samples[j]); + } + } + } + + //if ((name == "PauliX") || (name == "PauliY") || (name == "PauliZ") || + // (name == "Hadamard")) { + for (size_t i = 0; i < num_shots; i++) { + for (size_t j = 0; j < wires.size(); j++) { + obs_samples[i * wires.size() + j] = 1-2*sub_samples[i * num_qubits + num_qubits - 1 - wires[j]]; + } + } + //} + return obs_samples; + } + + /** + * @brief Groups the samples into a dictionary showing number of occurences + * for each possible outcome. + * + * @param samples A vector of samples with size of ``num_shots * + * num_obs_wires`` + * @param num_wires number of wires the sampled observable was performed on + * + * @return std::unordered_map with format ``{'outcome': + * num_occurences}`` + */ + /* + auto _samples_to_counts(std::vector &samples, size_t &num_shots, + size_t &num_obs_wires) + -> std::unordered_map { + std::unordered_map outcome_map; + + for (size_t i = 0; i < num_shots; i++) { + auto local_sample = + std::vector(samples.begin() + i * num_obs_wires, + samples.begin() + (i + 1) * num_obs_wires - 1); + std::string key = sample_to_str(local_sample); + + auto it = outcome_map.find(key); + + if (it != outcome_map.end()) { + it->second += 1; + } else { + outcome_map[key] = 1; + } + } + return outcome_map; + } + */ }; // class Measurements } // namespace Pennylane::LightningQubit::Measures \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index b4be45e99a..41bb629fde 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -20,6 +20,8 @@ #include #include "MeasurementsLQubit.hpp" +#include "Observables.hpp" +#include "../../observables/ObservablesLQubit.hpp" #include "StateVectorLQubitManaged.hpp" #include "StateVectorLQubitRaw.hpp" #include "Util.hpp" @@ -34,6 +36,7 @@ using namespace Pennylane::Util; using namespace Pennylane::LightningQubit; using namespace Pennylane::LightningQubit::Measures; +using namespace Pennylane::LightningQubit::Observables; }; // namespace /// @endcond @@ -115,8 +118,20 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(1e-6)); } + + SECTION("Testing for expval with obs & shots"){ + NamedObs obs("PauliX", {0}); + size_t num_shots = 10000000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.492725; + + CHECK(expval_shot == Approx(expval_ref).margin(1e-2)); + } } + TEMPLATE_PRODUCT_TEST_CASE("Variances", "[Measurements]", (StateVectorLQubitManaged, StateVectorLQubitRaw), (float, double)) { From 5c8c2866b2538d1cfea40b78e2b3c03354892bd2 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 10:52:17 -0500 Subject: [PATCH 03/76] add PauliX, Y, Z & Hadamard support --- .../measurements/MeasurementsLQubit.hpp | 55 +++++--- .../tests/Test_MeasurementsLQubit.cpp | 132 +++++++++++++++++- 2 files changed, 161 insertions(+), 26 deletions(-) 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 36866c306a..f76f9c022f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -286,15 +286,14 @@ class Measurements final * @return Floating point expected value of the observable. */ - auto expval(const Observable &ob, size_t &num_shots, - std::vector &shot_range) - -> PrecisionT { + auto expval(const Observable &obs, size_t &num_shots, + std::vector &shot_range) -> PrecisionT { PrecisionT result = 0; std::vector short_range = {}; - auto obs_samples = _samples(ob, num_shots, shot_range); + auto obs_samples = samples(obs, num_shots, shot_range); size_t num_elements = 0; - for (auto element : obs_samples) { + for (int element : obs_samples) { result += element; num_elements++; } @@ -682,6 +681,7 @@ class Measurements final return init_idx; } + public: /** * @brief Return samples of a observable * @@ -696,15 +696,33 @@ class Measurements final * * @return std::vector samples in std::vector */ - auto _samples(const Observable &ob, size_t &num_shots, - std::vector &shot_range, [[maybe_unused]] size_t bin_size = 0, - [[maybe_unused]] bool counts = false) { - auto name = ob.getObsName(); - auto wires = ob.getWires(); + auto samples(const Observable &obs, size_t &num_shots, + std::vector &shot_range, + [[maybe_unused]] size_t bin_size = 0, + [[maybe_unused]] bool counts = false) { + auto obs_name = obs.getObsName(); + auto obs_wires = obs.getWires(); const size_t num_qubits = this->_statevector.getNumQubits(); - std::vector samples = generate_samples(num_shots); + + StateVectorT sv(this->_statevector); + + if (obs_name.find("PauliX") != std::string::npos) { + sv.applyOperation("Hadamard", {obs_wires[0]}, false); + } else if (obs_name.find("PauliY") != std::string::npos) { + sv.applyOperation("PauliZ", {obs_wires[0]}, false); + sv.applyOperation("S", {obs_wires[0]}, false); + sv.applyOperation("Hadamard", {obs_wires[0]}, false); + } else if (obs_name.find("Hadamard") != std::string::npos) { + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", obs_wires, false, {theta}); + } else if (obs_name.find("PauliZ")) { + } + + Measurements measure(sv); + + std::vector samples = measure.generate_samples(num_shots); std::vector sub_samples; - std::vector obs_samples(num_shots * wires.size(), 0); + std::vector obs_samples(num_shots * obs_wires.size(), 0); if (shot_range.empty()) { sub_samples = samples; @@ -717,14 +735,11 @@ class Measurements final } } - //if ((name == "PauliX") || (name == "PauliY") || (name == "PauliZ") || - // (name == "Hadamard")) { - for (size_t i = 0; i < num_shots; i++) { - for (size_t j = 0; j < wires.size(); j++) { - obs_samples[i * wires.size() + j] = 1-2*sub_samples[i * num_qubits + num_qubits - 1 - wires[j]]; - } - } - //} + for (size_t i = 0; i < num_shots; i++) { + obs_samples[i] = + (1 - 2 * static_cast( + sub_samples[i * num_qubits + obs_wires[0]])); + } return obs_samples; } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 41bb629fde..92d04b0925 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -19,9 +19,9 @@ #include "TestHelpers.hpp" #include +#include "../../observables/ObservablesLQubit.hpp" #include "MeasurementsLQubit.hpp" #include "Observables.hpp" -#include "../../observables/ObservablesLQubit.hpp" #include "StateVectorLQubitManaged.hpp" #include "StateVectorLQubitRaw.hpp" #include "Util.hpp" @@ -119,18 +119,138 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(1e-6)); } - SECTION("Testing for expval with obs & shots"){ + SECTION("Testing for expval with obs & shots PauliX[0]") { NamedObs obs("PauliX", {0}); - size_t num_shots = 10000000; + size_t num_shots = 10000; std::vector shots_range = {}; auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.492725; + PrecisionT expval_ref = 0.49272486; - CHECK(expval_shot == Approx(expval_ref).margin(1e-2)); + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); } -} + SECTION("Testing for expval with obs & shots PauliX[1]") { + NamedObs obs("PauliX", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.42073549; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliX[2]") { + NamedObs obs("PauliX", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.28232124; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[0]") { + NamedObs obs("PauliY", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.64421768; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[1]") { + NamedObs obs("PauliY", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.47942553; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[2]") { + NamedObs obs("PauliY", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.29552020; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[0]") { + NamedObs obs("PauliZ", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.58498357; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[1]") { + NamedObs obs("PauliZ", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.77015115; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[2]") { + NamedObs obs("PauliZ", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.91266780; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[0]") { + NamedObs obs("Hadamard", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.7620549436; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[1]") { + NamedObs obs("Hadamard", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.8420840225; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[1]") { + NamedObs obs("Hadamard", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.8420840225; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } +} TEMPLATE_PRODUCT_TEST_CASE("Variances", "[Measurements]", (StateVectorLQubitManaged, StateVectorLQubitRaw), From 56f02e8306d3b12b13d401d042b85106c3ee990f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 14:11:46 -0500 Subject: [PATCH 04/76] move expval shots to base class --- .../src/measurements/MeasurementsBase.hpp | 86 +++++++++++++++++++ .../measurements/MeasurementsLQubit.hpp | 14 ++- .../measurements/tests/CMakeLists.txt | 1 + .../tests/Test_MeasurementsLQubit.cpp | 6 +- 4 files changed, 101 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 9dbf6f9958..43827a6efe 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -111,6 +111,92 @@ template class MeasurementsBase { auto generate_samples(size_t num_samples) -> std::vector { return static_cast(this)->generate_samples(num_samples); }; + + /** + * @brief Calculate the expectation value for a general Observable. + * + * @param obs Observable. + * @param shots Vector of shot number to measurement + * @param shot_range The range of samples to use. If it's empty, all samples + * are used. + * + * @return Expectation value with respect to the given observable. + */ + auto expval(const Observable &obs, size_t &num_shots, + std::vector &shot_range) -> PrecisionT { + PrecisionT result = 0; + std::vector short_range = {}; + auto obs_samples = samples(obs, num_shots, shot_range); + + size_t num_elements = 0; + for (int element : obs_samples) { + result += element; + num_elements++; + } + + return result / num_elements; + } + + /** + * @brief Return samples of a observable + * + * @param obs The observable to sample + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. If it's empty, all samples + * are used. + * @param bin_size Divides the shot range into bins of size ``bin_size``, + * and returns the measurement statistic separately over each bin. + * @param counts Whether count("True") or raw samples ("False") should be + * retruned + * + * @return std::vector samples in std::vector + */ + auto samples(const Observable &obs, size_t &num_shots, + std::vector &shot_range, + [[maybe_unused]] size_t bin_size = 0, + [[maybe_unused]] bool counts = false) { + auto obs_name = obs.getObsName(); + auto obs_wires = obs.getWires(); + const size_t num_qubits = _statevector.getNumQubits(); + + StateVectorT sv(_statevector); + + if (obs_name.find("PauliX") != std::string::npos) { + sv.applyOperation("Hadamard", obs_wires, false); + } else if (obs_name.find("PauliY") != std::string::npos) { + sv.applyOperation("PauliZ", obs_wires, false); + sv.applyOperation("S", obs_wires, false); + sv.applyOperation("Hadamard", obs_wires, false); + } else if (obs_name.find("Hadamard") != std::string::npos) { + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", obs_wires, false, {theta}); + } else if (obs_name.find("PauliZ")) { + } + + MeasurementsBase measure(sv); + + std::vector samples = measure.generate_samples(num_shots); + std::vector sub_samples; + std::vector obs_samples(num_shots * obs_wires.size(), 0); + + if (shot_range.empty()) { + sub_samples = samples; + } else { + // Get a slice of samples based on the shot_range vector + for (auto &i : shot_range) { + for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { + sub_samples.push_back(samples[j]); + } + } + } + + for (size_t i = 0; i < num_shots; i++) { + obs_samples[i] = + (1 - 2 * static_cast( + sub_samples[i * num_qubits + obs_wires[0]])); + } + return obs_samples; + } }; } // namespace Pennylane::Measures \ No newline at end of file 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 f76f9c022f..62bf038ace 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -288,6 +288,7 @@ class Measurements final auto expval(const Observable &obs, size_t &num_shots, std::vector &shot_range) -> PrecisionT { + /* PrecisionT result = 0; std::vector short_range = {}; auto obs_samples = samples(obs, num_shots, shot_range); @@ -299,6 +300,9 @@ class Measurements final } return result / num_elements; + */ + + return BaseType::expval(obs, num_shots, shot_range); } /** @@ -696,6 +700,7 @@ class Measurements final * * @return std::vector samples in std::vector */ + /* auto samples(const Observable &obs, size_t &num_shots, std::vector &shot_range, [[maybe_unused]] size_t bin_size = 0, @@ -707,11 +712,11 @@ class Measurements final StateVectorT sv(this->_statevector); if (obs_name.find("PauliX") != std::string::npos) { - sv.applyOperation("Hadamard", {obs_wires[0]}, false); + sv.applyOperation("Hadamard", obs_wires, false); } else if (obs_name.find("PauliY") != std::string::npos) { - sv.applyOperation("PauliZ", {obs_wires[0]}, false); - sv.applyOperation("S", {obs_wires[0]}, false); - sv.applyOperation("Hadamard", {obs_wires[0]}, false); + sv.applyOperation("PauliZ", obs_wires, false); + sv.applyOperation("S", obs_wires, false); + sv.applyOperation("Hadamard", obs_wires, false); } else if (obs_name.find("Hadamard") != std::string::npos) { const PrecisionT theta = -M_PI / 4.0; sv.applyOperation("RY", obs_wires, false, {theta}); @@ -742,6 +747,7 @@ class Measurements final } return obs_samples; } + */ /** * @brief Groups the samples into a dictionary showing number of occurences diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt index 1ea6861b8a..79b3b18e8a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(lightning_qubit_measurements_tests INTERFACE) target_link_libraries(lightning_qubit_measurements_tests INTERFACE Catch2::Catch2 lightning_measurements lightning_qubit_measurements + lightning_qubit_observables ) ProcessTestOptions(lightning_qubit_measurements_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 92d04b0925..dd0939b27e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -19,9 +19,10 @@ #include "TestHelpers.hpp" #include -#include "../../observables/ObservablesLQubit.hpp" +#include "MeasurementsBase.hpp" #include "MeasurementsLQubit.hpp" #include "Observables.hpp" +#include "ObservablesLQubit.hpp" #include "StateVectorLQubitManaged.hpp" #include "StateVectorLQubitRaw.hpp" #include "Util.hpp" @@ -33,6 +34,7 @@ /// @cond DEV namespace { using namespace Pennylane::Util; +using namespace Pennylane::Measures; using namespace Pennylane::LightningQubit; using namespace Pennylane::LightningQubit::Measures; @@ -240,7 +242,7 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots Hadamard[1]") { + SECTION("Testing for expval with obs & shots Hadamard[2]") { NamedObs obs("Hadamard", {2}); size_t num_shots = 10000; std::vector shots_range = {}; From d9cacbcd3c356615206182d5510a849d993cc1b3 Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Thu, 9 Nov 2023 20:08:00 +0000 Subject: [PATCH 05/76] 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 f3438898a8..a2ae112382 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.34.0-dev4" +__version__ = "0.34.0-dev5" From b3a21d16e6259442951610854a2e742aa61f58a9 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 22:41:23 +0000 Subject: [PATCH 06/76] add MPI support --- .../src/measurements/MeasurementsBase.hpp | 10 +- .../lightning_gpu/StateVectorCudaMPI.hpp | 2 + .../lightning_gpu/StateVectorCudaManaged.hpp | 7 + .../measurements/MeasurementsGPU.hpp | 13 + .../measurements/MeasurementsGPUMPI.hpp | 26 +- .../Test_StateVectorCudaManaged_Measure.cpp | 132 ++++++++++ .../mpi/Test_StateVectorCudaMPI_Measure.cpp | 235 ++++++++++++++++++ .../lightning_kokkos/StateVectorKokkos.hpp | 7 + .../StateVectorLQubitManaged.hpp | 7 + .../lightning_qubit/StateVectorLQubitRaw.hpp | 7 + 10 files changed, 440 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 43827a6efe..5e23f4646b 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -151,13 +151,13 @@ template class MeasurementsBase { * * @return std::vector samples in std::vector */ - auto samples(const Observable &obs, size_t &num_shots, - std::vector &shot_range, + auto samples(const Observable &obs, const size_t &num_shots, + const std::vector &shot_range, [[maybe_unused]] size_t bin_size = 0, [[maybe_unused]] bool counts = false) { auto obs_name = obs.getObsName(); auto obs_wires = obs.getWires(); - const size_t num_qubits = _statevector.getNumQubits(); + const size_t num_qubits = _statevector.getTotalNumQubits(); StateVectorT sv(_statevector); @@ -170,10 +170,10 @@ template class MeasurementsBase { } else if (obs_name.find("Hadamard") != std::string::npos) { const PrecisionT theta = -M_PI / 4.0; sv.applyOperation("RY", obs_wires, false, {theta}); - } else if (obs_name.find("PauliZ")) { + } else if (obs_name.find("PauliZ")!= std::string::npos) { } - MeasurementsBase measure(sv); + Derived measure(sv); std::vector samples = measure.generate_samples(num_shots); std::vector sub_samples; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp index db77384d71..98c0e18c03 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp @@ -204,6 +204,8 @@ class StateVectorCudaMPI final handle_.get(), mpi_manager_, 0, BaseType::getData(), numLocalQubits_, localStream_.get())), gate_cache_(true, other.getDataBuffer().getDevTag()) { + PL_CUDA_IS_SUCCESS(cudaDeviceSynchronize()); + mpi_manager_.Barrier(); BaseType::CopyGpuDataToGpuIn(other.getData(), other.getLength(), false); PL_CUDA_IS_SUCCESS(cudaDeviceSynchronize()); mpi_manager_.Barrier(); diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp index 107e436c98..b47c96100c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp @@ -141,6 +141,13 @@ class StateVectorCudaManaged ~StateVectorCudaManaged() = default; + /** + * @brief Get the total number of wires. + */ + auto getTotalNumQubits() const -> size_t { + return BaseType::getNumQubits(); + } + /** * @brief Set value for a single element of the state-vector on device. This * method is implemented by cudaMemcpy. 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 8ca6eacc69..ea87ef52e3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -350,6 +350,19 @@ class Measurements final return static_cast(expect); } + /** + * @brief Expectation value for a Observable with shots + * + * @param obs Observable. + * @param shots Vector of shot number to measurement + * @return Floating point expected value of the observable. + */ + + auto expval(const Observable &obs, size_t &num_shots, + std::vector &shot_range) -> PrecisionT { + return BaseType::expval(obs, num_shots, shot_range); + } + /** * @brief Expected value of an observable. * diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp index ff101654df..2faa2023bd 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp @@ -87,6 +87,7 @@ class MeasurementsMPI final } else { data_type_ = CUDA_C_32F; } + mpi_manager_.Barrier(); }; /** @@ -218,7 +219,7 @@ class MeasurementsMPI final * be accessed using the stride sample_id*num_qubits, where sample_id is a * number between 0 and num_samples-1. */ - auto generate_samples(size_t num_samples) -> std::vector { + auto generate_samples(size_t num_samples) -> std::vector { double epsilon = 1e-15; size_t nSubSvs = 1UL << (this->_statevector.getNumGlobalQubits()); std::vector rand_nums(num_samples); @@ -291,6 +292,7 @@ class MeasurementsMPI final precumulative = 0; } PL_CUDA_IS_SUCCESS(cudaDeviceSynchronize()); + mpi_manager_.Barrier(); // Ensure the 'custatevecSamplerApplySubSVOffset' function can be called // successfully without reducing accuracy. @@ -320,6 +322,7 @@ class MeasurementsMPI final if (mpi_manager_.getRank() == 0) { preshotOffset = 0; } + mpi_manager_.Barrier(); int nSubShots = shotOffset - preshotOffset; if (nSubShots > 0) { @@ -341,6 +344,9 @@ class MeasurementsMPI final PL_CUDA_IS_SUCCESS(cudaFree(extraWorkspace)); } + PL_CUDA_IS_SUCCESS(cudaDeviceSynchronize()); + mpi_manager_.Barrier(); + mpi_manager_.Allreduce(localBitStrings, globalBitStrings, "sum"); @@ -350,6 +356,7 @@ class MeasurementsMPI final (globalBitStrings[i] >> j) & 1U; } } + mpi_manager_.Barrier(); return samples; } @@ -486,6 +493,23 @@ class MeasurementsMPI final return static_cast(expect); } + /** + * @brief Expectation value for a Observable with shots + * + * @param obs Observable. + * @param shots Vector of shot number to measurement + * @return Floating point expected value of the observable. + */ + + auto expval(const Observable &obs, size_t &num_shots, + std::vector &shot_range) -> PrecisionT { + mpi_manager_.Barrier(); + PrecisionT result = BaseType::expval(obs, num_shots, shot_range); + mpi_manager_.Barrier(); + return result; + } + + /** * @brief Expected value of an observable. * diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp index 679cd4855a..960aceb445 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp @@ -121,6 +121,138 @@ TEMPLATE_TEST_CASE("Expected Values", "[Measurements]", float, double) { LightningException, "Currently unsupported observable"); } + + SECTION("Testing for expval with obs & shots PauliX[0]") { + NamedObs obs("PauliX", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.49272486; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliX[1]") { + NamedObs obs("PauliX", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.42073549; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliX[2]") { + NamedObs obs("PauliX", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.28232124; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[0]") { + NamedObs obs("PauliY", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.64421768; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[1]") { + NamedObs obs("PauliY", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.47942553; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[2]") { + NamedObs obs("PauliY", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.29552020; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[0]") { + NamedObs obs("PauliZ", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.58498357; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[1]") { + NamedObs obs("PauliZ", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.77015115; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[2]") { + NamedObs obs("PauliZ", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.91266780; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[0]") { + NamedObs obs("Hadamard", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.7620549436; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[1]") { + NamedObs obs("Hadamard", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.8420840225; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[2]") { + NamedObs obs("Hadamard", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.8420840225; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } } TEMPLATE_TEST_CASE("Pauli word based API", "[Measurements]", float, double) { diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp index 553cf1bfb4..d01ff70f1b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp @@ -21,6 +21,8 @@ #include +#include "ObservablesGPU.hpp" +#include "ObservablesGPUMPI.hpp" #include "MPIManager.hpp" #include "MeasurementsGPU.hpp" #include "MeasurementsGPUMPI.hpp" @@ -187,6 +189,239 @@ TEMPLATE_TEST_CASE("Expected Values", "[MeasurementsMPI]", float, double) { LightningException, "Currently unsupported observable"); } + + SECTION("Testing for expval with obs & shots PauliX[0]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliX", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + mpi_manager.Barrier(); + + PrecisionT expval_ref = 0.49272486; + + CHECK((expval_shot) == Approx(expval_ref).margin(5e-2)); + } + + + SECTION("Testing for expval with obs & shots PauliX[1]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliX", {1}); + + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.42073549; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliX[2]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliX", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.28232124; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[0]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliY", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.64421768; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[1]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliY", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.47942553; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliY[2]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliY", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = -0.29552020; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[0]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliZ", {0}); + + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.58498357; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[1]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliZ", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.77015115; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots PauliZ[2]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("PauliZ", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.91266780; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[0]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("Hadamard", {0}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.7620549436; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[1]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("Hadamard", {1}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.8420840225; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } + + SECTION("Testing for expval with obs & shots Hadamard[2]") { + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + NamedObsMPI obs("Hadamard", {2}); + size_t num_shots = 10000; + std::vector shots_range = {}; + + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); + + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + PrecisionT expval_ref = 0.8420840225; + + CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + } } TEMPLATE_TEST_CASE("Pauliwords base on expval", "[MeasurementsMPI]", float, diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp index 02064e811f..bc41557015 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp @@ -112,6 +112,13 @@ class StateVectorKokkos final init_generators_indices_(); }; + /** + * @brief Get the total number of wires. + */ + auto getTotalNumQubits() const -> size_t { + return BaseType::getNumQubits(); + } + /** * @brief Init zeros for the state-vector on device. */ diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp index add76efeb0..3cf00b5aba 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp @@ -139,6 +139,13 @@ class StateVectorLQubitManaged final ~StateVectorLQubitManaged() = default; + /** + * @brief Get the total number of wires. + */ + auto getTotalNumQubits() const -> size_t { + return BaseType::getNumQubits(); + } + [[nodiscard]] auto getData() -> ComplexT * { return data_.data(); } [[nodiscard]] auto getData() const -> const ComplexT * { diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp index 167a0b22f1..65c529ef62 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp @@ -86,6 +86,13 @@ class StateVectorLQubitRaw final "The size of provided data must be a power of 2."); } + /** + * @brief Get the total number of wires. + */ + auto getTotalNumQubits() const -> size_t { + return BaseType::getNumQubits(); + } + /** * @brief Get the underlying data pointer. * From 62b371447be8d7be9bf4b4b2b3e094a0a6db5bef Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 22:55:27 +0000 Subject: [PATCH 07/76] add samples_to_counts to measurement base class --- .../src/measurements/MeasurementsBase.hpp | 42 ++++++ .../measurements/MeasurementsLQubit.hpp | 123 ------------------ 2 files changed, 42 insertions(+), 123 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 5e23f4646b..d209d8ad0b 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -24,6 +24,15 @@ /// @cond DEV namespace { using namespace Pennylane::Observables; + +auto sample_to_str(std::vector &sample) -> std::string { + std::string str; + for (auto &element : sample) { + str += std::to_string(element); + } + return str; +} + } // namespace /// @endcond @@ -197,6 +206,39 @@ template class MeasurementsBase { } return obs_samples; } + + /** + * @brief Groups the samples into a dictionary showing number of occurences + * for each possible outcome. + * + * @param samples A vector of samples with size of ``num_shots * + * num_obs_wires`` + * @param num_wires number of wires the sampled observable was performed on + * + * @return std::unordered_map with format ``{'outcome': + * num_occurences}`` + */ + auto samples_to_counts(std::vector &samples, size_t &num_shots, + size_t &num_obs_wires) + -> std::unordered_map { + std::unordered_map outcome_map; + + for (size_t i = 0; i < num_shots; i++) { + auto local_sample = + std::vector(samples.begin() + i * num_obs_wires, + samples.begin() + (i + 1) * num_obs_wires - 1); + std::string key = sample_to_str(local_sample); + + auto it = outcome_map.find(key); + + if (it != outcome_map.end()) { + it->second += 1; + } else { + outcome_map[key] = 1; + } + } + return outcome_map; + } }; } // namespace Pennylane::Measures \ No newline at end of file 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 62bf038ace..2ad3fa8205 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -44,16 +44,6 @@ using namespace Pennylane::Measures; using namespace Pennylane::Observables; using Pennylane::LightningQubit::StateVectorLQubitManaged; using Pennylane::LightningQubit::Util::innerProdC; - -/* -auto sample_to_str(std::vector &sample) -> std::string { - std::string str; - for (auto &element : sample) { - str += std::to_string(element); - } - return str; -} -*/ } // namespace /// @endcond @@ -288,20 +278,6 @@ class Measurements final auto expval(const Observable &obs, size_t &num_shots, std::vector &shot_range) -> PrecisionT { - /* - PrecisionT result = 0; - std::vector short_range = {}; - auto obs_samples = samples(obs, num_shots, shot_range); - - size_t num_elements = 0; - for (int element : obs_samples) { - result += element; - num_elements++; - } - - return result / num_elements; - */ - return BaseType::expval(obs, num_shots, shot_range); } @@ -684,104 +660,5 @@ class Measurements final } return init_idx; } - - public: - /** - * @brief Return samples of a observable - * - * @param obs The observable to sample - * @param num_shots Number of shots used to generate samples - * @param shot_range The range of samples to use. If it's empty, all samples - * are used. - * @param bin_size Divides the shot range into bins of size ``bin_size``, - * and returns the measurement statistic separately over each bin. - * @param counts Whether count("True") or raw samples ("False") should be - * retruned - * - * @return std::vector samples in std::vector - */ - /* - auto samples(const Observable &obs, size_t &num_shots, - std::vector &shot_range, - [[maybe_unused]] size_t bin_size = 0, - [[maybe_unused]] bool counts = false) { - auto obs_name = obs.getObsName(); - auto obs_wires = obs.getWires(); - const size_t num_qubits = this->_statevector.getNumQubits(); - - StateVectorT sv(this->_statevector); - - if (obs_name.find("PauliX") != std::string::npos) { - sv.applyOperation("Hadamard", obs_wires, false); - } else if (obs_name.find("PauliY") != std::string::npos) { - sv.applyOperation("PauliZ", obs_wires, false); - sv.applyOperation("S", obs_wires, false); - sv.applyOperation("Hadamard", obs_wires, false); - } else if (obs_name.find("Hadamard") != std::string::npos) { - const PrecisionT theta = -M_PI / 4.0; - sv.applyOperation("RY", obs_wires, false, {theta}); - } else if (obs_name.find("PauliZ")) { - } - - Measurements measure(sv); - - std::vector samples = measure.generate_samples(num_shots); - std::vector sub_samples; - std::vector obs_samples(num_shots * obs_wires.size(), 0); - - if (shot_range.empty()) { - sub_samples = samples; - } else { - // Get a slice of samples based on the shot_range vector - for (auto &i : shot_range) { - for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { - sub_samples.push_back(samples[j]); - } - } - } - - for (size_t i = 0; i < num_shots; i++) { - obs_samples[i] = - (1 - 2 * static_cast( - sub_samples[i * num_qubits + obs_wires[0]])); - } - return obs_samples; - } - */ - - /** - * @brief Groups the samples into a dictionary showing number of occurences - * for each possible outcome. - * - * @param samples A vector of samples with size of ``num_shots * - * num_obs_wires`` - * @param num_wires number of wires the sampled observable was performed on - * - * @return std::unordered_map with format ``{'outcome': - * num_occurences}`` - */ - /* - auto _samples_to_counts(std::vector &samples, size_t &num_shots, - size_t &num_obs_wires) - -> std::unordered_map { - std::unordered_map outcome_map; - - for (size_t i = 0; i < num_shots; i++) { - auto local_sample = - std::vector(samples.begin() + i * num_obs_wires, - samples.begin() + (i + 1) * num_obs_wires - 1); - std::string key = sample_to_str(local_sample); - - auto it = outcome_map.find(key); - - if (it != outcome_map.end()) { - it->second += 1; - } else { - outcome_map[key] = 1; - } - } - return outcome_map; - } - */ }; // class Measurements } // namespace Pennylane::LightningQubit::Measures \ No newline at end of file From 05cfb89d32d8d9985a9d33c69ea50d9dd9b77d5d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 23:21:10 +0000 Subject: [PATCH 08/76] tidy up tests --- .../Test_StateVectorCudaManaged_Measure.cpp | 148 +++------- .../mpi/Test_StateVectorCudaMPI_Measure.cpp | 257 +++++------------- .../tests/Test_MeasurementsLQubit.cpp | 147 +++------- 3 files changed, 152 insertions(+), 400 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp index 960aceb445..b4ce24533d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp @@ -122,136 +122,76 @@ TEMPLATE_TEST_CASE("Expected Values", "[Measurements]", float, double) { "Currently unsupported observable"); } - SECTION("Testing for expval with obs & shots PauliX[0]") { - NamedObs obs("PauliX", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.49272486; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliX[1]") { - NamedObs obs("PauliX", {1}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.42073549; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliX[2]") { - NamedObs obs("PauliX", {2}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.28232124; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY[0]") { - NamedObs obs("PauliY", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.64421768; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY[1]") { - NamedObs obs("PauliY", {1}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.47942553; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots PauliX") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots PauliY[2]") { - NamedObs obs("PauliY", {2}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.29552020; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("PauliX", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.49272486, 0.42073549, 0.28232124}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots PauliZ[0]") { - NamedObs obs("PauliZ", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.58498357; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots PauliY") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots PauliZ[1]") { - NamedObs obs("PauliZ", {1}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.77015115; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("PauliY", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {-0.64421768, -0.47942553, -0.29552020}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots PauliZ[2]") { - NamedObs obs("PauliZ", {2}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.91266780; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots PauliZ") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots Hadamard[0]") { - NamedObs obs("Hadamard", {0}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.7620549436; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("PauliZ", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots Hadamard[1]") { - NamedObs obs("Hadamard", {1}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.8420840225; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots Hadamard") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots Hadamard[2]") { - NamedObs obs("Hadamard", {2}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.8420840225; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("Hadamard", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.7620549436, 0.8420840225, 0.8449848566}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } } diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp index d01ff70f1b..f849da2dc6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp @@ -190,237 +190,108 @@ TEMPLATE_TEST_CASE("Expected Values", "[MeasurementsMPI]", float, double) { "Currently unsupported observable"); } - SECTION("Testing for expval with obs & shots PauliX[0]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - NamedObsMPI obs("PauliX", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - mpi_manager.Barrier(); - - PrecisionT expval_ref = 0.49272486; - - CHECK((expval_shot) == Approx(expval_ref).margin(5e-2)); - } - - - SECTION("Testing for expval with obs & shots PauliX[1]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - NamedObsMPI obs("PauliX", {1}); - - size_t num_shots = 10000; - std::vector shots_range = {}; - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.42073549; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliX[2]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - NamedObsMPI obs("PauliX", {2}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.28232124; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY[0]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - NamedObsMPI obs("PauliY", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.64421768; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY[1]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); + SECTION("Testing for expval with obs & shots PauliX") { + std::vector exp_values; + std::vector exp_values_ref; - NamedObsMPI obs("PauliY", {1}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.47942553; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY[2]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + for(size_t i = 0; i < num_qubits; i++){ + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); - NamedObsMPI obs("PauliY", {2}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.29552020; + NamedObsMPI obs("PauliX", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.49272486, 0.42073549, 0.28232124}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots PauliZ[0]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - NamedObsMPI obs("PauliZ", {0}); + SECTION("Testing for expval with obs & shots PauliY") { + std::vector exp_values; + std::vector exp_values_ref; size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.58498357; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliZ[1]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + for(size_t i = 0; i < num_qubits; i++){ + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); - NamedObsMPI obs("PauliZ", {1}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.77015115; + NamedObs obs("PauliY", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {-0.64421768, -0.47942553, -0.29552020}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots PauliZ[2]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); + SECTION("Testing for expval with obs & shots PauliZ") { + std::vector exp_values; + std::vector exp_values_ref; - NamedObsMPI obs("PauliZ", {2}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.91266780; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots Hadamard[0]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + for(size_t i = 0; i < num_qubits; i++){ + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); - NamedObsMPI obs("Hadamard", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.7620549436; + NamedObs obs("PauliZ", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots Hadamard[1]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); + SECTION("Testing for expval with obs & shots Hadamard") { + std::vector exp_values; + std::vector exp_values_ref; - NamedObsMPI obs("Hadamard", {1}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.8420840225; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots Hadamard[2]") { - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + for(size_t i = 0; i < num_qubits; i++){ + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); - NamedObsMPI obs("Hadamard", {2}); - size_t num_shots = 10000; - std::vector shots_range = {}; + MeasurementsMPI Measurer(sv); + mpi_manager.Barrier(); - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.8420840225; + NamedObs obs("Hadamard", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.7620549436, 0.8420840225, 0.8449848566}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index dd0939b27e..0a32234635 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -121,136 +121,77 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(1e-6)); } - SECTION("Testing for expval with obs & shots PauliX[0]") { - NamedObs obs("PauliX", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.49272486; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliX[1]") { - NamedObs obs("PauliX", {1}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.42073549; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliX[2]") { - NamedObs obs("PauliX", {2}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.28232124; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY[0]") { - NamedObs obs("PauliY", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.64421768; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY[1]") { - NamedObs obs("PauliY", {1}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.47942553; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots PauliX") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots PauliY[2]") { - NamedObs obs("PauliY", {2}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = -0.29552020; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("PauliX", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.49272486, 0.42073549, 0.28232124}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots PauliZ[0]") { - NamedObs obs("PauliZ", {0}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.58498357; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots PauliY") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots PauliZ[1]") { - NamedObs obs("PauliZ", {1}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.77015115; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("PauliY", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {-0.64421768, -0.47942553, -0.29552020}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots PauliZ[2]") { - NamedObs obs("PauliZ", {2}); - size_t num_shots = 10000; - std::vector shots_range = {}; - - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.91266780; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots PauliZ") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots Hadamard[0]") { - NamedObs obs("Hadamard", {0}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.7620549436; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("PauliZ", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } - SECTION("Testing for expval with obs & shots Hadamard[1]") { - NamedObs obs("Hadamard", {1}); - size_t num_shots = 10000; - std::vector shots_range = {}; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.8420840225; - - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); - } + SECTION("Testing for expval with obs & shots Hadamard") { + std::vector exp_values; + std::vector exp_values_ref; - SECTION("Testing for expval with obs & shots Hadamard[2]") { - NamedObs obs("Hadamard", {2}); size_t num_shots = 10000; std::vector shots_range = {}; + size_t num_qubits = 3; - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - PrecisionT expval_ref = 0.8420840225; + for(size_t i = 0; i < num_qubits; i++){ + NamedObs obs("Hadamard", {i}); + auto expval_shot = Measurer.expval(obs, num_shots, shots_range); + exp_values.push_back(expval_shot); + } + exp_values_ref = {0.7620549436, 0.8420840225, 0.8449848566}; - CHECK(expval_shot == Approx(expval_ref).margin(5e-2)); + REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); } } From ddfdb727eed80f91d5881dbd661a278991a3eeee Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 23:36:36 +0000 Subject: [PATCH 09/76] move tests to measurement base --- .../tests/Test_MeasurementsBase.cpp | 52 ++++++++++++- .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 74 +++++++++++++++++++ .../Test_StateVectorCudaManaged_Measure.cpp | 72 ------------------ .../tests/Test_MeasurementsLQubit.cpp | 73 ------------------ 4 files changed, 125 insertions(+), 146 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 7626ea835c..eb16a0849b 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -187,12 +187,62 @@ template void testNamedObsExpval() { } } -TEST_CASE("Expval - NamedObs", "[MeasurementsBase][Observables]") { +TEST_CASE("Expval Shot - NamedObs", "[MeasurementsBase][Observables]") { if constexpr (BACKEND_FOUND) { testNamedObsExpval(); } } +template void testNamedObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + + // Defining the State Vector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + std::vector> wires_list = {{0}, {1}, {2}}; + std::vector obs_name = {"PauliX", "PauliY", "PauliZ", "Hadamard"}; + // Expected results calculated with Pennylane default.qubit: + std::vector> exp_values_ref = { + {0.49272486, 0.42073549, 0.28232124}, + {-0.64421768, -0.47942553, -0.29552020}, + {0.58498357, 0.77015115, 0.91266780}, + {0.7620549436, 0.8420840225, 0.8449848566}}; + + size_t num_shots = 10000; + std::vector shots_range = {}; + + for (size_t ind_obs = 0; ind_obs < obs_name.size(); ind_obs++) { + DYNAMIC_SECTION(obs_name[ind_obs] + << " - Varying wires" + << StateVectorToName::name) { + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObs obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + PrecisionT result = Measurer.expval(obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(2e-2)); + } + } + } + testNamedObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot- NamedObs", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testNamedObsExpvalShot(); + } +} + template void testHermitianObsExpval() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index b459f762a5..efeae96232 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -187,6 +187,80 @@ TEST_CASE("Expval - NamedObs", "[MeasurementsBase][Observables]") { } } +template void testNamedObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + + // Defining the State Vector that will be measured. + auto statevector_data = + createNonTrivialState>(); + + size_t num_qubits = 3; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + auto sv_data_local = mpi_manager.scatter(statevector_data, 0); + + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + // Initializing the measurements class. + // This object attaches to the statevector allowing several measures. + MeasurementsMPI Measurer(sv); + + std::vector> wires_list = {{0}, {1}, {2}}; + std::vector obs_name = {"PauliX", "PauliY", "PauliZ", "Hadamard"}; + // Expected results calculated with Pennylane default.qubit: + std::vector> exp_values_ref = { + {0.49272486, 0.42073549, 0.28232124}, + {-0.64421768, -0.47942553, -0.29552020}, + {0.58498357, 0.77015115, 0.91266780}, + {0.7620549436, 0.8420840225, 0.8449848566}}; + + size_t num_shots = 10000; + std::vector shots_range = {}; + + for (size_t ind_obs = 0; ind_obs < obs_name.size(); ind_obs++) { + DYNAMIC_SECTION(obs_name[ind_obs] + << " - Varying wires" + << StateVectorMPIToName::name) { + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObsMPI obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + PrecisionT result = Measurer.expval(obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(2e-2)); + } + } + } + testNamedObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot- NamedObs", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testNamedObsExpvalShot(); + } +} + template void testHermitianObsExpval() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp index b4ce24533d..679cd4855a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Measure.cpp @@ -121,78 +121,6 @@ TEMPLATE_TEST_CASE("Expected Values", "[Measurements]", float, double) { LightningException, "Currently unsupported observable"); } - - SECTION("Testing for expval with obs & shots PauliX") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("PauliX", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.49272486, 0.42073549, 0.28232124}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("PauliY", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {-0.64421768, -0.47942553, -0.29552020}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliZ") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("PauliZ", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots Hadamard") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("Hadamard", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.7620549436, 0.8420840225, 0.8449848566}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } } TEMPLATE_TEST_CASE("Pauli word based API", "[Measurements]", float, double) { diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 0a32234635..74e7952efc 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -120,79 +120,6 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(1e-6)); } - - SECTION("Testing for expval with obs & shots PauliX") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("PauliX", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.49272486, 0.42073549, 0.28232124}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("PauliY", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {-0.64421768, -0.47942553, -0.29552020}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliZ") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("PauliZ", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - - SECTION("Testing for expval with obs & shots Hadamard") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - NamedObs obs("Hadamard", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.7620549436, 0.8420840225, 0.8449848566}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } } TEMPLATE_PRODUCT_TEST_CASE("Variances", "[Measurements]", From 44df7652b77ffa83869739bb1c724a1d28bff8cd Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 23:38:44 +0000 Subject: [PATCH 10/76] move mpi tests to measurement base class --- .../mpi/Test_StateVectorCudaMPI_Measure.cpp | 104 ------------------ 1 file changed, 104 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp index f849da2dc6..2cc2591fa5 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp @@ -189,110 +189,6 @@ TEMPLATE_TEST_CASE("Expected Values", "[MeasurementsMPI]", float, double) { LightningException, "Currently unsupported observable"); } - - SECTION("Testing for expval with obs & shots PauliX") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - NamedObsMPI obs("PauliX", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.49272486, 0.42073549, 0.28232124}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliY") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - NamedObs obs("PauliY", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {-0.64421768, -0.47942553, -0.29552020}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots PauliZ") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - NamedObs obs("PauliZ", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.58498357, 0.77015115, 0.91266780}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } - - SECTION("Testing for expval with obs & shots Hadamard") { - std::vector exp_values; - std::vector exp_values_ref; - - size_t num_shots = 10000; - std::vector shots_range = {}; - size_t num_qubits = 3; - - for(size_t i = 0; i < num_qubits; i++){ - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); - mpi_manager.Barrier(); - - MeasurementsMPI Measurer(sv); - mpi_manager.Barrier(); - - NamedObs obs("Hadamard", {i}); - auto expval_shot = Measurer.expval(obs, num_shots, shots_range); - exp_values.push_back(expval_shot); - } - exp_values_ref = {0.7620549436, 0.8420840225, 0.8449848566}; - - REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(5e-2)); - } } TEMPLATE_TEST_CASE("Pauliwords base on expval", "[MeasurementsMPI]", float, From b3931e9e4df0b46db5ea22776ebc450a7a66351b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 9 Nov 2023 23:46:56 +0000 Subject: [PATCH 11/76] make format --- .../core/src/measurements/MeasurementsBase.hpp | 4 ++-- .../core/src/measurements/tests/Test_MeasurementsBase.cpp | 8 +++++--- .../measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp | 8 +++++--- .../lightning_gpu/measurements/MeasurementsGPUMPI.hpp | 3 +-- .../tests/mpi/Test_StateVectorCudaMPI_Measure.cpp | 2 -- .../lightning_qubit/measurements/tests/CMakeLists.txt | 1 - .../measurements/tests/Test_MeasurementsLQubit.cpp | 6 ------ 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index d209d8ad0b..4d285ffee9 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -179,7 +179,7 @@ template class MeasurementsBase { } else if (obs_name.find("Hadamard") != std::string::npos) { const PrecisionT theta = -M_PI / 4.0; sv.applyOperation("RY", obs_wires, false, {theta}); - } else if (obs_name.find("PauliZ")!= std::string::npos) { + } else if (obs_name.find("PauliZ") != std::string::npos) { } Derived measure(sv); @@ -219,7 +219,7 @@ template class MeasurementsBase { * num_occurences}`` */ auto samples_to_counts(std::vector &samples, size_t &num_shots, - size_t &num_obs_wires) + size_t &num_obs_wires) -> std::unordered_map { std::unordered_map outcome_map; diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index eb16a0849b..458665ff17 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -208,14 +208,15 @@ template void testNamedObsExpvalShot() { Measurements Measurer(statevector); std::vector> wires_list = {{0}, {1}, {2}}; - std::vector obs_name = {"PauliX", "PauliY", "PauliZ", "Hadamard"}; + std::vector obs_name = {"PauliX", "PauliY", "PauliZ", + "Hadamard"}; // Expected results calculated with Pennylane default.qubit: std::vector> exp_values_ref = { {0.49272486, 0.42073549, 0.28232124}, {-0.64421768, -0.47942553, -0.29552020}, {0.58498357, 0.77015115, 0.91266780}, {0.7620549436, 0.8420840225, 0.8449848566}}; - + size_t num_shots = 10000; std::vector shots_range = {}; @@ -228,7 +229,8 @@ template void testNamedObsExpvalShot() { NamedObs obs(obs_name[ind_obs], wires_list[ind_wires]); PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; - PrecisionT result = Measurer.expval(obs, num_shots, shots_range); + PrecisionT result = + Measurer.expval(obs, num_shots, shots_range); REQUIRE(expected == Approx(result).margin(2e-2)); } } diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index efeae96232..3a69782a2d 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -226,14 +226,15 @@ template void testNamedObsExpvalShot() { MeasurementsMPI Measurer(sv); std::vector> wires_list = {{0}, {1}, {2}}; - std::vector obs_name = {"PauliX", "PauliY", "PauliZ", "Hadamard"}; + std::vector obs_name = {"PauliX", "PauliY", "PauliZ", + "Hadamard"}; // Expected results calculated with Pennylane default.qubit: std::vector> exp_values_ref = { {0.49272486, 0.42073549, 0.28232124}, {-0.64421768, -0.47942553, -0.29552020}, {0.58498357, 0.77015115, 0.91266780}, {0.7620549436, 0.8420840225, 0.8449848566}}; - + size_t num_shots = 10000; std::vector shots_range = {}; @@ -246,7 +247,8 @@ template void testNamedObsExpvalShot() { NamedObsMPI obs(obs_name[ind_obs], wires_list[ind_wires]); PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; - PrecisionT result = Measurer.expval(obs, num_shots, shots_range); + PrecisionT result = + Measurer.expval(obs, num_shots, shots_range); REQUIRE(expected == Approx(result).margin(2e-2)); } } diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp index 2faa2023bd..c51604b914 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp @@ -219,7 +219,7 @@ class MeasurementsMPI final * be accessed using the stride sample_id*num_qubits, where sample_id is a * number between 0 and num_samples-1. */ - auto generate_samples(size_t num_samples) -> std::vector { + auto generate_samples(size_t num_samples) -> std::vector { double epsilon = 1e-15; size_t nSubSvs = 1UL << (this->_statevector.getNumGlobalQubits()); std::vector rand_nums(num_samples); @@ -509,7 +509,6 @@ class MeasurementsMPI final return result; } - /** * @brief Expected value of an observable. * diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp index 2cc2591fa5..553cf1bfb4 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Measure.cpp @@ -21,8 +21,6 @@ #include -#include "ObservablesGPU.hpp" -#include "ObservablesGPUMPI.hpp" #include "MPIManager.hpp" #include "MeasurementsGPU.hpp" #include "MeasurementsGPUMPI.hpp" diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt index 79b3b18e8a..1ea6861b8a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt @@ -18,7 +18,6 @@ add_library(lightning_qubit_measurements_tests INTERFACE) target_link_libraries(lightning_qubit_measurements_tests INTERFACE Catch2::Catch2 lightning_measurements lightning_qubit_measurements - lightning_qubit_observables ) ProcessTestOptions(lightning_qubit_measurements_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 74e7952efc..35e7280be1 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -19,10 +19,7 @@ #include "TestHelpers.hpp" #include -#include "MeasurementsBase.hpp" #include "MeasurementsLQubit.hpp" -#include "Observables.hpp" -#include "ObservablesLQubit.hpp" #include "StateVectorLQubitManaged.hpp" #include "StateVectorLQubitRaw.hpp" #include "Util.hpp" @@ -34,12 +31,9 @@ /// @cond DEV namespace { using namespace Pennylane::Util; -using namespace Pennylane::Measures; using namespace Pennylane::LightningQubit; using namespace Pennylane::LightningQubit::Measures; -using namespace Pennylane::LightningQubit::Observables; - }; // namespace /// @endcond From 3a521848f82c575017af7293da77fa36790cb0b8 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 10 Nov 2023 00:54:15 +0000 Subject: [PATCH 12/76] add python layer --- .../core/src/bindings/Bindings.hpp | 17 +++++ .../core/src/bindings/BindingsMPI.hpp | 17 +++++ .../src/measurements/MeasurementsBase.hpp | 4 +- .../measurements/MeasurementsGPU.hpp | 4 +- .../measurements/MeasurementsGPUMPI.hpp | 4 +- .../measurements/MeasurementsLQubit.hpp | 4 +- .../lightning_gpu/lightning_gpu.py | 13 +++- .../lightning_kokkos/lightning_kokkos.py | 14 +++- .../lightning_qubit/lightning_qubit.py | 14 +++- tests/conftest.py | 12 ++++ tests/test_expval.py | 69 +++++++++++++++++++ 11 files changed, 156 insertions(+), 16 deletions(-) diff --git a/pennylane_lightning/core/src/bindings/Bindings.hpp b/pennylane_lightning/core/src/bindings/Bindings.hpp index 1368ee3a94..266e1b7959 100644 --- a/pennylane_lightning/core/src/bindings/Bindings.hpp +++ b/pennylane_lightning/core/src/bindings/Bindings.hpp @@ -439,6 +439,23 @@ void registerBackendAgnosticMeasurements(PyClass &pyclass) { return M.expval(*ob); }, "Expected value of an observable object.") + .def( + "expval", + [](Measurements &M, + const std::shared_ptr> &ob, + const size_t &num_shots) { + const std::vector &shot_range = {}; + return M.expval(*ob, num_shots, shot_range); + }, + "Expected value of an observable object.") + .def( + "expval", + [](Measurements &M, + const std::shared_ptr> &ob, + const size_t &num_shots, const std::vector &shot_range) { + return M.expval(*ob, num_shots, shot_range); + }, + "Expected value of an observable object.") .def( "var", [](Measurements &M, diff --git a/pennylane_lightning/core/src/bindings/BindingsMPI.hpp b/pennylane_lightning/core/src/bindings/BindingsMPI.hpp index 41276afe5d..7ab4166501 100644 --- a/pennylane_lightning/core/src/bindings/BindingsMPI.hpp +++ b/pennylane_lightning/core/src/bindings/BindingsMPI.hpp @@ -269,6 +269,23 @@ void registerBackendAgnosticMeasurementsMPI(PyClass &pyclass) { return M.expval(*ob); }, "Expected value of an observable object.") + .def( + "expval", + [](MeasurementsMPI &M, + const std::shared_ptr> &ob, + const size_t &num_shots) { + const std::vector &shot_range = {}; + return M.expval(*ob, num_shots, shot_range); + }, + "Expected value of an observable object.") + .def( + "expval", + [](MeasurementsMPI &M, + const std::shared_ptr> &ob, + const size_t &num_shots, const std::vector &shot_range) { + return M.expval(*ob, num_shots, shot_range); + }, + "Expected value of an observable object.") .def( "var", [](MeasurementsMPI &M, diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 4d285ffee9..7c96967337 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -131,8 +131,8 @@ template class MeasurementsBase { * * @return Expectation value with respect to the given observable. */ - auto expval(const Observable &obs, size_t &num_shots, - std::vector &shot_range) -> PrecisionT { + auto expval(const Observable &obs, const size_t &num_shots, + const std::vector &shot_range) -> PrecisionT { PrecisionT result = 0; std::vector short_range = {}; auto obs_samples = samples(obs, num_shots, shot_range); 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 ea87ef52e3..cbf4bc5c8a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -358,8 +358,8 @@ class Measurements final * @return Floating point expected value of the observable. */ - auto expval(const Observable &obs, size_t &num_shots, - std::vector &shot_range) -> PrecisionT { + auto expval(const Observable &obs, const size_t &num_shots, + const std::vector &shot_range) -> PrecisionT { return BaseType::expval(obs, num_shots, shot_range); } diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp index c51604b914..bd2a96a147 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp @@ -501,8 +501,8 @@ class MeasurementsMPI final * @return Floating point expected value of the observable. */ - auto expval(const Observable &obs, size_t &num_shots, - std::vector &shot_range) -> PrecisionT { + auto expval(const Observable &obs, const size_t &num_shots, + const std::vector &shot_range) -> PrecisionT { mpi_manager_.Barrier(); PrecisionT result = BaseType::expval(obs, num_shots, shot_range); mpi_manager_.Barrier(); 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 2ad3fa8205..e58f369251 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -276,8 +276,8 @@ class Measurements final * @return Floating point expected value of the observable. */ - auto expval(const Observable &obs, size_t &num_shots, - std::vector &shot_range) -> PrecisionT { + auto expval(const Observable &obs, const size_t &num_shots, + const std::vector &shot_range) -> PrecisionT { return BaseType::expval(obs, num_shots, shot_range); } diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index 177275ec13..22f8d58c19 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -830,8 +830,17 @@ def expval(self, observable, shot_range=None, bin_size=None): """ if self.shots is not None: # estimate the expectation value - samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) - return np.squeeze(np.mean(samples, axis=0)) + if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: + obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( + observable, self.wire_map + ) + + if shot_range is None: + return self.measurements.expval(obs, self.shots) + else: + return self.measurements.expval(obs, self.shots, shot_range) + else: + raise RuntimeError(f"{observable.name} obs does not support.") if observable.name in ["SparseHamiltonian"]: if self._mpi: diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 56cda8f92c..35a717aeba 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -469,9 +469,17 @@ def expval(self, observable, shot_range=None, bin_size=None): if self.shots is not None: # estimate the expectation value - # LightningQubit doesn't support sampling yet - samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) - return np.squeeze(np.mean(samples, axis=0)) + if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: + obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( + observable, self.wire_map + ) + + if shot_range is None: + return self.measurements.expval(obs, self.shots) + else: + return self.measurements.expval(obs, self.shots, shot_range) + else: + raise RuntimeError(f"{observable.name} obs does not support.") # Initialization of state measure = ( diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 9a4d4f5b35..4aa73d37c8 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -423,9 +423,17 @@ def expval(self, observable, shot_range=None, bin_size=None): if self.shots is not None: # estimate the expectation value - # LightningQubit doesn't support sampling yet - samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) - return np.squeeze(np.mean(samples, axis=0)) + if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: + obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( + observable, self.wire_map + ) + + if shot_range is None: + return self.measurements.expval(obs, self.shots) + else: + return self.measurements.expval(obs, self.shots, shot_range) + else: + raise RuntimeError(f"{observable.name} obs does not support.") # Initialization of state ket = np.ravel(self._pre_rotated_state) diff --git a/tests/conftest.py b/tests/conftest.py index 7bfb8c5b69..f636f44ec9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -136,3 +136,15 @@ def _device(wires): return qml.device(device_name, wires=wires, c_dtype=request.param) return _device + + +# General qubit_device fixture, for any number of wires. +@pytest.fixture( + scope="function", + params=[np.complex64, np.complex128], +) +def qubit_device_shots(request): + def _device(wires): + return qml.device(device_name, wires=wires, c_dtype=request.param, shots=10000) + + return _device diff --git a/tests/test_expval.py b/tests/test_expval.py index e64ef2a329..fc8622e06b 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -41,6 +41,22 @@ def test_identity_expectation(self, theta, phi, qubit_device, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([1, 1]), tol) + def test_pauliz_expectation(self, theta, phi, qubit_device_shots): + """Test that PauliZ expectation value is correct""" + TOL = 5e-2 + dev = qubit_device_shots(wires=3) + + O1 = qml.PauliZ(wires=[0]) + O2 = qml.PauliZ(wires=[1]) + + dev.apply( + [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)]) + assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), atol=TOL) + def test_pauliz_expectation(self, theta, phi, qubit_device, tol): """Test that PauliZ expectation value is correct""" dev = qubit_device(wires=3) @@ -73,6 +89,24 @@ def test_paulix_expectation(self, theta, phi, qubit_device, tol): res, np.array([np.sin(theta) * np.sin(phi), np.sin(phi)], dtype=dev.C_DTYPE), tol * 10 ) + def test_paulix_expectation(self, theta, phi, qubit_device_shots): + """Test that PauliX expectation value is correct""" + TOL = 5e-2 + dev = qubit_device_shots(wires=3) + + O1 = qml.PauliX(wires=[0]) + O2 = qml.PauliX(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)], dtype=dev.C_DTYPE) + assert np.allclose( + res, np.array([np.sin(theta) * np.sin(phi), np.sin(phi)], dtype=dev.C_DTYPE), atol=TOL + ) + def test_pauliy_expectation(self, theta, phi, qubit_device, tol): """Test that PauliY expectation value is correct""" dev = qubit_device(wires=3) @@ -88,6 +122,22 @@ def test_pauliy_expectation(self, theta, phi, qubit_device, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), tol) + def test_pauliy_expectation(self, theta, phi, qubit_device_shots): + """Test that PauliY expectation value is correct""" + TOL = 5e-2 + dev = qubit_device_shots(wires=3) + + O1 = qml.PauliY(wires=[0]) + O2 = qml.PauliY(wires=[1]) + + dev.apply( + [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)]) + assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), atol=TOL) + def test_hadamard_expectation(self, theta, phi, qubit_device, tol): """Test that Hadamard expectation value is correct""" dev = qubit_device(wires=3) @@ -106,6 +156,25 @@ def test_hadamard_expectation(self, theta, phi, qubit_device, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) + def test_hadamard_expectation(self, theta, phi, qubit_device_shots): + """Test that Hadamard expectation value is correct""" + TOL = 5e-2 + dev = qubit_device_shots(wires=3) + + O1 = qml.Hadamard(wires=[0]) + O2 = qml.Hadamard(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)]) + expected = np.array( + [np.sin(theta) * np.sin(phi) + np.cos(theta), np.cos(theta) * np.cos(phi) + np.sin(phi)] + ) / np.sqrt(2) + assert np.allclose(res, expected, atol=TOL) + @pytest.mark.parametrize("n_wires", range(1, 7)) def test_hermitian_expectation(self, n_wires, theta, phi, qubit_device, tol): """Test that Hadamard expectation value is correct""" From d714e0e896495d1350c09dc55e17e02a8022b6b0 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 10 Nov 2023 01:05:59 +0000 Subject: [PATCH 13/76] add mpi tests --- mpitests/test_expval.py | 88 ++++++++++++++++--- .../lightning_kokkos/lightning_kokkos.py | 2 +- .../lightning_qubit/lightning_qubit.py | 2 +- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/mpitests/test_expval.py b/mpitests/test_expval.py index ad76da1aa5..eafc50d1b8 100644 --- a/mpitests/test_expval.py +++ b/mpitests/test_expval.py @@ -31,8 +31,6 @@ class TestExpval: def test_identity_expectation(self, theta, phi, tol): """Test that identity expectation value (i.e. the trace) is 1""" dev = qml.device(device_name, mpi=True, wires=3) - if device_name == "lightning.gpu" and dev.R_DTYPE == np.float32: - pytest.skip("Skipped FP32 tests for expval in lightning.gpu") O1 = qml.Identity(wires=[0]) O2 = qml.Identity(wires=[1]) @@ -49,9 +47,6 @@ def test_pauliz_expectation(self, theta, phi, tol): """Test that PauliZ expectation value is correct""" dev = qml.device(device_name, mpi=True, wires=3) - if device_name == "lightning.gpu" and dev.R_DTYPE == np.float32: - pytest.skip("Skipped FP32 tests for expval in lightning.gpu") - O1 = qml.PauliZ(wires=[0]) O2 = qml.PauliZ(wires=[1]) @@ -63,13 +58,26 @@ def test_pauliz_expectation(self, theta, phi, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), tol) + def test_pauliz_expectation_shots(self, theta, phi, tol): + """Test that PauliZ expectation value is correct""" + TOL = 5e-2 + dev = qml.device(device_name, mpi=True, wires=3, shots=1000) + + O1 = qml.PauliZ(wires=[0]) + O2 = qml.PauliZ(wires=[1]) + + dev.apply( + [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)]) + assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), atol=TOL) + def test_paulix_expectation(self, theta, phi, tol): """Test that PauliX expectation value is correct""" dev = qml.device(device_name, mpi=True, wires=3) - if device_name == "lightning.gpu" and dev.R_DTYPE == np.float32: - pytest.skip("Skipped FP32 tests for expval in lightning.gpu") - O1 = qml.PauliX(wires=[0]) O2 = qml.PauliX(wires=[1]) @@ -85,13 +93,46 @@ def test_paulix_expectation(self, theta, phi, tol): tol * 10, ) + def test_paulix_expectation_shots(self, theta, phi, tol): + """Test that PauliX expectation value is correct""" + TOL = 5e-2 + dev = qml.device(device_name, mpi=True, wires=3, shots=1000) + + O1 = qml.PauliX(wires=[0]) + O2 = qml.PauliX(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)], dtype=dev.C_DTYPE) + assert np.allclose( + res, + np.array([np.sin(theta) * np.sin(phi), np.sin(phi)], dtype=dev.C_DTYPE), + atol=TOL, + ) + + def test_pauliy_expectation_shots(self, theta, phi, tol): + """Test that PauliY expectation value is correct""" + TOL = 5e-2 + dev = qml.device(device_name, mpi=True, wires=3, shots=1000) + + O1 = qml.PauliY(wires=[0]) + O2 = qml.PauliY(wires=[1]) + + dev.apply( + [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)]) + assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), atol=TOL) + def test_pauliy_expectation(self, theta, phi, tol): """Test that PauliY expectation value is correct""" dev = qml.device(device_name, mpi=True, wires=3) - if device_name == "lightning.gpu" and dev.R_DTYPE == np.float32: - pytest.skip("Skipped FP32 tests for expval in lightning.gpu") - O1 = qml.PauliY(wires=[0]) O2 = qml.PauliY(wires=[1]) @@ -124,14 +165,35 @@ def test_hadamard_expectation(self, theta, phi, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) + def test_hadamard_expectation_shot(self, theta, phi, tol): + """Test that Hadamard expectation value is correct""" + TOL = 5e-2 + dev = qml.device(device_name, mpi=True, wires=3, shots=1000) + + O1 = qml.Hadamard(wires=[0]) + O2 = qml.Hadamard(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], + ) + + res = np.array([dev.expval(O1), dev.expval(O2)]) + expected = np.array( + [ + np.sin(theta) * np.sin(phi) + np.cos(theta), + np.cos(theta) * np.cos(phi) + np.sin(phi), + ] + ) / np.sqrt(2) + assert np.allclose(res, expected, atol=TOL) + @pytest.mark.parametrize("n_wires", range(1, 8)) def test_hermitian_expectation(self, n_wires, theta, phi, tol): """Test that Hadamard expectation value is correct""" n_qubits = 7 dev_def = qml.device("default.qubit", wires=n_qubits) dev = qml.device(device_name, mpi=True, wires=n_qubits) - if device_name == "lightning.gpu" and dev.R_DTYPE == np.float32: - pytest.skip("Skipped FP32 tests for expval in lightning.gpu") + comm = MPI.COMM_WORLD m = 2**n_wires diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 35a717aeba..96a674a07d 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -470,7 +470,7 @@ def expval(self, observable, shot_range=None, bin_size=None): if self.shots is not None: # estimate the expectation value if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: - obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( + obs = QuantumScriptSerializer(self.short_name, self.use_csingle)._ob( observable, self.wire_map ) diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 4aa73d37c8..52108dca7a 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -424,7 +424,7 @@ def expval(self, observable, shot_range=None, bin_size=None): if self.shots is not None: # estimate the expectation value if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: - obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( + obs = QuantumScriptSerializer(self.short_name, self.use_csingle)._ob( observable, self.wire_map ) From 9d1a418a4c98cb758316e2e59280ddc2e831d723 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 10 Nov 2023 01:07:55 +0000 Subject: [PATCH 14/76] remove else --- pennylane_lightning/lightning_gpu/lightning_gpu.py | 6 ++---- pennylane_lightning/lightning_kokkos/lightning_kokkos.py | 6 ++---- pennylane_lightning/lightning_qubit/lightning_qubit.py | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index 22f8d58c19..bbf92fcd34 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -837,10 +837,8 @@ def expval(self, observable, shot_range=None, bin_size=None): if shot_range is None: return self.measurements.expval(obs, self.shots) - else: - return self.measurements.expval(obs, self.shots, shot_range) - else: - raise RuntimeError(f"{observable.name} obs does not support.") + return self.measurements.expval(obs, self.shots, shot_range) + raise RuntimeError(f"{observable.name} obs does not support.") if observable.name in ["SparseHamiltonian"]: if self._mpi: diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 96a674a07d..8f52efb513 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -476,10 +476,8 @@ def expval(self, observable, shot_range=None, bin_size=None): if shot_range is None: return self.measurements.expval(obs, self.shots) - else: - return self.measurements.expval(obs, self.shots, shot_range) - else: - raise RuntimeError(f"{observable.name} obs does not support.") + return self.measurements.expval(obs, self.shots, shot_range) + raise RuntimeError(f"{observable.name} obs does not support.") # Initialization of state measure = ( diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 52108dca7a..42f98464fe 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -430,10 +430,8 @@ def expval(self, observable, shot_range=None, bin_size=None): if shot_range is None: return self.measurements.expval(obs, self.shots) - else: - return self.measurements.expval(obs, self.shots, shot_range) - else: - raise RuntimeError(f"{observable.name} obs does not support.") + return self.measurements.expval(obs, self.shots, shot_range) + raise RuntimeError(f"{observable.name} obs does not support.") # Initialization of state ket = np.ravel(self._pre_rotated_state) From d9d7a7dc6117725846b8d55dcb1041a32feaf7c9 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Sun, 12 Nov 2023 01:36:39 +0000 Subject: [PATCH 15/76] add tensor product support --- .../src/measurements/MeasurementsBase.hpp | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 7c96967337..0ad42c7936 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -18,12 +18,26 @@ #pragma once #include +#include +#include #include "Observables.hpp" /// @cond DEV namespace { using namespace Pennylane::Observables; +void parse_obs2ops(const std::string& obs_name, std::vector& ops, std::vector>& wires){ + std::regex regex(R"((Pauli[XYZ]|Hadamard|Identity)\[(\d+)\])"); + // Use std::sregex_iterator to iterate over matches in the obs_name string + auto it = std::sregex_iterator(obs_name.begin(), obs_name.end(), regex); + auto end = std::sregex_iterator(); + + for (; it != end; ++it) { + std::smatch match = *it; + ops.push_back(match[1].str()); + wires.push_back({std::stoul(match[2].str())}); + } +} auto sample_to_str(std::vector &sample) -> std::string { std::string str; @@ -170,23 +184,30 @@ template class MeasurementsBase { StateVectorT sv(_statevector); - if (obs_name.find("PauliX") != std::string::npos) { - sv.applyOperation("Hadamard", obs_wires, false); - } else if (obs_name.find("PauliY") != std::string::npos) { - sv.applyOperation("PauliZ", obs_wires, false); - sv.applyOperation("S", obs_wires, false); - sv.applyOperation("Hadamard", obs_wires, false); - } else if (obs_name.find("Hadamard") != std::string::npos) { - const PrecisionT theta = -M_PI / 4.0; - sv.applyOperation("RY", obs_wires, false, {theta}); - } else if (obs_name.find("PauliZ") != std::string::npos) { + std::vector ops; + std::vector> wires_list; + parse_obs2ops(obs_name, ops, wires_list); + + for(size_t i = 0; i < ops.size(); i++){ + auto ops_name = ops[i]; + if(ops_name == "PauliX"){ + sv.applyOperation("Hadamard", wires_list[i], false); + }else if (ops_name == "PauliY"){ + sv.applyOperations({"PauliZ", "S", "Hadamard"}, + {wires_list[i], wires_list[i], wires_list[i]}, + {false, false, false}); + }else if (ops_name == "Hadamard"){ + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", wires_list[i], false, {theta}); + }else if (ops_name == "PauliZ"){ + } } Derived measure(sv); std::vector samples = measure.generate_samples(num_shots); std::vector sub_samples; - std::vector obs_samples(num_shots * obs_wires.size(), 0); + std::vector obs_samples(num_shots, 0); if (shot_range.empty()) { sub_samples = samples; @@ -200,9 +221,16 @@ template class MeasurementsBase { } for (size_t i = 0; i < num_shots; i++) { - obs_samples[i] = - (1 - 2 * static_cast( - sub_samples[i * num_qubits + obs_wires[0]])); + std::vector local_sample(obs_wires.size()); + for(size_t j = 0; j < obs_wires.size(); j++){ + local_sample[j] = sub_samples[i * num_qubits + obs_wires[j]]; + } + + if(std::reduce(local_sample.begin(), local_sample.end())%2 == 1){ + obs_samples[i] = -1; + }else{ + obs_samples[i] = 1; + } } return obs_samples; } From 5745f4ff70d37290f0a9e7a968a690def26db5e3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Sun, 12 Nov 2023 02:16:38 +0000 Subject: [PATCH 16/76] add more tests for tensor prod obs shots --- .../src/measurements/MeasurementsBase.hpp | 15 ++++-- .../Test_StateVectorCudaManaged_Expval.cpp | 54 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 0ad42c7936..141a6cb81d 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -188,6 +188,8 @@ template class MeasurementsBase { std::vector> wires_list; parse_obs2ops(obs_name, ops, wires_list); + size_t num_identity_obs = 0; + for(size_t i = 0; i < ops.size(); i++){ auto ops_name = ops[i]; if(ops_name == "PauliX"){ @@ -200,6 +202,9 @@ template class MeasurementsBase { const PrecisionT theta = -M_PI / 4.0; sv.applyOperation("RY", wires_list[i], false, {theta}); }else if (ops_name == "PauliZ"){ + }else if (ops_name == "Identity"){ + std::swap(obs_wires[num_identity_obs], obs_wires[i]); + num_identity_obs++; } } @@ -225,9 +230,13 @@ template class MeasurementsBase { for(size_t j = 0; j < obs_wires.size(); j++){ local_sample[j] = sub_samples[i * num_qubits + obs_wires[j]]; } - - if(std::reduce(local_sample.begin(), local_sample.end())%2 == 1){ - obs_samples[i] = -1; + + if(num_identity_obs != obs_wires.size()){ + if(std::reduce(local_sample.begin() + num_identity_obs, local_sample.end())%2 == 1){ + obs_samples[i] = -1; + }else{ + obs_samples[i] = 1; + } }else{ obs_samples[i] = 1; } diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp index 36f1f1f128..d64345bb97 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp @@ -332,6 +332,60 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", } } +TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots", + "[StateVectorCudaManaged_Expval]", float, double) { + using StateVectorT = StateVectorCudaManaged; + using ComplexT = StateVectorT::ComplexT; + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT sv{init_state.data(), init_state.size()}; + auto m = Measurements(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + size_t num_shots = 10000; + std::vector shot_range = {}; + + auto ob = TensorProdObs::create({X0, Z1}); + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = TestType(-0.36); + + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + +TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots with Identity", + "[StateVectorCudaManaged_Expval]", float, double) { + using StateVectorT = StateVectorCudaManaged; + using ComplexT = StateVectorT::ComplexT; + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT sv{init_state.data(), init_state.size()}; + auto m = Measurements(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "Identity", std::vector{1}); + + size_t num_shots = 10000; + std::vector shot_range = {}; + + auto ob = TensorProdObs::create({X0, Z1}); + auto res_shots = m.expval(*ob, num_shots, shot_range); + auto expected = m.expval(*ob); + + REQUIRE(expected == Approx(res_shots).margin(5e-2)); + } +} + TEMPLATE_TEST_CASE("StateVectorCudaManaged::Hamiltonian_expval_Sparse", "[StateVectorCudaManaged_Expval]", float, double) { using StateVectorT = StateVectorCudaManaged; From bcb46d1752a3cfaa3a146319deb5260949ff3721 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Sun, 12 Nov 2023 02:17:04 +0000 Subject: [PATCH 17/76] make format --- .../src/measurements/MeasurementsBase.hpp | 37 +++++++++++-------- .../Test_StateVectorCudaManaged_Expval.cpp | 5 ++- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 141a6cb81d..bed1f5b3e0 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -17,16 +17,17 @@ */ #pragma once -#include #include #include +#include #include "Observables.hpp" /// @cond DEV namespace { using namespace Pennylane::Observables; -void parse_obs2ops(const std::string& obs_name, std::vector& ops, std::vector>& wires){ +void parse_obs2ops(const std::string &obs_name, std::vector &ops, + std::vector> &wires) { std::regex regex(R"((Pauli[XYZ]|Hadamard|Identity)\[(\d+)\])"); // Use std::sregex_iterator to iterate over matches in the obs_name string auto it = std::sregex_iterator(obs_name.begin(), obs_name.end(), regex); @@ -190,19 +191,20 @@ template class MeasurementsBase { size_t num_identity_obs = 0; - for(size_t i = 0; i < ops.size(); i++){ + for (size_t i = 0; i < ops.size(); i++) { auto ops_name = ops[i]; - if(ops_name == "PauliX"){ + if (ops_name == "PauliX") { sv.applyOperation("Hadamard", wires_list[i], false); - }else if (ops_name == "PauliY"){ - sv.applyOperations({"PauliZ", "S", "Hadamard"}, - {wires_list[i], wires_list[i], wires_list[i]}, - {false, false, false}); - }else if (ops_name == "Hadamard"){ + } else if (ops_name == "PauliY") { + sv.applyOperations( + {"PauliZ", "S", "Hadamard"}, + {wires_list[i], wires_list[i], wires_list[i]}, + {false, false, false}); + } else if (ops_name == "Hadamard") { const PrecisionT theta = -M_PI / 4.0; sv.applyOperation("RY", wires_list[i], false, {theta}); - }else if (ops_name == "PauliZ"){ - }else if (ops_name == "Identity"){ + } else if (ops_name == "PauliZ") { + } else if (ops_name == "Identity") { std::swap(obs_wires[num_identity_obs], obs_wires[i]); num_identity_obs++; } @@ -227,17 +229,20 @@ template class MeasurementsBase { for (size_t i = 0; i < num_shots; i++) { std::vector local_sample(obs_wires.size()); - for(size_t j = 0; j < obs_wires.size(); j++){ + for (size_t j = 0; j < obs_wires.size(); j++) { local_sample[j] = sub_samples[i * num_qubits + obs_wires[j]]; } - if(num_identity_obs != obs_wires.size()){ - if(std::reduce(local_sample.begin() + num_identity_obs, local_sample.end())%2 == 1){ + if (num_identity_obs != obs_wires.size()) { + if (std::reduce(local_sample.begin() + num_identity_obs, + local_sample.end()) % + 2 == + 1) { obs_samples[i] = -1; - }else{ + } else { obs_samples[i] = 1; } - }else{ + } else { obs_samples[i] = 1; } } diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp index d64345bb97..b0c1b173d5 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp @@ -359,8 +359,9 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots", } } -TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots with Identity", - "[StateVectorCudaManaged_Expval]", float, double) { +TEMPLATE_TEST_CASE( + "Test expectation value of TensorProdObs shots with Identity", + "[StateVectorCudaManaged_Expval]", float, double) { using StateVectorT = StateVectorCudaManaged; using ComplexT = StateVectorT::ComplexT; SECTION("Using expval") { From 68f28659ff4f2b4955509a4b1b5d026f7fa9fd9a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 14 Nov 2023 00:44:51 +0000 Subject: [PATCH 18/76] add Hamiltonian support --- .../src/measurements/MeasurementsBase.hpp | 79 +++++++++++-------- .../core/src/observables/Observables.hpp | 76 ++++++++++++++++++ .../observables/ObservablesGPU.hpp | 6 ++ .../observables/ObservablesGPUMPI.hpp | 7 ++ 4 files changed, 135 insertions(+), 33 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index bed1f5b3e0..cb00fa4898 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -150,15 +150,35 @@ template class MeasurementsBase { const std::vector &shot_range) -> PrecisionT { PrecisionT result = 0; std::vector short_range = {}; - auto obs_samples = samples(obs, num_shots, shot_range); - size_t num_elements = 0; - for (int element : obs_samples) { - result += element; - num_elements++; + if(obs.getObsName().find("SparseHamiltonian") != std::string::npos){ + PL_ABORT("For SparseHamiltonian Observables, expval calculation is not supported by shots"); + }else if(obs.getObsName().find("Hermintian") != std::string::npos){ + PL_ABORT("For Hermintian Observables, expval calculation is not supported by shots"); + }else if (obs.getObsName().find("Hamiltonian") != std::string::npos){ + auto coeffs = obs.getCoeffs(); + for(size_t obs_term_idx = 0; obs_term_idx < coeffs.size(); obs_term_idx++){ + auto obs_samples = samples(obs, num_shots, shot_range, obs_term_idx); + size_t num_elements = 0; + PrecisionT result_per_term = 0.0; + for (int element : obs_samples) { + result_per_term += element; + num_elements++; + } + result += result_per_term / num_elements; + } + } else{ + auto obs_samples = samples(obs, num_shots, shot_range); + size_t num_elements = 0; + for (int element : obs_samples) { + result += element; + num_elements++; + } + result = result / num_elements; + } - return result / num_elements; + return result; } /** @@ -177,38 +197,20 @@ template class MeasurementsBase { */ auto samples(const Observable &obs, const size_t &num_shots, const std::vector &shot_range, + const size_t term_idx = 0, [[maybe_unused]] size_t bin_size = 0, [[maybe_unused]] bool counts = false) { - auto obs_name = obs.getObsName(); - auto obs_wires = obs.getWires(); + std::vector obs_wires; //for Hamiltonian this obs_wires should be calculated based on terms const size_t num_qubits = _statevector.getTotalNumQubits(); + + bool shots = true; + std::vector identify_wires; StateVectorT sv(_statevector); - std::vector ops; - std::vector> wires_list; - parse_obs2ops(obs_name, ops, wires_list); - - size_t num_identity_obs = 0; - - for (size_t i = 0; i < ops.size(); i++) { - auto ops_name = ops[i]; - if (ops_name == "PauliX") { - sv.applyOperation("Hadamard", wires_list[i], false); - } else if (ops_name == "PauliY") { - sv.applyOperations( - {"PauliZ", "S", "Hadamard"}, - {wires_list[i], wires_list[i], wires_list[i]}, - {false, false, false}); - } else if (ops_name == "Hadamard") { - const PrecisionT theta = -M_PI / 4.0; - sv.applyOperation("RY", wires_list[i], false, {theta}); - } else if (ops_name == "PauliZ") { - } else if (ops_name == "Identity") { - std::swap(obs_wires[num_identity_obs], obs_wires[i]); - num_identity_obs++; - } - } + + obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); + Derived measure(sv); @@ -226,7 +228,18 @@ template class MeasurementsBase { } } } - + + size_t num_identity_obs = identify_wires.size(); + if(!identify_wires.empty()){ + size_t identity_obs_idx = 0; + for (size_t i = 0; i < obs_wires.size(); i++) { + if (identify_wires[identity_obs_idx] == obs_wires[i]) { + std::swap(obs_wires[identity_obs_idx], obs_wires[i]); + identity_obs_idx++; + } + } + } + for (size_t i = 0; i < num_shots; i++) { std::vector local_sample(obs_wires.size()); for (size_t j = 0; j < obs_wires.size(); j++) { diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 183a9fcd82..e410bc20e7 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -61,6 +61,11 @@ template class Observable { */ virtual void applyInPlace(StateVectorT &sv) const = 0; + /** + * @brief Apply the observable to the given statevector in place. + */ + virtual void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires = {}, const size_t term_idx = 0) const = 0; + /** * @brief Get the name of the observable */ @@ -71,6 +76,13 @@ template class Observable { */ [[nodiscard]] virtual auto getWires() const -> std::vector = 0; + /** + * @brief Get the wires the observable applies to. + */ + [[nodiscard]] virtual auto getCoeffs() const -> std::vector{ + return {}; + }; + /** * @brief Test whether this object is equal to another object */ @@ -140,6 +152,30 @@ class NamedObsBase : public Observable { void applyInPlace(StateVectorT &sv) const override { sv.applyOperation(obs_name_, wires_, false, params_); } + + void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wire, std::vector& ob_wires = {}, [[maybe_unused]] const size_t term_idx = 0) const override { + ob_wires = getWires(); + if(shots){ + if (obs_name_ == "PauliX") { + sv.applyOperation("Hadamard", wires_, false); + } else if (obs_name_ == "PauliY") { + sv.applyOperations( + {"PauliZ", "S", "Hadamard"}, + {wires_, wires_, wires_}, + {false, false, false}); + } else if (obs_name_ == "Hadamard") { + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", wires_, false, {theta}); + } else if (obs_name_ == "PauliZ") { + } else if (obs_name_ == "Identity"){ + if(!identify_wire.empty()){ + identify_wire.clear(); + } + identify_wire.push_back(wires_[0]); + } else{ + } + } + } }; /** @@ -192,6 +228,11 @@ class HermitianObsBase : public Observable { void applyInPlace(StateVectorT &sv) const override { sv.applyMatrix(matrix_, wires_); } + + void applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, [[maybe_unused]] std::vector& identify_wire,[[maybe_unused]] std::vector& ob_wires = {}, [[maybe_unused]] const size_t term_idx = 0) const override { + PL_ABORT("For Hermitian Observables with shots, the applyInPlace method is " + "not supported."); + } }; /** @@ -224,6 +265,7 @@ class TensorProdObsBase : public Observable { } public: + using PrecisionT = typename StateVectorT::PrecisionT; /** * @brief Create a tensor product of observables * @@ -301,6 +343,21 @@ class TensorProdObsBase : public Observable { } } + void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { + identify_wires.clear(); + if(shots){ + for (const auto &ob : obs_) { + std::vector identity_wire = {}; + std::vector ob_wire = {}; + ob->applyInPlace(sv, shots, identity_wire, ob_wire); + if(!identity_wire.empty()){ + identify_wires.push_back(identity_wire[0]); + } + ob_wires.push_back(ob_wire[0]); + } + } + } + [[nodiscard]] auto getObsName() const -> std::string override { using Util::operator<<; std::ostringstream obs_stream; @@ -386,6 +443,12 @@ class HamiltonianBase : public Observable { "defined at the backend level."); } + void applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, [[maybe_unused]] std::vector& identify_wires,[[maybe_unused]] std::vector& ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { + PL_ABORT("For Hamiltonian Observables, the applyInPlace method must be " + "defined at the backend level."); + } + + [[nodiscard]] auto getWires() const -> std::vector override { std::unordered_set wires; @@ -412,6 +475,13 @@ class HamiltonianBase : public Observable { ss << "]}"; return ss.str(); } + + /** + * @brief Get the wires the observable applies to. + */ + [[nodiscard]] auto getCoeffs() const -> std::vector override{ + return coeffs_; + }; }; /** @@ -496,6 +566,12 @@ class SparseHamiltonianBase : public Observable { "defined at the backend level."); } + void applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, [[maybe_unused]] std::vector& identify_wire,[[maybe_unused]] std::vector& ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { + PL_ABORT("For SparseHamiltonian Observables, the applyInPlace method " + "must be " + "defined at the backend level."); + } + [[nodiscard]] auto getObsName() const -> std::string override { using Pennylane::Util::operator<<; std::ostringstream ss; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp index 6d0d0a94e7..8e92de10f6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp @@ -207,6 +207,12 @@ class Hamiltonian final : public HamiltonianBase { } sv.updateData(std::move(buffer)); } + + // to work with + void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires, const size_t term_idx) const override { + ob_wires.clear(); + this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, term_idx); + } }; /** diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp index 955365915a..2e49b79125 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp @@ -214,6 +214,13 @@ class HamiltonianMPI final : public HamiltonianBase { PL_CUDA_IS_SUCCESS(cudaDeviceSynchronize()); mpi_manager.Barrier(); } + + + // to work with + void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires, const size_t term_idx) const override { + ob_wires.clear(); + this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, term_idx); + } }; /** From bc583327b4ba1030b463439701b68ad63a9df59d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 14 Nov 2023 00:54:19 +0000 Subject: [PATCH 19/76] make format --- .../src/measurements/MeasurementsBase.hpp | 38 ++++++----- .../core/src/observables/Observables.hpp | 66 ++++++++++++------- .../observables/ObservablesGPU.hpp | 10 ++- .../observables/ObservablesGPUMPI.hpp | 11 ++-- .../observables/ObservablesKokkos.hpp | 10 +++ .../observables/ObservablesLQubit.hpp | 10 +++ 6 files changed, 98 insertions(+), 47 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index cb00fa4898..6f2027b407 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -151,14 +151,18 @@ template class MeasurementsBase { PrecisionT result = 0; std::vector short_range = {}; - if(obs.getObsName().find("SparseHamiltonian") != std::string::npos){ - PL_ABORT("For SparseHamiltonian Observables, expval calculation is not supported by shots"); - }else if(obs.getObsName().find("Hermintian") != std::string::npos){ - PL_ABORT("For Hermintian Observables, expval calculation is not supported by shots"); - }else if (obs.getObsName().find("Hamiltonian") != std::string::npos){ + if (obs.getObsName().find("SparseHamiltonian") != std::string::npos) { + PL_ABORT("For SparseHamiltonian Observables, expval calculation is " + "not supported by shots"); + } else if (obs.getObsName().find("Hermintian") != std::string::npos) { + PL_ABORT("For Hermintian Observables, expval calculation is not " + "supported by shots"); + } else if (obs.getObsName().find("Hamiltonian") != std::string::npos) { auto coeffs = obs.getCoeffs(); - for(size_t obs_term_idx = 0; obs_term_idx < coeffs.size(); obs_term_idx++){ - auto obs_samples = samples(obs, num_shots, shot_range, obs_term_idx); + for (size_t obs_term_idx = 0; obs_term_idx < coeffs.size(); + obs_term_idx++) { + auto obs_samples = + samples(obs, num_shots, shot_range, obs_term_idx); size_t num_elements = 0; PrecisionT result_per_term = 0.0; for (int element : obs_samples) { @@ -167,7 +171,7 @@ template class MeasurementsBase { } result += result_per_term / num_elements; } - } else{ + } else { auto obs_samples = samples(obs, num_shots, shot_range); size_t num_elements = 0; for (int element : obs_samples) { @@ -175,7 +179,6 @@ template class MeasurementsBase { num_elements++; } result = result / num_elements; - } return result; @@ -200,17 +203,16 @@ template class MeasurementsBase { const size_t term_idx = 0, [[maybe_unused]] size_t bin_size = 0, [[maybe_unused]] bool counts = false) { - std::vector obs_wires; //for Hamiltonian this obs_wires should be calculated based on terms + std::vector obs_wires; // for Hamiltonian this obs_wires should + // be calculated based on terms const size_t num_qubits = _statevector.getTotalNumQubits(); - + bool shots = true; std::vector identify_wires; StateVectorT sv(_statevector); - obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); - Derived measure(sv); @@ -228,10 +230,10 @@ template class MeasurementsBase { } } } - - size_t num_identity_obs = identify_wires.size(); - if(!identify_wires.empty()){ - size_t identity_obs_idx = 0; + + size_t num_identity_obs = identify_wires.size(); + if (!identify_wires.empty()) { + size_t identity_obs_idx = 0; for (size_t i = 0; i < obs_wires.size(); i++) { if (identify_wires[identity_obs_idx] == obs_wires[i]) { std::swap(obs_wires[identity_obs_idx], obs_wires[i]); @@ -239,7 +241,7 @@ template class MeasurementsBase { } } } - + for (size_t i = 0; i < num_shots; i++) { std::vector local_sample(obs_wires.size()); for (size_t j = 0; j < obs_wires.size(); j++) { diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index e410bc20e7..8cad6e04cf 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -64,7 +64,10 @@ template class Observable { /** * @brief Apply the observable to the given statevector in place. */ - virtual void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires = {}, const size_t term_idx = 0) const = 0; + virtual void applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wires, + std::vector &ob_wires = {}, + const size_t term_idx = 0) const = 0; /** * @brief Get the name of the observable @@ -79,7 +82,7 @@ template class Observable { /** * @brief Get the wires the observable applies to. */ - [[nodiscard]] virtual auto getCoeffs() const -> std::vector{ + [[nodiscard]] virtual auto getCoeffs() const -> std::vector { return {}; }; @@ -153,26 +156,29 @@ class NamedObsBase : public Observable { sv.applyOperation(obs_name_, wires_, false, params_); } - void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wire, std::vector& ob_wires = {}, [[maybe_unused]] const size_t term_idx = 0) const override { - ob_wires = getWires(); - if(shots){ + void + applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wire, + std::vector &ob_wires = {}, + [[maybe_unused]] const size_t term_idx = 0) const override { + ob_wires = getWires(); + if (shots) { if (obs_name_ == "PauliX") { sv.applyOperation("Hadamard", wires_, false); } else if (obs_name_ == "PauliY") { - sv.applyOperations( - {"PauliZ", "S", "Hadamard"}, - {wires_, wires_, wires_}, - {false, false, false}); + sv.applyOperations({"PauliZ", "S", "Hadamard"}, + {wires_, wires_, wires_}, + {false, false, false}); } else if (obs_name_ == "Hadamard") { const PrecisionT theta = -M_PI / 4.0; sv.applyOperation("RY", wires_, false, {theta}); } else if (obs_name_ == "PauliZ") { - } else if (obs_name_ == "Identity"){ - if(!identify_wire.empty()){ + } else if (obs_name_ == "Identity") { + if (!identify_wire.empty()) { identify_wire.clear(); } identify_wire.push_back(wires_[0]); - } else{ + } else { } } } @@ -229,9 +235,14 @@ class HermitianObsBase : public Observable { sv.applyMatrix(matrix_, wires_); } - void applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, [[maybe_unused]] std::vector& identify_wire,[[maybe_unused]] std::vector& ob_wires = {}, [[maybe_unused]] const size_t term_idx = 0) const override { - PL_ABORT("For Hermitian Observables with shots, the applyInPlace method is " - "not supported."); + void + applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, + [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &ob_wires = {}, + [[maybe_unused]] const size_t term_idx = 0) const override { + PL_ABORT( + "For Hermitian Observables with shots, the applyInPlace method is " + "not supported."); } }; @@ -343,14 +354,18 @@ class TensorProdObsBase : public Observable { } } - void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { + void + applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wires, + std::vector &ob_wires, + [[maybe_unused]] const size_t term_idx = 0) const override { identify_wires.clear(); - if(shots){ + if (shots) { for (const auto &ob : obs_) { std::vector identity_wire = {}; std::vector ob_wire = {}; ob->applyInPlace(sv, shots, identity_wire, ob_wire); - if(!identity_wire.empty()){ + if (!identity_wire.empty()) { identify_wires.push_back(identity_wire[0]); } ob_wires.push_back(ob_wire[0]); @@ -443,12 +458,15 @@ class HamiltonianBase : public Observable { "defined at the backend level."); } - void applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, [[maybe_unused]] std::vector& identify_wires,[[maybe_unused]] std::vector& ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { + void + applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, + [[maybe_unused]] std::vector &identify_wires, + [[maybe_unused]] std::vector &ob_wires, + [[maybe_unused]] const size_t term_idx = 0) const override { PL_ABORT("For Hamiltonian Observables, the applyInPlace method must be " "defined at the backend level."); } - [[nodiscard]] auto getWires() const -> std::vector override { std::unordered_set wires; @@ -479,7 +497,7 @@ class HamiltonianBase : public Observable { /** * @brief Get the wires the observable applies to. */ - [[nodiscard]] auto getCoeffs() const -> std::vector override{ + [[nodiscard]] auto getCoeffs() const -> std::vector override { return coeffs_; }; }; @@ -566,7 +584,11 @@ class SparseHamiltonianBase : public Observable { "defined at the backend level."); } - void applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, [[maybe_unused]] std::vector& identify_wire,[[maybe_unused]] std::vector& ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { + void + applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, + [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &ob_wires, + [[maybe_unused]] const size_t term_idx = 0) const override { PL_ABORT("For SparseHamiltonian Observables, the applyInPlace method " "must be " "defined at the backend level."); diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp index 8e92de10f6..fee0b53d6c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp @@ -209,9 +209,13 @@ class Hamiltonian final : public HamiltonianBase { } // to work with - void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires, const size_t term_idx) const override { - ob_wires.clear(); - this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, term_idx); + void applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { + ob_wires.clear(); + this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, + term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp index 2e49b79125..47c25be8d1 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp @@ -215,11 +215,14 @@ class HamiltonianMPI final : public HamiltonianBase { mpi_manager.Barrier(); } - // to work with - void applyInPlace(StateVectorT &sv, bool shots, std::vector& identify_wires, std::vector& ob_wires, const size_t term_idx) const override { - ob_wires.clear(); - this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, term_idx); + void applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { + ob_wires.clear(); + this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, + term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp index c3fae6b3ea..00d4efd6a1 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp @@ -268,6 +268,16 @@ class SparseHamiltonian final : public SparseHamiltonianBase { sv.updateData(d_sv_prime); } + + // to work with + void applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { + ob_wires.clear(); + this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, + term_idx); + } }; /// @cond DEV diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp index b659969037..b0fa98df5b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp @@ -358,6 +358,16 @@ class Hamiltonian final : public HamiltonianBase { StateVectorT, Pennylane::Util::use_openmp>::run(this->coeffs_, this->obs_, sv); } + + // to work with + void applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { + ob_wires.clear(); + this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, + term_idx); + } }; /** From 52884912a6a39064dcf2ad5cfde823d567cd5d7d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 14 Nov 2023 00:57:53 +0000 Subject: [PATCH 20/76] quick fix --- pennylane_lightning/core/src/measurements/MeasurementsBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 6f2027b407..c727dab812 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -169,7 +169,7 @@ template class MeasurementsBase { result_per_term += element; num_elements++; } - result += result_per_term / num_elements; + result += coeffs[obs_term_idx] * result_per_term / num_elements; } } else { auto obs_samples = samples(obs, num_shots, shot_range); From c7f5ea21740b0fa7a72e8fa0a78e7b3486a21c83 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 14 Nov 2023 01:11:19 +0000 Subject: [PATCH 21/76] add hamiltonian tests --- .../Test_StateVectorCudaManaged_Expval.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp index b0c1b173d5..e5bd7dce79 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp @@ -309,6 +309,31 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs", } } +TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", + "[StateVectorCudaManaged_Expval]", float, double) { + using StateVectorT = StateVectorCudaManaged; + using ComplexT = StateVectorT::ComplexT; + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT sv{init_state.data(), init_state.size()}; + auto m = Measurements(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); + size_t num_shots = 10000; + std::vector shot_range = {}; + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = TestType(-0.086); + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", "[StateVectorCudaManaged_Expval]", float, double) { using StateVectorT = StateVectorCudaManaged; From 4b56805ba3d2b4beb5786d76f440840062027d45 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 14 Nov 2023 13:25:04 +0000 Subject: [PATCH 22/76] add more py tests for tensorprod --- mpitests/test_expval.py | 72 ++++++++++++++++- .../lightning_gpu/lightning_gpu.py | 18 +++-- tests/test_expval.py | 78 ++++++++++++++++++- 3 files changed, 158 insertions(+), 10 deletions(-) diff --git a/mpitests/test_expval.py b/mpitests/test_expval.py index eafc50d1b8..fb7fca2e57 100644 --- a/mpitests/test_expval.py +++ b/mpitests/test_expval.py @@ -165,7 +165,7 @@ def test_hadamard_expectation(self, theta, phi, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) - def test_hadamard_expectation_shot(self, theta, phi, tol): + def test_hadamard_expectation_shots(self, theta, phi, tol): """Test that Hadamard expectation value is correct""" TOL = 5e-2 dev = qml.device(device_name, mpi=True, wires=3, shots=1000) @@ -347,6 +347,29 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) assert np.allclose(res, expected, atol=tol) + + def test_paulix_pauliy_shots(self, theta, phi, varphi): + """Test that a tensor product involving PauliX and PauliY works + correctly""" + TOL = 5e-2 + dev = qml.device(device_name, mpi=True, wires=3, shots=1000) + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + rotations=obs.diagonalizing_gates(), + ) + res = dev.expval(obs) + + expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + + assert np.allclose(res, expected, atol=TOL) def test_pauliz_identity(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works @@ -370,6 +393,30 @@ def test_pauliz_identity(self, theta, phi, varphi, tol): expected = np.cos(varphi) * np.cos(phi) assert np.allclose(res, expected, tol) + + def test_pauliz_identity_shots(self, theta, phi, varphi): + """Test that a tensor product involving PauliZ and Identity works + correctly""" + TOL = 5e-2 + dev = qml.device(device_name, mpi=True, wires=3, shots=1000) + obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + rotations=obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.cos(varphi) * np.cos(phi) + + assert np.allclose(res, expected, atol=TOL) def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and Hadamard @@ -392,3 +439,26 @@ def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, tol): expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) assert np.allclose(res, expected, tol) + + def test_pauliz_hadamard_pauliy_shots(self, theta, phi, varphi): + """Test that a tensor product involving PauliZ and PauliY and Hadamard + works correctly""" + TOL = 5e-2 + dev = qml.device(device_name, mpi=True, wires=3, shots=1000) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + rotations=obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + + assert np.allclose(res, expected, atol=TOL) diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index bbf92fcd34..dea68c4054 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -829,15 +829,23 @@ def expval(self, observable, shot_range=None, bin_size=None): Expectation value of the observable """ if self.shots is not None: + obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( + observable, self.wire_map) # estimate the expectation value - if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: - obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( - observable, self.wire_map - ) - + if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard", "Identity"]: + if shot_range is None: + return self.measurements.expval(obs, self.shots) + return self.measurements.expval(obs, self.shots, shot_range) + elif isinstance(observable, Tensor): if shot_range is None: return self.measurements.expval(obs, self.shots) return self.measurements.expval(obs, self.shots, shot_range) + elif observable.name in ["Hamiltonian"]: + if shot_range is None: + return self.measurements.expval(obs, self.shots) + return self.measurements.expval(obs, self.shots, shot_range) + + raise RuntimeError(f"{observable.name} obs does not support.") if observable.name in ["SparseHamiltonian"]: diff --git a/tests/test_expval.py b/tests/test_expval.py index fc8622e06b..c47f61fdc1 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -41,7 +41,7 @@ def test_identity_expectation(self, theta, phi, qubit_device, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([1, 1]), tol) - def test_pauliz_expectation(self, theta, phi, qubit_device_shots): + def test_pauliz_expectation_shots(self, theta, phi, qubit_device_shots): """Test that PauliZ expectation value is correct""" TOL = 5e-2 dev = qubit_device_shots(wires=3) @@ -89,7 +89,7 @@ def test_paulix_expectation(self, theta, phi, qubit_device, tol): res, np.array([np.sin(theta) * np.sin(phi), np.sin(phi)], dtype=dev.C_DTYPE), tol * 10 ) - def test_paulix_expectation(self, theta, phi, qubit_device_shots): + def test_paulix_expectation_shots(self, theta, phi, qubit_device_shots): """Test that PauliX expectation value is correct""" TOL = 5e-2 dev = qubit_device_shots(wires=3) @@ -122,7 +122,7 @@ def test_pauliy_expectation(self, theta, phi, qubit_device, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), tol) - def test_pauliy_expectation(self, theta, phi, qubit_device_shots): + def test_pauliy_expectation_shots(self, theta, phi, qubit_device_shots): """Test that PauliY expectation value is correct""" TOL = 5e-2 dev = qubit_device_shots(wires=3) @@ -156,7 +156,7 @@ def test_hadamard_expectation(self, theta, phi, qubit_device, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) - def test_hadamard_expectation(self, theta, phi, qubit_device_shots): + def test_hadamard_expectation_shots(self, theta, phi, qubit_device_shots): """Test that Hadamard expectation value is correct""" TOL = 5e-2 dev = qubit_device_shots(wires=3) @@ -318,6 +318,29 @@ def test_paulix_pauliy(self, theta, phi, varphi, qubit_device, tol): expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) assert np.allclose(res, expected, atol=tol) + + def test_paulix_pauliy_shots(self, theta, phi, varphi, qubit_device_shots): + """Test that a tensor product involving PauliX and PauliY works + correctly""" + TOL=5e-2 + dev = qubit_device_shots(wires=3) + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + rotations=obs.diagonalizing_gates(), + ) + res = dev.expval(obs) + + expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + + assert np.allclose(res, expected, atol=TOL) def test_pauliz_identity(self, theta, phi, varphi, qubit_device, tol): """Test that a tensor product involving PauliZ and Identity works @@ -341,6 +364,30 @@ def test_pauliz_identity(self, theta, phi, varphi, qubit_device, tol): expected = np.cos(varphi) * np.cos(phi) assert np.allclose(res, expected, tol) + + def test_pauliz_identity_shots(self, theta, phi, varphi, qubit_device_shots): + """Test that a tensor product involving PauliZ and Identity works + correctly""" + TOL = 5e-2 + dev = qubit_device_shots(wires=3) + obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + rotations=obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.cos(varphi) * np.cos(phi) + + assert np.allclose(res, expected, atol=TOL) def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, qubit_device, tol): """Test that a tensor product involving PauliZ and PauliY and Hadamard @@ -363,3 +410,26 @@ def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, qubit_device, tol): expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) assert np.allclose(res, expected, tol) + + def test_pauliz_hadamard_pauliy_shots(self, theta, phi, varphi, qubit_device_shots): + """Test that a tensor product involving PauliZ and PauliY and Hadamard + works correctly""" + TOL = 5e-2 + dev = qubit_device_shots(wires=3) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + rotations=obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + + assert np.allclose(res, expected, atol=TOL) From f09342fa605ed28402dd6a0f95f9028a7a6d45bc Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 18:42:18 +0000 Subject: [PATCH 23/76] remove changes made in py layer --- mpitests/test_expval.py | 142 ------------------ .../core/src/bindings/Bindings.hpp | 17 --- .../core/src/bindings/BindingsMPI.hpp | 17 --- .../lightning_gpu/lightning_gpu.py | 19 +-- .../lightning_kokkos/lightning_kokkos.py | 11 +- .../lightning_qubit/lightning_qubit.py | 12 +- tests/conftest.py | 12 +- tests/test_expval.py | 140 +---------------- 8 files changed, 8 insertions(+), 362 deletions(-) diff --git a/mpitests/test_expval.py b/mpitests/test_expval.py index fb7fca2e57..d43593bfbb 100644 --- a/mpitests/test_expval.py +++ b/mpitests/test_expval.py @@ -58,21 +58,6 @@ def test_pauliz_expectation(self, theta, phi, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), tol) - def test_pauliz_expectation_shots(self, theta, phi, tol): - """Test that PauliZ expectation value is correct""" - TOL = 5e-2 - dev = qml.device(device_name, mpi=True, wires=3, shots=1000) - - O1 = qml.PauliZ(wires=[0]) - O2 = qml.PauliZ(wires=[1]) - - dev.apply( - [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)]) - assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), atol=TOL) def test_paulix_expectation(self, theta, phi, tol): """Test that PauliX expectation value is correct""" @@ -93,41 +78,6 @@ def test_paulix_expectation(self, theta, phi, tol): tol * 10, ) - def test_paulix_expectation_shots(self, theta, phi, tol): - """Test that PauliX expectation value is correct""" - TOL = 5e-2 - dev = qml.device(device_name, mpi=True, wires=3, shots=1000) - - O1 = qml.PauliX(wires=[0]) - O2 = qml.PauliX(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)], dtype=dev.C_DTYPE) - assert np.allclose( - res, - np.array([np.sin(theta) * np.sin(phi), np.sin(phi)], dtype=dev.C_DTYPE), - atol=TOL, - ) - - def test_pauliy_expectation_shots(self, theta, phi, tol): - """Test that PauliY expectation value is correct""" - TOL = 5e-2 - dev = qml.device(device_name, mpi=True, wires=3, shots=1000) - - O1 = qml.PauliY(wires=[0]) - O2 = qml.PauliY(wires=[1]) - - dev.apply( - [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)]) - assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), atol=TOL) def test_pauliy_expectation(self, theta, phi, tol): """Test that PauliY expectation value is correct""" @@ -165,28 +115,6 @@ def test_hadamard_expectation(self, theta, phi, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) - def test_hadamard_expectation_shots(self, theta, phi, tol): - """Test that Hadamard expectation value is correct""" - TOL = 5e-2 - dev = qml.device(device_name, mpi=True, wires=3, shots=1000) - - O1 = qml.Hadamard(wires=[0]) - O2 = qml.Hadamard(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)]) - expected = np.array( - [ - np.sin(theta) * np.sin(phi) + np.cos(theta), - np.cos(theta) * np.cos(phi) + np.sin(phi), - ] - ) / np.sqrt(2) - assert np.allclose(res, expected, atol=TOL) - @pytest.mark.parametrize("n_wires", range(1, 8)) def test_hermitian_expectation(self, n_wires, theta, phi, tol): """Test that Hadamard expectation value is correct""" @@ -347,29 +275,6 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) assert np.allclose(res, expected, atol=tol) - - def test_paulix_pauliy_shots(self, theta, phi, varphi): - """Test that a tensor product involving PauliX and PauliY works - correctly""" - TOL = 5e-2 - dev = qml.device(device_name, mpi=True, wires=3, shots=1000) - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - rotations=obs.diagonalizing_gates(), - ) - res = dev.expval(obs) - - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - - assert np.allclose(res, expected, atol=TOL) def test_pauliz_identity(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works @@ -393,30 +298,6 @@ def test_pauliz_identity(self, theta, phi, varphi, tol): expected = np.cos(varphi) * np.cos(phi) assert np.allclose(res, expected, tol) - - def test_pauliz_identity_shots(self, theta, phi, varphi): - """Test that a tensor product involving PauliZ and Identity works - correctly""" - TOL = 5e-2 - dev = qml.device(device_name, mpi=True, wires=3, shots=1000) - obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - rotations=obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.cos(varphi) * np.cos(phi) - - assert np.allclose(res, expected, atol=TOL) def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and Hadamard @@ -439,26 +320,3 @@ def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, tol): expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) assert np.allclose(res, expected, tol) - - def test_pauliz_hadamard_pauliy_shots(self, theta, phi, varphi): - """Test that a tensor product involving PauliZ and PauliY and Hadamard - works correctly""" - TOL = 5e-2 - dev = qml.device(device_name, mpi=True, wires=3, shots=1000) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - rotations=obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - - assert np.allclose(res, expected, atol=TOL) diff --git a/pennylane_lightning/core/src/bindings/Bindings.hpp b/pennylane_lightning/core/src/bindings/Bindings.hpp index 266e1b7959..1368ee3a94 100644 --- a/pennylane_lightning/core/src/bindings/Bindings.hpp +++ b/pennylane_lightning/core/src/bindings/Bindings.hpp @@ -439,23 +439,6 @@ void registerBackendAgnosticMeasurements(PyClass &pyclass) { return M.expval(*ob); }, "Expected value of an observable object.") - .def( - "expval", - [](Measurements &M, - const std::shared_ptr> &ob, - const size_t &num_shots) { - const std::vector &shot_range = {}; - return M.expval(*ob, num_shots, shot_range); - }, - "Expected value of an observable object.") - .def( - "expval", - [](Measurements &M, - const std::shared_ptr> &ob, - const size_t &num_shots, const std::vector &shot_range) { - return M.expval(*ob, num_shots, shot_range); - }, - "Expected value of an observable object.") .def( "var", [](Measurements &M, diff --git a/pennylane_lightning/core/src/bindings/BindingsMPI.hpp b/pennylane_lightning/core/src/bindings/BindingsMPI.hpp index 7ab4166501..41276afe5d 100644 --- a/pennylane_lightning/core/src/bindings/BindingsMPI.hpp +++ b/pennylane_lightning/core/src/bindings/BindingsMPI.hpp @@ -269,23 +269,6 @@ void registerBackendAgnosticMeasurementsMPI(PyClass &pyclass) { return M.expval(*ob); }, "Expected value of an observable object.") - .def( - "expval", - [](MeasurementsMPI &M, - const std::shared_ptr> &ob, - const size_t &num_shots) { - const std::vector &shot_range = {}; - return M.expval(*ob, num_shots, shot_range); - }, - "Expected value of an observable object.") - .def( - "expval", - [](MeasurementsMPI &M, - const std::shared_ptr> &ob, - const size_t &num_shots, const std::vector &shot_range) { - return M.expval(*ob, num_shots, shot_range); - }, - "Expected value of an observable object.") .def( "var", [](MeasurementsMPI &M, diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index dea68c4054..177275ec13 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -829,24 +829,9 @@ def expval(self, observable, shot_range=None, bin_size=None): Expectation value of the observable """ if self.shots is not None: - obs = QuantumScriptSerializer(self.short_name, self.use_csingle, self._mpi)._ob( - observable, self.wire_map) # estimate the expectation value - if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard", "Identity"]: - if shot_range is None: - return self.measurements.expval(obs, self.shots) - return self.measurements.expval(obs, self.shots, shot_range) - elif isinstance(observable, Tensor): - if shot_range is None: - return self.measurements.expval(obs, self.shots) - return self.measurements.expval(obs, self.shots, shot_range) - elif observable.name in ["Hamiltonian"]: - if shot_range is None: - return self.measurements.expval(obs, self.shots) - return self.measurements.expval(obs, self.shots, shot_range) - - - raise RuntimeError(f"{observable.name} obs does not support.") + samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) + return np.squeeze(np.mean(samples, axis=0)) if observable.name in ["SparseHamiltonian"]: if self._mpi: diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 8f52efb513..34f9610bda 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -469,15 +469,8 @@ def expval(self, observable, shot_range=None, bin_size=None): if self.shots is not None: # estimate the expectation value - if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: - obs = QuantumScriptSerializer(self.short_name, self.use_csingle)._ob( - observable, self.wire_map - ) - - if shot_range is None: - return self.measurements.expval(obs, self.shots) - return self.measurements.expval(obs, self.shots, shot_range) - raise RuntimeError(f"{observable.name} obs does not support.") + samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) + return np.squeeze(np.mean(samples, axis=0)) # Initialization of state measure = ( diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 42f98464fe..72f25e841c 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -422,16 +422,8 @@ def expval(self, observable, shot_range=None, bin_size=None): return super().expval(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: - # estimate the expectation value - if observable.name in ["PauliX", "PauliY", "PauliZ", "Hadamard"]: - obs = QuantumScriptSerializer(self.short_name, self.use_csingle)._ob( - observable, self.wire_map - ) - - if shot_range is None: - return self.measurements.expval(obs, self.shots) - return self.measurements.expval(obs, self.shots, shot_range) - raise RuntimeError(f"{observable.name} obs does not support.") + samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) + return np.squeeze(np.mean(samples, axis=0)) # Initialization of state ket = np.ravel(self._pre_rotated_state) diff --git a/tests/conftest.py b/tests/conftest.py index f636f44ec9..da58c9f1fc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -111,6 +111,7 @@ def get_device(): device_name = get_device() +# device_name = "lightning.kokkos" if device_name not in qml.plugin_devices: raise qml.DeviceError( @@ -137,14 +138,3 @@ def _device(wires): return _device - -# General qubit_device fixture, for any number of wires. -@pytest.fixture( - scope="function", - params=[np.complex64, np.complex128], -) -def qubit_device_shots(request): - def _device(wires): - return qml.device(device_name, wires=wires, c_dtype=request.param, shots=10000) - - return _device diff --git a/tests/test_expval.py b/tests/test_expval.py index c47f61fdc1..ab79be3468 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -41,22 +41,6 @@ def test_identity_expectation(self, theta, phi, qubit_device, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([1, 1]), tol) - def test_pauliz_expectation_shots(self, theta, phi, qubit_device_shots): - """Test that PauliZ expectation value is correct""" - TOL = 5e-2 - dev = qubit_device_shots(wires=3) - - O1 = qml.PauliZ(wires=[0]) - O2 = qml.PauliZ(wires=[1]) - - dev.apply( - [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)]) - assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), atol=TOL) - def test_pauliz_expectation(self, theta, phi, qubit_device, tol): """Test that PauliZ expectation value is correct""" dev = qubit_device(wires=3) @@ -89,24 +73,6 @@ def test_paulix_expectation(self, theta, phi, qubit_device, tol): res, np.array([np.sin(theta) * np.sin(phi), np.sin(phi)], dtype=dev.C_DTYPE), tol * 10 ) - def test_paulix_expectation_shots(self, theta, phi, qubit_device_shots): - """Test that PauliX expectation value is correct""" - TOL = 5e-2 - dev = qubit_device_shots(wires=3) - - O1 = qml.PauliX(wires=[0]) - O2 = qml.PauliX(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)], dtype=dev.C_DTYPE) - assert np.allclose( - res, np.array([np.sin(theta) * np.sin(phi), np.sin(phi)], dtype=dev.C_DTYPE), atol=TOL - ) - def test_pauliy_expectation(self, theta, phi, qubit_device, tol): """Test that PauliY expectation value is correct""" dev = qubit_device(wires=3) @@ -122,21 +88,6 @@ def test_pauliy_expectation(self, theta, phi, qubit_device, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), tol) - def test_pauliy_expectation_shots(self, theta, phi, qubit_device_shots): - """Test that PauliY expectation value is correct""" - TOL = 5e-2 - dev = qubit_device_shots(wires=3) - - O1 = qml.PauliY(wires=[0]) - O2 = qml.PauliY(wires=[1]) - - dev.apply( - [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)]) - assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), atol=TOL) def test_hadamard_expectation(self, theta, phi, qubit_device, tol): """Test that Hadamard expectation value is correct""" @@ -156,25 +107,6 @@ def test_hadamard_expectation(self, theta, phi, qubit_device, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) - def test_hadamard_expectation_shots(self, theta, phi, qubit_device_shots): - """Test that Hadamard expectation value is correct""" - TOL = 5e-2 - dev = qubit_device_shots(wires=3) - - O1 = qml.Hadamard(wires=[0]) - O2 = qml.Hadamard(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)]) - expected = np.array( - [np.sin(theta) * np.sin(phi) + np.cos(theta), np.cos(theta) * np.cos(phi) + np.sin(phi)] - ) / np.sqrt(2) - assert np.allclose(res, expected, atol=TOL) - @pytest.mark.parametrize("n_wires", range(1, 7)) def test_hermitian_expectation(self, n_wires, theta, phi, qubit_device, tol): """Test that Hadamard expectation value is correct""" @@ -318,29 +250,6 @@ def test_paulix_pauliy(self, theta, phi, varphi, qubit_device, tol): expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) assert np.allclose(res, expected, atol=tol) - - def test_paulix_pauliy_shots(self, theta, phi, varphi, qubit_device_shots): - """Test that a tensor product involving PauliX and PauliY works - correctly""" - TOL=5e-2 - dev = qubit_device_shots(wires=3) - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - rotations=obs.diagonalizing_gates(), - ) - res = dev.expval(obs) - - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - - assert np.allclose(res, expected, atol=TOL) def test_pauliz_identity(self, theta, phi, varphi, qubit_device, tol): """Test that a tensor product involving PauliZ and Identity works @@ -364,30 +273,6 @@ def test_pauliz_identity(self, theta, phi, varphi, qubit_device, tol): expected = np.cos(varphi) * np.cos(phi) assert np.allclose(res, expected, tol) - - def test_pauliz_identity_shots(self, theta, phi, varphi, qubit_device_shots): - """Test that a tensor product involving PauliZ and Identity works - correctly""" - TOL = 5e-2 - dev = qubit_device_shots(wires=3) - obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - rotations=obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.cos(varphi) * np.cos(phi) - - assert np.allclose(res, expected, atol=TOL) def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, qubit_device, tol): """Test that a tensor product involving PauliZ and PauliY and Hadamard @@ -409,27 +294,4 @@ def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, qubit_device, tol): res = dev.expval(obs) expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - assert np.allclose(res, expected, tol) - - def test_pauliz_hadamard_pauliy_shots(self, theta, phi, varphi, qubit_device_shots): - """Test that a tensor product involving PauliZ and PauliY and Hadamard - works correctly""" - TOL = 5e-2 - dev = qubit_device_shots(wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - rotations=obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - - assert np.allclose(res, expected, atol=TOL) + assert np.allclose(res, expected, tol) \ No newline at end of file From d13e9f23ca0d1bcd9050470513a5dff238adc4bf Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 18:49:20 +0000 Subject: [PATCH 24/76] revert more changes in py layer --- pennylane_lightning/lightning_kokkos/lightning_kokkos.py | 1 + pennylane_lightning/lightning_qubit/lightning_qubit.py | 2 ++ tests/conftest.py | 2 -- tests/test_expval.py | 3 +-- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 34f9610bda..56cda8f92c 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -469,6 +469,7 @@ def expval(self, observable, shot_range=None, bin_size=None): if self.shots is not None: # estimate the expectation value + # LightningQubit doesn't support sampling yet samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) return np.squeeze(np.mean(samples, axis=0)) diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 72f25e841c..9a4d4f5b35 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -422,6 +422,8 @@ def expval(self, observable, shot_range=None, bin_size=None): return super().expval(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: + # estimate the expectation value + # LightningQubit doesn't support sampling yet samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) return np.squeeze(np.mean(samples, axis=0)) diff --git a/tests/conftest.py b/tests/conftest.py index da58c9f1fc..7bfb8c5b69 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -111,7 +111,6 @@ def get_device(): device_name = get_device() -# device_name = "lightning.kokkos" if device_name not in qml.plugin_devices: raise qml.DeviceError( @@ -137,4 +136,3 @@ def _device(wires): return qml.device(device_name, wires=wires, c_dtype=request.param) return _device - diff --git a/tests/test_expval.py b/tests/test_expval.py index ab79be3468..e64ef2a329 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -88,7 +88,6 @@ def test_pauliy_expectation(self, theta, phi, qubit_device, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([0, -np.cos(theta) * np.sin(phi)]), tol) - def test_hadamard_expectation(self, theta, phi, qubit_device, tol): """Test that Hadamard expectation value is correct""" dev = qubit_device(wires=3) @@ -294,4 +293,4 @@ def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, qubit_device, tol): res = dev.expval(obs) expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - assert np.allclose(res, expected, tol) \ No newline at end of file + assert np.allclose(res, expected, tol) From 9ef8dac45e4bf4712acb983ba1feecf100ead62d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 18:49:37 +0000 Subject: [PATCH 25/76] tidy up code --- mpitests/test_expval.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mpitests/test_expval.py b/mpitests/test_expval.py index d43593bfbb..9db1e76b31 100644 --- a/mpitests/test_expval.py +++ b/mpitests/test_expval.py @@ -58,7 +58,6 @@ def test_pauliz_expectation(self, theta, phi, tol): res = np.array([dev.expval(O1), dev.expval(O2)]) assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), tol) - def test_paulix_expectation(self, theta, phi, tol): """Test that PauliX expectation value is correct""" dev = qml.device(device_name, mpi=True, wires=3) @@ -78,7 +77,6 @@ def test_paulix_expectation(self, theta, phi, tol): tol * 10, ) - def test_pauliy_expectation(self, theta, phi, tol): """Test that PauliY expectation value is correct""" dev = qml.device(device_name, mpi=True, wires=3) @@ -121,7 +119,6 @@ def test_hermitian_expectation(self, n_wires, theta, phi, tol): n_qubits = 7 dev_def = qml.device("default.qubit", wires=n_qubits) dev = qml.device(device_name, mpi=True, wires=n_qubits) - comm = MPI.COMM_WORLD m = 2**n_wires From bd8fd5a710cd087c3ebbe469a40959f73dfa7c15 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 19:36:56 +0000 Subject: [PATCH 26/76] update measurement base and kokkos --- .../src/measurements/MeasurementsBase.hpp | 109 ++++++++++-------- .../tests/Test_MeasurementsBase.cpp | 2 +- .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 2 +- .../core/src/observables/Observables.hpp | 13 ++- .../lightning_kokkos/StateVectorKokkos.hpp | 4 +- .../measurements/MeasurementsKokkos.hpp | 14 +++ .../observables/ObservablesKokkos.hpp | 20 ++-- .../StateVectorLQubitManaged.hpp | 2 +- .../lightning_qubit/StateVectorLQubitRaw.hpp | 3 +- .../measurements/tests/CMakeLists.txt | 1 + .../tests/Test_MeasurementsLQubit.cpp | 61 ++++++++++ 11 files changed, 160 insertions(+), 71 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index c727dab812..efd0dd7106 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -17,29 +17,19 @@ */ #pragma once -#include #include #include #include "Observables.hpp" +#ifdef _ENABLE_PLQUBIT +#include "CPUMemoryModel.hpp" +#endif + /// @cond DEV namespace { using namespace Pennylane::Observables; -void parse_obs2ops(const std::string &obs_name, std::vector &ops, - std::vector> &wires) { - std::regex regex(R"((Pauli[XYZ]|Hadamard|Identity)\[(\d+)\])"); - // Use std::sregex_iterator to iterate over matches in the obs_name string - auto it = std::sregex_iterator(obs_name.begin(), obs_name.end(), regex); - auto end = std::sregex_iterator(); - - for (; it != end; ++it) { - std::smatch match = *it; - ops.push_back(match[1].str()); - wires.push_back({std::stoul(match[2].str())}); - } -} - +/* auto sample_to_str(std::vector &sample) -> std::string { std::string str; for (auto &element : sample) { @@ -47,6 +37,7 @@ auto sample_to_str(std::vector &sample) -> std::string { } return str; } +*/ } // namespace /// @endcond @@ -203,20 +194,41 @@ template class MeasurementsBase { const size_t term_idx = 0, [[maybe_unused]] size_t bin_size = 0, [[maybe_unused]] bool counts = false) { - std::vector obs_wires; // for Hamiltonian this obs_wires should - // be calculated based on terms + std::vector obs_wires; const size_t num_qubits = _statevector.getTotalNumQubits(); - bool shots = true; std::vector identify_wires; - StateVectorT sv(_statevector); + std::vector samples; - obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); +#ifdef _ENABLE_PLQUBIT + if constexpr (std::is_same_v) { + StateVectorT sv(_statevector); + obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); + Derived measure(sv); + samples = measure.generate_samples(num_shots); + } else if constexpr (std::is_same_v< + typename StateVectorT::MemoryStorageT, + MemoryStorageLocation::External>) { + + std::vector data_storage(_statevector.getData(), + _statevector.getData() + + _statevector.getLength()); + StateVectorT sv(data_storage.data(), data_storage.size()); + + obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); + Derived measure(sv); + samples = measure.generate_samples(num_shots); + } +#else + StateVectorT sv(_statevector); + obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); Derived measure(sv); + samples = measure.generate_samples(num_shots); +#endif - std::vector samples = measure.generate_samples(num_shots); std::vector sub_samples; std::vector obs_samples(num_shots, 0); @@ -243,16 +255,13 @@ template class MeasurementsBase { } for (size_t i = 0; i < num_shots; i++) { - std::vector local_sample(obs_wires.size()); - for (size_t j = 0; j < obs_wires.size(); j++) { - local_sample[j] = sub_samples[i * num_qubits + obs_wires[j]]; + std::vector local_sample; + for (auto& obs_wire : obs_wires){ + local_sample.push_back(sub_samples[i * num_qubits + obs_wire]); } if (num_identity_obs != obs_wires.size()) { - if (std::reduce(local_sample.begin() + num_identity_obs, - local_sample.end()) % - 2 == - 1) { + if((std::accumulate(local_sample.begin() + num_identity_obs, local_sample.end(), 0) & 1) == 1){ obs_samples[i] = -1; } else { obs_samples[i] = 1; @@ -275,27 +284,29 @@ template class MeasurementsBase { * @return std::unordered_map with format ``{'outcome': * num_occurences}`` */ - auto samples_to_counts(std::vector &samples, size_t &num_shots, - size_t &num_obs_wires) - -> std::unordered_map { - std::unordered_map outcome_map; - - for (size_t i = 0; i < num_shots; i++) { - auto local_sample = - std::vector(samples.begin() + i * num_obs_wires, - samples.begin() + (i + 1) * num_obs_wires - 1); - std::string key = sample_to_str(local_sample); - - auto it = outcome_map.find(key); - - if (it != outcome_map.end()) { - it->second += 1; - } else { - outcome_map[key] = 1; - } - } - return outcome_map; - } + /* + auto samples_to_counts(std::vector &samples, size_t &num_shots, + size_t &num_obs_wires) + -> std::unordered_map { + std::unordered_map outcome_map; + + for (size_t i = 0; i < num_shots; i++) { + auto local_sample = + std::vector(samples.begin() + i * num_obs_wires, + samples.begin() + (i + 1) * num_obs_wires - 1); + std::string key = sample_to_str(local_sample); + + auto it = outcome_map.find(key); + + if (it != outcome_map.end()) { + it->second += 1; + } else { + outcome_map[key] = 1; + } + } + return outcome_map; + } + */ }; } // namespace Pennylane::Measures \ No newline at end of file diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 458665ff17..477fc7ce42 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -231,7 +231,7 @@ template void testNamedObsExpvalShot() { PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; PrecisionT result = Measurer.expval(obs, num_shots, shots_range); - REQUIRE(expected == Approx(result).margin(2e-2)); + REQUIRE(expected == Approx(result).margin(5e-2)); } } } diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index 3a69782a2d..af2f90477e 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -249,7 +249,7 @@ template void testNamedObsExpvalShot() { PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; PrecisionT result = Measurer.expval(obs, num_shots, shots_range); - REQUIRE(expected == Approx(result).margin(2e-2)); + REQUIRE(expected == Approx(result).margin(5e-2)); } } } diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 8cad6e04cf..8412058531 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -66,7 +66,7 @@ template class Observable { */ virtual void applyInPlace(StateVectorT &sv, bool shots, std::vector &identify_wires, - std::vector &ob_wires = {}, + std::vector &ob_wires, const size_t term_idx = 0) const = 0; /** @@ -159,9 +159,11 @@ class NamedObsBase : public Observable { void applyInPlace(StateVectorT &sv, bool shots, std::vector &identify_wire, - std::vector &ob_wires = {}, + std::vector &ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { - ob_wires = getWires(); + ob_wires.clear(); + identify_wire.clear(); + ob_wires.push_back(wires_[0]); if (shots) { if (obs_name_ == "PauliX") { sv.applyOperation("Hadamard", wires_, false); @@ -360,10 +362,11 @@ class TensorProdObsBase : public Observable { std::vector &ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { identify_wires.clear(); + ob_wires.clear(); if (shots) { for (const auto &ob : obs_) { - std::vector identity_wire = {}; - std::vector ob_wire = {}; + std::vector identity_wire; + std::vector ob_wire; ob->applyInPlace(sv, shots, identity_wire, ob_wire); if (!identity_wire.empty()) { identify_wires.push_back(identity_wire[0]); diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp index bc41557015..5ebc323201 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp @@ -115,9 +115,7 @@ class StateVectorKokkos final /** * @brief Get the total number of wires. */ - auto getTotalNumQubits() const -> size_t { - return BaseType::getNumQubits(); - } + auto getTotalNumQubits() const -> size_t { return this->getNumQubits(); } /** * @brief Init zeros for the state-vector on device. diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp index c9414921f6..e4212d5b15 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp @@ -275,6 +275,20 @@ class Measurements final return expected_value_list; } + /** + * @brief Expectation value for a Observable with shots + * + * @param obs Observable. + * @param num_shots Number of shots. + * @param shots_range Vector of shot number to measurement. + * @return Floating point expected value of the observable. + */ + + auto expval(const Observable &obs, const size_t &num_shots, + const std::vector &shot_range) -> PrecisionT { + return BaseType::expval(obs, num_shots, shot_range); + } + /** * @brief Expected value of a Sparse Hamiltonian. * diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp index 00d4efd6a1..4c3daf2fea 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp @@ -198,6 +198,16 @@ class Hamiltonian final : public HamiltonianBase { } sv.updateData(buffer); } + + // to work with + void applyInPlace(StateVectorT &sv, bool shots, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { + ob_wires.clear(); + this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, + term_idx); + } }; /** @@ -268,16 +278,6 @@ class SparseHamiltonian final : public SparseHamiltonianBase { sv.updateData(d_sv_prime); } - - // to work with - void applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wires, - std::vector &ob_wires, - const size_t term_idx) const override { - ob_wires.clear(); - this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, - term_idx); - } }; /// @cond DEV diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp index 3cf00b5aba..2d7aaf32ac 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp @@ -143,7 +143,7 @@ class StateVectorLQubitManaged final * @brief Get the total number of wires. */ auto getTotalNumQubits() const -> size_t { - return BaseType::getNumQubits(); + return log2PerfectPower(data_.size()); } [[nodiscard]] auto getData() -> ComplexT * { return data_.data(); } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp index 65c529ef62..e60502e1b5 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp @@ -90,7 +90,8 @@ class StateVectorLQubitRaw final * @brief Get the total number of wires. */ auto getTotalNumQubits() const -> size_t { - return BaseType::getNumQubits(); + return log2PerfectPower(length_); + ; } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt index 1ea6861b8a..79b3b18e8a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(lightning_qubit_measurements_tests INTERFACE) target_link_libraries(lightning_qubit_measurements_tests INTERFACE Catch2::Catch2 lightning_measurements lightning_qubit_measurements + lightning_qubit_observables ) ProcessTestOptions(lightning_qubit_measurements_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 35e7280be1..c7dcc3bdfb 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -20,6 +20,7 @@ #include #include "MeasurementsLQubit.hpp" +#include "ObservablesLQubit.hpp" #include "StateVectorLQubitManaged.hpp" #include "StateVectorLQubitRaw.hpp" #include "Util.hpp" @@ -31,9 +32,11 @@ /// @cond DEV namespace { using namespace Pennylane::Util; +using namespace Pennylane::Observables; using namespace Pennylane::LightningQubit; using namespace Pennylane::LightningQubit::Measures; +using namespace Pennylane::LightningQubit::Observables; }; // namespace /// @endcond @@ -116,6 +119,64 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", } } +TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of TensorProdObs shots", + "[StateVectorLQubit_Expval]", + (StateVectorLQubitManaged, StateVectorLQubitRaw), + (float, double)) { + using StateVectorT = TestType; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = StateVectorT::ComplexT; + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT sv{init_state.data(), init_state.size()}; + auto m = Measurements(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + size_t num_shots = 10000; + std::vector shot_range = {}; + + auto ob = TensorProdObs::create({X0, Z1}); + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = PrecisionT(-0.36); + + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + +TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of HamiltonianObs shot", + "[StateVectorLQubit_Expval]", + (StateVectorLQubitManaged, StateVectorLQubitRaw), + (float, double)) { + using StateVectorT = TestType; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = StateVectorT::ComplexT; + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT sv{init_state.data(), init_state.size()}; + auto m = Measurements(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); + size_t num_shots = 10000; + std::vector shot_range = {}; + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = PrecisionT(-0.086); + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + TEMPLATE_PRODUCT_TEST_CASE("Variances", "[Measurements]", (StateVectorLQubitManaged, StateVectorLQubitRaw), (float, double)) { From 15d824462f6e1e2e66eba980f3fb4a757e080739 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 19:38:48 +0000 Subject: [PATCH 27/76] make format --- .../core/src/measurements/MeasurementsBase.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index efd0dd7106..ceb2e930ab 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -194,7 +194,7 @@ template class MeasurementsBase { const size_t term_idx = 0, [[maybe_unused]] size_t bin_size = 0, [[maybe_unused]] bool counts = false) { - std::vector obs_wires; + std::vector obs_wires; const size_t num_qubits = _statevector.getTotalNumQubits(); bool shots = true; std::vector identify_wires; @@ -256,12 +256,14 @@ template class MeasurementsBase { for (size_t i = 0; i < num_shots; i++) { std::vector local_sample; - for (auto& obs_wire : obs_wires){ + for (auto &obs_wire : obs_wires) { local_sample.push_back(sub_samples[i * num_qubits + obs_wire]); } if (num_identity_obs != obs_wires.size()) { - if((std::accumulate(local_sample.begin() + num_identity_obs, local_sample.end(), 0) & 1) == 1){ + if ((std::accumulate(local_sample.begin() + num_identity_obs, + local_sample.end(), 0) & + 1) == 1) { obs_samples[i] = -1; } else { obs_samples[i] = 1; From 1bc196f8d19847e19d3a68525797e1741f17d47a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 21:56:15 +0000 Subject: [PATCH 28/76] refactor and add _sample_state method --- .../src/measurements/MeasurementsBase.hpp | 173 +++++++++++------- .../core/src/observables/Observables.hpp | 104 +++++------ .../observables/ObservablesGPU.hpp | 12 +- .../observables/ObservablesGPUMPI.hpp | 12 +- .../observables/ObservablesKokkos.hpp | 12 +- .../observables/ObservablesLQubit.hpp | 12 +- 6 files changed, 182 insertions(+), 143 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index ceb2e930ab..e0c2eff0c5 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -131,7 +131,7 @@ template class MeasurementsBase { * @brief Calculate the expectation value for a general Observable. * * @param obs Observable. - * @param shots Vector of shot number to measurement + * @param num_shots Vector of shot number to measurement * @param shot_range The range of samples to use. If it's empty, all samples * are used. * @@ -152,8 +152,8 @@ template class MeasurementsBase { auto coeffs = obs.getCoeffs(); for (size_t obs_term_idx = 0; obs_term_idx < coeffs.size(); obs_term_idx++) { - auto obs_samples = - samples(obs, num_shots, shot_range, obs_term_idx); + auto obs_samples = measure_with_samples( + obs, num_shots, shot_range, obs_term_idx); size_t num_elements = 0; PrecisionT result_per_term = 0.0; for (int element : obs_samples) { @@ -163,7 +163,7 @@ template class MeasurementsBase { result += coeffs[obs_term_idx] * result_per_term / num_elements; } } else { - auto obs_samples = samples(obs, num_shots, shot_range); + auto obs_samples = measure_with_samples(obs, num_shots, shot_range); size_t num_elements = 0; for (int element : obs_samples) { result += element; @@ -176,78 +176,34 @@ template class MeasurementsBase { } /** - * @brief Return samples of a observable + * @brief Calculate the expectation value for a general Observable. * - * @param obs The observable to sample - * @param num_shots Number of shots used to generate samples + * @param obs Observable. + * @param num_shots Vector of shot number to measurement * @param shot_range The range of samples to use. If it's empty, all samples * are used. - * @param bin_size Divides the shot range into bins of size ``bin_size``, - * and returns the measurement statistic separately over each bin. - * @param counts Whether count("True") or raw samples ("False") should be - * retruned + * @param term_idx Index of a Hamiltonian term * - * @return std::vector samples in std::vector + * @return Expectation value with respect to the given observable. */ - auto samples(const Observable &obs, const size_t &num_shots, - const std::vector &shot_range, - const size_t term_idx = 0, - [[maybe_unused]] size_t bin_size = 0, - [[maybe_unused]] bool counts = false) { - std::vector obs_wires; + auto measure_with_samples(const Observable &obs, + const size_t &num_shots, + const std::vector &shot_range, + const size_t term_idx = 0) { const size_t num_qubits = _statevector.getTotalNumQubits(); - bool shots = true; - std::vector identify_wires; - - std::vector samples; - -#ifdef _ENABLE_PLQUBIT - if constexpr (std::is_same_v) { - StateVectorT sv(_statevector); - obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); - Derived measure(sv); - samples = measure.generate_samples(num_shots); - } else if constexpr (std::is_same_v< - typename StateVectorT::MemoryStorageT, - MemoryStorageLocation::External>) { - - std::vector data_storage(_statevector.getData(), - _statevector.getData() + - _statevector.getLength()); + std::vector obs_wires; + std::vector identity_wires; - StateVectorT sv(data_storage.data(), data_storage.size()); + auto sub_samples = _sample_state(obs, num_shots, shot_range, obs_wires, + identity_wires, term_idx); - obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); - Derived measure(sv); - samples = measure.generate_samples(num_shots); - } -#else - StateVectorT sv(_statevector); - obs.applyInPlace(sv, shots, identify_wires, obs_wires, term_idx); - Derived measure(sv); - samples = measure.generate_samples(num_shots); -#endif - - std::vector sub_samples; std::vector obs_samples(num_shots, 0); - if (shot_range.empty()) { - sub_samples = samples; - } else { - // Get a slice of samples based on the shot_range vector - for (auto &i : shot_range) { - for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { - sub_samples.push_back(samples[j]); - } - } - } - - size_t num_identity_obs = identify_wires.size(); - if (!identify_wires.empty()) { + size_t num_identity_obs = identity_wires.size(); + if (!identity_wires.empty()) { size_t identity_obs_idx = 0; for (size_t i = 0; i < obs_wires.size(); i++) { - if (identify_wires[identity_obs_idx] == obs_wires[i]) { + if (identity_wires[identity_obs_idx] == obs_wires[i]) { std::swap(obs_wires[identity_obs_idx], obs_wires[i]); identity_obs_idx++; } @@ -261,6 +217,9 @@ template class MeasurementsBase { } if (num_identity_obs != obs_wires.size()) { + // eigen values are `1` and `-1` for PauliX, PauliY, PauliZ, + // Hadamard gates the eigen value for a eigen vector |00001> is + // -1 since sum of the value at each bit position is odd if ((std::accumulate(local_sample.begin() + num_identity_obs, local_sample.end(), 0) & 1) == 1) { @@ -269,12 +228,34 @@ template class MeasurementsBase { obs_samples[i] = 1; } } else { + // eigen value for Identity gate is `1` obs_samples[i] = 1; } } return obs_samples; } + /** + * @brief Return samples of a observable + * + * @param obs The observable to sample + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. If it's empty, all samples + * are used. + * + * @return std::vector samples in std::vector + */ + auto samples(const Observable &obs, const size_t &num_shots, + const std::vector &shot_range) { + PL_ABORT_IF( + obs.getObsName().find("Hamiltonian") != std::string::npos, + "Samples does not support Hamiltonian and Sparse Hamiltonian."); + std::vector obs_wires; + std::vector identity_wires; + return _sample_state(obs, num_shots, shot_range, obs_wires, + identity_wires); + } + /** * @brief Groups the samples into a dictionary showing number of occurences * for each possible outcome. @@ -309,6 +290,70 @@ template class MeasurementsBase { return outcome_map; } */ + private: + /** + * @brief Return samples of a observable + * + * @param obs The observable to sample + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. If it's empty, all samples + * are used. + * @param obs_wires Observable wires. + * @param identity_wires Wires of Identity gates + * @param term_idx Index of a Hamiltonian term + * + * @return std::vector samples in std::vector + */ + auto _sample_state(const Observable &obs, + const size_t &num_shots, + const std::vector &shot_range, + std::vector &obs_wires, + std::vector &identity_wires, + const size_t &term_idx = 0) { + const size_t num_qubits = _statevector.getTotalNumQubits(); + std::vector samples; + +#ifdef _ENABLE_PLQUBIT + if constexpr (std::is_same_v) { + StateVectorT sv(_statevector); + obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); + Derived measure(sv); + samples = measure.generate_samples(num_shots); + } else if constexpr (std::is_same_v< + typename StateVectorT::MemoryStorageT, + MemoryStorageLocation::External>) { + + std::vector data_storage(_statevector.getData(), + _statevector.getData() + + _statevector.getLength()); + + StateVectorT sv(data_storage.data(), data_storage.size()); + + obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); + Derived measure(sv); + samples = measure.generate_samples(num_shots); + } +#else + StateVectorT sv(_statevector); + obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); + Derived measure(sv); + samples = measure.generate_samples(num_shots); +#endif + std::vector sub_samples; + + if (shot_range.empty()) { + sub_samples = samples; + } else { + // Get a slice of samples based on the shot_range vector + for (auto &i : shot_range) { + for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { + sub_samples.push_back(samples[j]); + } + } + } + return sub_samples; + } }; } // namespace Pennylane::Measures \ No newline at end of file diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 8412058531..d321d33dfe 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -64,10 +64,10 @@ template class Observable { /** * @brief Apply the observable to the given statevector in place. */ - virtual void applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wires, - std::vector &ob_wires, - const size_t term_idx = 0) const = 0; + virtual void applyInPlaceShots(StateVectorT &sv, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx = 0) const = 0; /** * @brief Get the name of the observable @@ -156,32 +156,29 @@ class NamedObsBase : public Observable { sv.applyOperation(obs_name_, wires_, false, params_); } - void - applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wire, - std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + void applyInPlaceShots( + StateVectorT &sv, std::vector &identify_wire, + std::vector &ob_wires, + [[maybe_unused]] const size_t term_idx = 0) const override { ob_wires.clear(); identify_wire.clear(); ob_wires.push_back(wires_[0]); - if (shots) { - if (obs_name_ == "PauliX") { - sv.applyOperation("Hadamard", wires_, false); - } else if (obs_name_ == "PauliY") { - sv.applyOperations({"PauliZ", "S", "Hadamard"}, - {wires_, wires_, wires_}, - {false, false, false}); - } else if (obs_name_ == "Hadamard") { - const PrecisionT theta = -M_PI / 4.0; - sv.applyOperation("RY", wires_, false, {theta}); - } else if (obs_name_ == "PauliZ") { - } else if (obs_name_ == "Identity") { - if (!identify_wire.empty()) { - identify_wire.clear(); - } - identify_wire.push_back(wires_[0]); - } else { + + if (obs_name_ == "PauliX") { + sv.applyOperation("Hadamard", wires_, false); + } else if (obs_name_ == "PauliY") { + sv.applyOperations({"PauliZ", "S", "Hadamard"}, + {wires_, wires_, wires_}, {false, false, false}); + } else if (obs_name_ == "Hadamard") { + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", wires_, false, {theta}); + } else if (obs_name_ == "PauliZ") { + } else if (obs_name_ == "Identity") { + if (!identify_wire.empty()) { + identify_wire.clear(); } + identify_wire.push_back(wires_[0]); + } else { } } }; @@ -237,11 +234,11 @@ class HermitianObsBase : public Observable { sv.applyMatrix(matrix_, wires_); } - void - applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, - [[maybe_unused]] std::vector &identify_wire, - [[maybe_unused]] std::vector &ob_wires = {}, - [[maybe_unused]] const size_t term_idx = 0) const override { + void applyInPlaceShots( + [[maybe_unused]] StateVectorT &sv, + [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &ob_wires = {}, + [[maybe_unused]] const size_t term_idx = 0) const override { PL_ABORT( "For Hermitian Observables with shots, the applyInPlace method is " "not supported."); @@ -356,23 +353,20 @@ class TensorProdObsBase : public Observable { } } - void - applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wires, - std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + void applyInPlaceShots( + StateVectorT &sv, std::vector &identify_wires, + std::vector &ob_wires, + [[maybe_unused]] const size_t term_idx = 0) const override { identify_wires.clear(); ob_wires.clear(); - if (shots) { - for (const auto &ob : obs_) { - std::vector identity_wire; - std::vector ob_wire; - ob->applyInPlace(sv, shots, identity_wire, ob_wire); - if (!identity_wire.empty()) { - identify_wires.push_back(identity_wire[0]); - } - ob_wires.push_back(ob_wire[0]); + for (const auto &ob : obs_) { + std::vector identity_wire; + std::vector ob_wire; + ob->applyInPlaceShots(sv, identity_wire, ob_wire); + if (!identity_wire.empty()) { + identify_wires.push_back(identity_wire[0]); } + ob_wires.push_back(ob_wire[0]); } } @@ -461,11 +455,11 @@ class HamiltonianBase : public Observable { "defined at the backend level."); } - void - applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, - [[maybe_unused]] std::vector &identify_wires, - [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + void applyInPlaceShots( + [[maybe_unused]] StateVectorT &sv, + [[maybe_unused]] std::vector &identify_wires, + [[maybe_unused]] std::vector &ob_wires, + [[maybe_unused]] const size_t term_idx = 0) const override { PL_ABORT("For Hamiltonian Observables, the applyInPlace method must be " "defined at the backend level."); } @@ -587,11 +581,11 @@ class SparseHamiltonianBase : public Observable { "defined at the backend level."); } - void - applyInPlace([[maybe_unused]] StateVectorT &sv, [[maybe_unused]] bool shots, - [[maybe_unused]] std::vector &identify_wire, - [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + void applyInPlaceShots( + [[maybe_unused]] StateVectorT &sv, + [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &ob_wires, + [[maybe_unused]] const size_t term_idx = 0) const override { PL_ABORT("For SparseHamiltonian Observables, the applyInPlace method " "must be " "defined at the backend level."); diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp index fee0b53d6c..80b2c8f8ae 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp @@ -209,13 +209,13 @@ class Hamiltonian final : public HamiltonianBase { } // to work with - void applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wires, - std::vector &ob_wires, - const size_t term_idx) const override { + void applyInPlaceShots(StateVectorT &sv, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, - term_idx); + this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp index 47c25be8d1..fabd0f5d2d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp @@ -216,13 +216,13 @@ class HamiltonianMPI final : public HamiltonianBase { } // to work with - void applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wires, - std::vector &ob_wires, - const size_t term_idx) const override { + void applyInPlaceShots(StateVectorT &sv, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, - term_idx); + this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp index 4c3daf2fea..0737b2edea 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp @@ -200,13 +200,13 @@ class Hamiltonian final : public HamiltonianBase { } // to work with - void applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wires, - std::vector &ob_wires, - const size_t term_idx) const override { + void applyInPlaceShots(StateVectorT &sv, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, - term_idx); + this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp index b0fa98df5b..69d01fa250 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp @@ -360,13 +360,13 @@ class Hamiltonian final : public HamiltonianBase { } // to work with - void applyInPlace(StateVectorT &sv, bool shots, - std::vector &identify_wires, - std::vector &ob_wires, - const size_t term_idx) const override { + void applyInPlaceShots(StateVectorT &sv, + std::vector &identify_wires, + std::vector &ob_wires, + const size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlace(sv, shots, identify_wires, ob_wires, - term_idx); + this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + term_idx); } }; From e5b64a0030c7429a0a15d4aa57ffc6a9292db03b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 22:35:48 +0000 Subject: [PATCH 29/76] for loop sum to accumulate sum --- .../src/measurements/MeasurementsBase.hpp | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index e0c2eff0c5..d208d405a5 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -154,22 +154,17 @@ template class MeasurementsBase { obs_term_idx++) { auto obs_samples = measure_with_samples( obs, num_shots, shot_range, obs_term_idx); - size_t num_elements = 0; - PrecisionT result_per_term = 0.0; - for (int element : obs_samples) { - result_per_term += element; - num_elements++; - } - result += coeffs[obs_term_idx] * result_per_term / num_elements; + PrecisionT result_per_term = std::accumulate( + obs_samples.begin(), obs_samples.end(), 0.0); + + result += + coeffs[obs_term_idx] * result_per_term / obs_samples.size(); } } else { auto obs_samples = measure_with_samples(obs, num_shots, shot_range); - size_t num_elements = 0; - for (int element : obs_samples) { - result += element; - num_elements++; - } - result = result / num_elements; + result = + std::accumulate(obs_samples.begin(), obs_samples.end(), 0.0); + result = result / obs_samples.size(); } return result; @@ -240,8 +235,8 @@ template class MeasurementsBase { * * @param obs The observable to sample * @param num_shots Number of shots used to generate samples - * @param shot_range The range of samples to use. If it's empty, all samples - * are used. + * @param shot_range The range of samples to use. All samples are used by + * default. * * @return std::vector samples in std::vector */ @@ -296,8 +291,8 @@ template class MeasurementsBase { * * @param obs The observable to sample * @param num_shots Number of shots used to generate samples - * @param shot_range The range of samples to use. If it's empty, all samples - * are used. + * @param shot_range The range of samples to use. All samples are used by + * default. * @param obs_wires Observable wires. * @param identity_wires Wires of Identity gates * @param term_idx Index of a Hamiltonian term From 6fda0498842afc7a9b38b406eefa9299222602c8 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 15 Nov 2023 23:18:28 +0000 Subject: [PATCH 30/76] refactor and add _preprocess_state() method --- .../src/measurements/MeasurementsBase.hpp | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index d208d405a5..f5d6685164 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -138,9 +138,8 @@ template class MeasurementsBase { * @return Expectation value with respect to the given observable. */ auto expval(const Observable &obs, const size_t &num_shots, - const std::vector &shot_range) -> PrecisionT { + const std::vector &shot_range = {}) -> PrecisionT { PrecisionT result = 0; - std::vector short_range = {}; if (obs.getObsName().find("SparseHamiltonian") != std::string::npos) { PL_ABORT("For SparseHamiltonian Observables, expval calculation is " @@ -287,34 +286,24 @@ template class MeasurementsBase { */ private: /** - * @brief Return samples of a observable + * @brief Return preprocess state with a observable * * @param obs The observable to sample - * @param num_shots Number of shots used to generate samples - * @param shot_range The range of samples to use. All samples are used by - * default. * @param obs_wires Observable wires. * @param identity_wires Wires of Identity gates * @param term_idx Index of a Hamiltonian term * - * @return std::vector samples in std::vector + * @return a StateVectorT object */ - auto _sample_state(const Observable &obs, - const size_t &num_shots, - const std::vector &shot_range, - std::vector &obs_wires, - std::vector &identity_wires, - const size_t &term_idx = 0) { - const size_t num_qubits = _statevector.getTotalNumQubits(); - std::vector samples; - + auto _preprocess_state(const Observable &obs, + std::vector &obs_wires, + std::vector &identity_wires, + const size_t &term_idx = 0) { #ifdef _ENABLE_PLQUBIT if constexpr (std::is_same_v) { StateVectorT sv(_statevector); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); - Derived measure(sv); - samples = measure.generate_samples(num_shots); } else if constexpr (std::is_same_v< typename StateVectorT::MemoryStorageT, MemoryStorageLocation::External>) { @@ -326,28 +315,50 @@ template class MeasurementsBase { StateVectorT sv(data_storage.data(), data_storage.size()); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); - Derived measure(sv); - samples = measure.generate_samples(num_shots); } #else StateVectorT sv(_statevector); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); - Derived measure(sv); - samples = measure.generate_samples(num_shots); #endif - std::vector sub_samples; + return sv; + } + + /** + * @brief Return samples of a observable + * + * @param obs The observable to sample + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. All samples are used by + * default. + * @param obs_wires Observable wires. + * @param identity_wires Wires of Identity gates + * @param term_idx Index of a Hamiltonian term + * + * @return std::vector samples in std::vector + */ + auto _sample_state(const Observable &obs, + const size_t &num_shots, + const std::vector &shot_range, + std::vector &obs_wires, + std::vector &identity_wires, + const size_t &term_idx = 0) { + const size_t num_qubits = _statevector.getTotalNumQubits(); + auto sv = _preprocess_state(obs, obs_wires, identity_wires, term_idx); + Derived measure(sv); + auto samples = measure.generate_samples(num_shots); if (shot_range.empty()) { - sub_samples = samples; + return samples; } else { + std::vector sub_samples; // Get a slice of samples based on the shot_range vector for (auto &i : shot_range) { for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { sub_samples.push_back(samples[j]); } } + return sub_samples; } - return sub_samples; } }; From 2949500239bdf0ea64cbab2d8f1be44b0249837a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 14:21:50 +0000 Subject: [PATCH 31/76] add more unit tests for LK backend --- .../core/src/observables/Observables.hpp | 15 +++++- .../tests/Test_StateVectorKokkos_Expval.cpp | 54 +++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index d321d33dfe..6b8cad8ee6 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -62,7 +62,15 @@ template class Observable { virtual void applyInPlace(StateVectorT &sv) const = 0; /** - * @brief Apply the observable to the given statevector in place. + * @brief Apply unitaries of an observable to the given statevector in + * place. + * + * @param sv Reference to StateVector object. + * @param identify_wires Reference to a std::vector object which stores + * wires of Identity gates in the observable. + * @param ob_wires Reference to a std::vector object which stores wires of + * the observable. + * @param term_idx Index of a Hamiltonian term. */ virtual void applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, @@ -80,7 +88,7 @@ template class Observable { [[nodiscard]] virtual auto getWires() const -> std::vector = 0; /** - * @brief Get the wires the observable applies to. + * @brief Get the coefficients of a Hamiltonian observable. */ [[nodiscard]] virtual auto getCoeffs() const -> std::vector { return {}; @@ -179,6 +187,9 @@ class NamedObsBase : public Observable { } identify_wire.push_back(wires_[0]); } else { + PL_ABORT("Provided NamedObs is not supported for shots " + "calculation. Supported NamedObs are PauliX, PauliY, " + "PauliZ, Identity and Hadamard."); } } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp index 63204a5109..7a9891e399 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp @@ -381,6 +381,60 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", } } +TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots", + "[StateVectorKokkos_Expval]", float, double) { + using StateVectorT = StateVectorKokkos; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = StateVectorT::ComplexT; + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT sv{init_state.data(), init_state.size()}; + auto m = Measurements(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + size_t num_shots = 10000; + std::vector shot_range = {}; + + auto ob = TensorProdObs::create({X0, Z1}); + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = PrecisionT(-0.36); + + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + +TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", + "[StateVectorKokkos_Expval]", float, double) { + using StateVectorT = StateVectorKokkos; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = StateVectorT::ComplexT; + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT sv{init_state.data(), init_state.size()}; + auto m = Measurements(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); + size_t num_shots = 10000; + std::vector shot_range = {}; + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = PrecisionT(-0.086); + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + TEMPLATE_TEST_CASE("Test expectation value of NQubit Hermitian", "[StateVectorKokkos_Expval]", float, double) { using ComplexT = StateVectorKokkos::ComplexT; From 2cbd160079ee0700e546e5bf607ce96a01c89e6d Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Thu, 16 Nov 2023 14:23:22 +0000 Subject: [PATCH 32/76] 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 9daab1b916..226ada7853 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.34.0-dev7" +__version__ = "0.34.0-dev8" From 5595a8af79e74ace7186215c8401843a07e6059e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 14:38:37 +0000 Subject: [PATCH 33/76] tidy up docstring --- .../core/src/measurements/MeasurementsBase.hpp | 10 +++++----- .../core/src/observables/Observables.hpp | 2 +- .../lightning_gpu/measurements/MeasurementsGPU.hpp | 4 +++- .../lightning_gpu/measurements/MeasurementsGPUMPI.hpp | 4 +++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index f5d6685164..ec4f593a94 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -131,9 +131,9 @@ template class MeasurementsBase { * @brief Calculate the expectation value for a general Observable. * * @param obs Observable. - * @param num_shots Vector of shot number to measurement - * @param shot_range The range of samples to use. If it's empty, all samples - * are used. + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. All samples are used + * by default. * * @return Expectation value with respect to the given observable. */ @@ -144,8 +144,8 @@ template class MeasurementsBase { if (obs.getObsName().find("SparseHamiltonian") != std::string::npos) { PL_ABORT("For SparseHamiltonian Observables, expval calculation is " "not supported by shots"); - } else if (obs.getObsName().find("Hermintian") != std::string::npos) { - PL_ABORT("For Hermintian Observables, expval calculation is not " + } else if (obs.getObsName().find("Hermitian") != std::string::npos) { + PL_ABORT("For Hermitian Observables, expval calculation is not " "supported by shots"); } else if (obs.getObsName().find("Hamiltonian") != std::string::npos) { auto coeffs = obs.getCoeffs(); diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 6b8cad8ee6..64978d48b4 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -503,7 +503,7 @@ class HamiltonianBase : public Observable { } /** - * @brief Get the wires the observable applies to. + * @brief Get the coefficients of the observable. */ [[nodiscard]] auto getCoeffs() const -> std::vector override { return coeffs_; 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 cbf4bc5c8a..78ab5b53e8 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -354,7 +354,9 @@ class Measurements final * @brief Expectation value for a Observable with shots * * @param obs Observable. - * @param shots Vector of shot number to measurement + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. All samples are used + * by default. * @return Floating point expected value of the observable. */ diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp index bd2a96a147..c4bac79435 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp @@ -497,7 +497,9 @@ class MeasurementsMPI final * @brief Expectation value for a Observable with shots * * @param obs Observable. - * @param shots Vector of shot number to measurement + * @param num_shots Number of shots used to generate samples. + * @param shot_range The range of samples to use. All samples are used + * by default. * @return Floating point expected value of the observable. */ From d41f2b275284d1c3f7b496118eef23d520567ce2 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 14:48:30 +0000 Subject: [PATCH 34/76] remove samples() and samples2counts method --- .../src/measurements/MeasurementsBase.hpp | 70 +------------------ 1 file changed, 3 insertions(+), 67 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index ec4f593a94..e16df403ff 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -29,16 +29,6 @@ /// @cond DEV namespace { using namespace Pennylane::Observables; -/* -auto sample_to_str(std::vector &sample) -> std::string { - std::string str; - for (auto &element : sample) { - str += std::to_string(element); - } - return str; -} -*/ - } // namespace /// @endcond @@ -173,9 +163,9 @@ template class MeasurementsBase { * @brief Calculate the expectation value for a general Observable. * * @param obs Observable. - * @param num_shots Vector of shot number to measurement - * @param shot_range The range of samples to use. If it's empty, all samples - * are used. + * @param num_shots Number of shots used to generate samples + * @param shot_range The range of samples to use. All samples are used + * by default. * @param term_idx Index of a Hamiltonian term * * @return Expectation value with respect to the given observable. @@ -229,61 +219,7 @@ template class MeasurementsBase { return obs_samples; } - /** - * @brief Return samples of a observable - * - * @param obs The observable to sample - * @param num_shots Number of shots used to generate samples - * @param shot_range The range of samples to use. All samples are used by - * default. - * - * @return std::vector samples in std::vector - */ - auto samples(const Observable &obs, const size_t &num_shots, - const std::vector &shot_range) { - PL_ABORT_IF( - obs.getObsName().find("Hamiltonian") != std::string::npos, - "Samples does not support Hamiltonian and Sparse Hamiltonian."); - std::vector obs_wires; - std::vector identity_wires; - return _sample_state(obs, num_shots, shot_range, obs_wires, - identity_wires); - } - /** - * @brief Groups the samples into a dictionary showing number of occurences - * for each possible outcome. - * - * @param samples A vector of samples with size of ``num_shots * - * num_obs_wires`` - * @param num_wires number of wires the sampled observable was performed on - * - * @return std::unordered_map with format ``{'outcome': - * num_occurences}`` - */ - /* - auto samples_to_counts(std::vector &samples, size_t &num_shots, - size_t &num_obs_wires) - -> std::unordered_map { - std::unordered_map outcome_map; - - for (size_t i = 0; i < num_shots; i++) { - auto local_sample = - std::vector(samples.begin() + i * num_obs_wires, - samples.begin() + (i + 1) * num_obs_wires - 1); - std::string key = sample_to_str(local_sample); - - auto it = outcome_map.find(key); - - if (it != outcome_map.end()) { - it->second += 1; - } else { - outcome_map[key] = 1; - } - } - return outcome_map; - } - */ private: /** * @brief Return preprocess state with a observable From ebf80f01207da21082bee051f16d94fab609a1c9 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 14:54:08 +0000 Subject: [PATCH 35/76] fix typo --- .../core/src/measurements/MeasurementsBase.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index e16df403ff..94b2765ac7 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -155,7 +155,6 @@ template class MeasurementsBase { std::accumulate(obs_samples.begin(), obs_samples.end(), 0.0); result = result / obs_samples.size(); } - return result; } @@ -290,6 +289,7 @@ template class MeasurementsBase { // Get a slice of samples based on the shot_range vector for (auto &i : shot_range) { for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { + //TODO some extra work to make it cache-friendly sub_samples.push_back(samples[j]); } } @@ -297,5 +297,4 @@ template class MeasurementsBase { } } }; - -} // namespace Pennylane::Measures \ No newline at end of file +} // namespace Pennylane::Measures From 3238a080088312f8cc9df8acb7780c41753b5855 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 14:58:07 +0000 Subject: [PATCH 36/76] quick fix --- .../core/src/measurements/MeasurementsBase.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 94b2765ac7..03084436b2 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -239,6 +239,7 @@ template class MeasurementsBase { MemoryStorageLocation::Internal>) { StateVectorT sv(_statevector); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); + return sv; } else if constexpr (std::is_same_v< typename StateVectorT::MemoryStorageT, MemoryStorageLocation::External>) { @@ -250,12 +251,13 @@ template class MeasurementsBase { StateVectorT sv(data_storage.data(), data_storage.size()); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); + return sv; } #else StateVectorT sv(_statevector); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); -#endif return sv; +#endif } /** From 35065d1aa6a0e4d728d800360d33ddfd7f386ba0 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 18:16:48 +0000 Subject: [PATCH 37/76] update LQRaw object creation --- .../core/src/measurements/MeasurementsBase.hpp | 11 +++-------- .../core/src/observables/Observables.hpp | 2 +- .../lightning_qubit/StateVectorLQubitRaw.hpp | 1 - .../measurements/tests/Test_MeasurementsLQubit.cpp | 4 ++-- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 03084436b2..f7d4bacbef 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -218,7 +218,6 @@ template class MeasurementsBase { return obs_samples; } - private: /** * @brief Return preprocess state with a observable @@ -243,13 +242,9 @@ template class MeasurementsBase { } else if constexpr (std::is_same_v< typename StateVectorT::MemoryStorageT, MemoryStorageLocation::External>) { + StateVectorT sv(_statevector.getData(), _statevector.getLength()); - std::vector data_storage(_statevector.getData(), - _statevector.getData() + - _statevector.getLength()); - - StateVectorT sv(data_storage.data(), data_storage.size()); - + sv.updateData(_statevector.getData(), _statevector.getLength()); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); return sv; } @@ -291,7 +286,7 @@ template class MeasurementsBase { // Get a slice of samples based on the shot_range vector for (auto &i : shot_range) { for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { - //TODO some extra work to make it cache-friendly + // TODO some extra work to make it cache-friendly sub_samples.push_back(samples[j]); } } diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 64978d48b4..dc38f83f09 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -248,7 +248,7 @@ class HermitianObsBase : public Observable { void applyInPlaceShots( [[maybe_unused]] StateVectorT &sv, [[maybe_unused]] std::vector &identify_wire, - [[maybe_unused]] std::vector &ob_wires = {}, + [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] const size_t term_idx = 0) const override { PL_ABORT( "For Hermitian Observables with shots, the applyInPlace method is " diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp index e60502e1b5..b7879cf723 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp @@ -91,7 +91,6 @@ class StateVectorLQubitRaw final */ auto getTotalNumQubits() const -> size_t { return log2PerfectPower(length_); - ; } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index c7dcc3bdfb..2d3116c65d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -138,7 +138,7 @@ TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of TensorProdObs shots", auto Z1 = std::make_shared>( "PauliZ", std::vector{1}); - size_t num_shots = 10000; + size_t num_shots = 1000; std::vector shot_range = {}; auto ob = TensorProdObs::create({X0, Z1}); @@ -169,7 +169,7 @@ TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of HamiltonianObs shot", "PauliZ", std::vector{1}); auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); - size_t num_shots = 10000; + size_t num_shots = 1000; std::vector shot_range = {}; auto res = m.expval(*ob, num_shots, shot_range); auto expected = PrecisionT(-0.086); From 264481f60f1f89c5f05e331561b2e7799560f7f5 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 19:32:43 +0000 Subject: [PATCH 38/76] fix for multiple backends --- .../src/measurements/MeasurementsBase.hpp | 22 +++++-------------- .../lightning_gpu/StateVectorCudaMPI.hpp | 3 +++ .../lightning_gpu/StateVectorCudaManaged.hpp | 3 +++ .../lightning_kokkos/StateVectorKokkos.hpp | 3 +++ 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index f7d4bacbef..378642b8e2 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -22,9 +22,7 @@ #include "Observables.hpp" -#ifdef _ENABLE_PLQUBIT #include "CPUMemoryModel.hpp" -#endif /// @cond DEV namespace { @@ -233,26 +231,18 @@ template class MeasurementsBase { std::vector &obs_wires, std::vector &identity_wires, const size_t &term_idx = 0) { -#ifdef _ENABLE_PLQUBIT - if constexpr (std::is_same_v) { - StateVectorT sv(_statevector); - obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); - return sv; - } else if constexpr (std::is_same_v< + if constexpr (std::is_same_v< typename StateVectorT::MemoryStorageT, - MemoryStorageLocation::External>) { + Pennylane::Util::MemoryStorageLocation::External>) { StateVectorT sv(_statevector.getData(), _statevector.getLength()); - sv.updateData(_statevector.getData(), _statevector.getLength()); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); return sv; + } else { + StateVectorT sv(_statevector); + obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); + return sv; } -#else - StateVectorT sv(_statevector); - obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); - return sv; -#endif } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp index 39979501a0..268d7332ae 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaMPI.hpp @@ -38,6 +38,8 @@ #include "cuGates_host.hpp" #include "cuda_helpers.hpp" +#include "CPUMemoryModel.hpp" + #include "LinearAlg.hpp" /// @cond DEV @@ -97,6 +99,7 @@ class StateVectorCudaMPI final StateVectorCudaMPI>::CFP_t; using PrecisionT = Precision; using ComplexT = std::complex; + using MemoryStorageT = Pennylane::Util::MemoryStorageLocation::Undefined; StateVectorCudaMPI() = delete; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp index 6b4eb1bd52..ed7d77472d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp @@ -34,6 +34,8 @@ #include "cuGates_host.hpp" #include "cuda_helpers.hpp" +#include "CPUMemoryModel.hpp" + #include "cuError.hpp" #include "LinearAlg.hpp" @@ -81,6 +83,7 @@ class StateVectorCudaManaged using CFP_t = typename StateVectorCudaBase>::CFP_t; + using MemoryStorageT = Pennylane::Util::MemoryStorageLocation::Undefined; StateVectorCudaManaged() = delete; StateVectorCudaManaged(size_t num_qubits) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp index 5ebc323201..8dedce9c39 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp @@ -35,6 +35,8 @@ #include "StateVectorBase.hpp" #include "Util.hpp" +#include "CPUMemoryModel.hpp" + /// @cond DEV namespace { using Pennylane::Gates::GateOperation; @@ -90,6 +92,7 @@ class StateVectorKokkos final Kokkos::View>; using TeamPolicy = Kokkos::TeamPolicy<>; + using MemoryStorageT = Pennylane::Util::MemoryStorageLocation::Undefined; StateVectorKokkos() = delete; StateVectorKokkos(size_t num_qubits, From 2d3cf11fec083722fd56dd154f8a387170750be2 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 19:40:12 +0000 Subject: [PATCH 39/76] update format --- .../core/src/measurements/MeasurementsBase.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 378642b8e2..9674ab2088 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -201,8 +201,9 @@ template class MeasurementsBase { // eigen values are `1` and `-1` for PauliX, PauliY, PauliZ, // Hadamard gates the eigen value for a eigen vector |00001> is // -1 since sum of the value at each bit position is odd - if ((std::accumulate(local_sample.begin() + num_identity_obs, - local_sample.end(), 0) & + if ((static_cast(std::accumulate( + local_sample.begin() + num_identity_obs, + local_sample.end(), 0)) & 1) == 1) { obs_samples[i] = -1; } else { @@ -232,8 +233,8 @@ template class MeasurementsBase { std::vector &identity_wires, const size_t &term_idx = 0) { if constexpr (std::is_same_v< - typename StateVectorT::MemoryStorageT, - Pennylane::Util::MemoryStorageLocation::External>) { + typename StateVectorT::MemoryStorageT, + Pennylane::Util::MemoryStorageLocation::External>) { StateVectorT sv(_statevector.getData(), _statevector.getLength()); sv.updateData(_statevector.getData(), _statevector.getLength()); obs.applyInPlaceShots(sv, identity_wires, obs_wires, term_idx); @@ -269,9 +270,7 @@ template class MeasurementsBase { Derived measure(sv); auto samples = measure.generate_samples(num_shots); - if (shot_range.empty()) { - return samples; - } else { + if (!shot_range.empty()) { std::vector sub_samples; // Get a slice of samples based on the shot_range vector for (auto &i : shot_range) { @@ -282,6 +281,7 @@ template class MeasurementsBase { } return sub_samples; } + return samples; } }; } // namespace Pennylane::Measures From b12885d9f67b2012b1cafcb1a39e8c71b4ea160d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 19:51:11 +0000 Subject: [PATCH 40/76] format fix --- .../core/src/measurements/MeasurementsBase.hpp | 11 +++++++---- .../lightning_qubit/StateVectorLQubitManaged.hpp | 2 +- .../lightning_qubit/StateVectorLQubitRaw.hpp | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 9674ab2088..5829257514 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -204,7 +204,7 @@ template class MeasurementsBase { if ((static_cast(std::accumulate( local_sample.begin() + num_identity_obs, local_sample.end(), 0)) & - 1) == 1) { + size_t{1}) == 1) { obs_samples[i] = -1; } else { obs_samples[i] = 1; @@ -271,13 +271,16 @@ template class MeasurementsBase { auto samples = measure.generate_samples(num_shots); if (!shot_range.empty()) { - std::vector sub_samples; + std::vector sub_samples(shot_range.size() * num_qubits); // Get a slice of samples based on the shot_range vector - for (auto &i : shot_range) { + size_t shot_idx = 0; + for (const auto &i : shot_range) { for (size_t j = i * num_qubits; j < (i + 1) * num_qubits; j++) { // TODO some extra work to make it cache-friendly - sub_samples.push_back(samples[j]); + sub_samples[shot_idx * num_qubits + j - i * num_qubits] = + samples[j]; } + shot_idx++; } return sub_samples; } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp index 2d7aaf32ac..f31890240d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp @@ -142,7 +142,7 @@ class StateVectorLQubitManaged final /** * @brief Get the total number of wires. */ - auto getTotalNumQubits() const -> size_t { + [[nodiscard]] auto getTotalNumQubits() const -> size_t { return log2PerfectPower(data_.size()); } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp index b7879cf723..e5eeac87fc 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp @@ -89,7 +89,7 @@ class StateVectorLQubitRaw final /** * @brief Get the total number of wires. */ - auto getTotalNumQubits() const -> size_t { + [[nodiscard]] auto getTotalNumQubits() const -> size_t { return log2PerfectPower(length_); } From ad1e11d5d36b9900d535114aa86c2c0a55a5830f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 20:14:29 +0000 Subject: [PATCH 41/76] format update --- .../core/src/measurements/MeasurementsBase.hpp | 8 +++++--- .../core/src/observables/Observables.hpp | 12 ++++++------ .../lightning_gpu/observables/ObservablesGPU.hpp | 2 +- .../lightning_gpu/observables/ObservablesGPUMPI.hpp | 2 +- .../observables/ObservablesKokkos.hpp | 2 +- .../observables/ObservablesLQubit.hpp | 2 +- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 5829257514..92ee5c98c0 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -170,7 +170,7 @@ template class MeasurementsBase { auto measure_with_samples(const Observable &obs, const size_t &num_shots, const std::vector &shot_range, - const size_t term_idx = 0) { + size_t term_idx = 0) { const size_t num_qubits = _statevector.getTotalNumQubits(); std::vector obs_wires; std::vector identity_wires; @@ -192,9 +192,11 @@ template class MeasurementsBase { } for (size_t i = 0; i < num_shots; i++) { - std::vector local_sample; + std::vector local_sample(obs_wires.size()); + size_t idx = 0; for (auto &obs_wire : obs_wires) { - local_sample.push_back(sub_samples[i * num_qubits + obs_wire]); + local_sample[idx] = sub_samples[i * num_qubits + obs_wire]; + idx++; } if (num_identity_obs != obs_wires.size()) { diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index dc38f83f09..ab6647ecc9 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -75,7 +75,7 @@ template class Observable { virtual void applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, std::vector &ob_wires, - const size_t term_idx = 0) const = 0; + size_t term_idx = 0) const = 0; /** * @brief Get the name of the observable @@ -167,7 +167,7 @@ class NamedObsBase : public Observable { void applyInPlaceShots( StateVectorT &sv, std::vector &identify_wire, std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + [[maybe_unused]] size_t term_idx = 0) const override { ob_wires.clear(); identify_wire.clear(); ob_wires.push_back(wires_[0]); @@ -249,7 +249,7 @@ class HermitianObsBase : public Observable { [[maybe_unused]] StateVectorT &sv, [[maybe_unused]] std::vector &identify_wire, [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT( "For Hermitian Observables with shots, the applyInPlace method is " "not supported."); @@ -367,7 +367,7 @@ class TensorProdObsBase : public Observable { void applyInPlaceShots( StateVectorT &sv, std::vector &identify_wires, std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + [[maybe_unused]] size_t term_idx = 0) const override { identify_wires.clear(); ob_wires.clear(); for (const auto &ob : obs_) { @@ -470,7 +470,7 @@ class HamiltonianBase : public Observable { [[maybe_unused]] StateVectorT &sv, [[maybe_unused]] std::vector &identify_wires, [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT("For Hamiltonian Observables, the applyInPlace method must be " "defined at the backend level."); } @@ -596,7 +596,7 @@ class SparseHamiltonianBase : public Observable { [[maybe_unused]] StateVectorT &sv, [[maybe_unused]] std::vector &identify_wire, [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] const size_t term_idx = 0) const override { + [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT("For SparseHamiltonian Observables, the applyInPlace method " "must be " "defined at the backend level."); diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp index 80b2c8f8ae..5b08f912ed 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp @@ -212,7 +212,7 @@ class Hamiltonian final : public HamiltonianBase { void applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, std::vector &ob_wires, - const size_t term_idx) const override { + size_t term_idx) const override { ob_wires.clear(); this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, term_idx); diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp index fabd0f5d2d..837862a96c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp @@ -219,7 +219,7 @@ class HamiltonianMPI final : public HamiltonianBase { void applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, std::vector &ob_wires, - const size_t term_idx) const override { + size_t term_idx) const override { ob_wires.clear(); this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, term_idx); diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp index 0737b2edea..c473ae70e2 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp @@ -203,7 +203,7 @@ class Hamiltonian final : public HamiltonianBase { void applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, std::vector &ob_wires, - const size_t term_idx) const override { + size_t term_idx) const override { ob_wires.clear(); this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, term_idx); diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp index 69d01fa250..f96cc82351 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp @@ -363,7 +363,7 @@ class Hamiltonian final : public HamiltonianBase { void applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, std::vector &ob_wires, - const size_t term_idx) const override { + size_t term_idx) const override { ob_wires.clear(); this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, term_idx); From 288e01e6efb9d061a59ff7662bbd67daa9ffcfad Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 20:29:04 +0000 Subject: [PATCH 42/76] make format & trigger MPI CI --- .../core/src/observables/Observables.hpp | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index ab6647ecc9..fe41b677be 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -164,10 +164,10 @@ class NamedObsBase : public Observable { sv.applyOperation(obs_name_, wires_, false, params_); } - void applyInPlaceShots( - StateVectorT &sv, std::vector &identify_wire, - std::vector &ob_wires, - [[maybe_unused]] size_t term_idx = 0) const override { + void + applyInPlaceShots(StateVectorT &sv, std::vector &identify_wire, + std::vector &ob_wires, + [[maybe_unused]] size_t term_idx = 0) const override { ob_wires.clear(); identify_wire.clear(); ob_wires.push_back(wires_[0]); @@ -245,11 +245,11 @@ class HermitianObsBase : public Observable { sv.applyMatrix(matrix_, wires_); } - void applyInPlaceShots( - [[maybe_unused]] StateVectorT &sv, - [[maybe_unused]] std::vector &identify_wire, - [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] size_t term_idx = 0) const override { + void + applyInPlaceShots([[maybe_unused]] StateVectorT &sv, + [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &ob_wires, + [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT( "For Hermitian Observables with shots, the applyInPlace method is " "not supported."); @@ -364,10 +364,10 @@ class TensorProdObsBase : public Observable { } } - void applyInPlaceShots( - StateVectorT &sv, std::vector &identify_wires, - std::vector &ob_wires, - [[maybe_unused]] size_t term_idx = 0) const override { + void + applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, + std::vector &ob_wires, + [[maybe_unused]] size_t term_idx = 0) const override { identify_wires.clear(); ob_wires.clear(); for (const auto &ob : obs_) { @@ -466,11 +466,11 @@ class HamiltonianBase : public Observable { "defined at the backend level."); } - void applyInPlaceShots( - [[maybe_unused]] StateVectorT &sv, - [[maybe_unused]] std::vector &identify_wires, - [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] size_t term_idx = 0) const override { + void + applyInPlaceShots([[maybe_unused]] StateVectorT &sv, + [[maybe_unused]] std::vector &identify_wires, + [[maybe_unused]] std::vector &ob_wires, + [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT("For Hamiltonian Observables, the applyInPlace method must be " "defined at the backend level."); } @@ -592,11 +592,11 @@ class SparseHamiltonianBase : public Observable { "defined at the backend level."); } - void applyInPlaceShots( - [[maybe_unused]] StateVectorT &sv, - [[maybe_unused]] std::vector &identify_wire, - [[maybe_unused]] std::vector &ob_wires, - [[maybe_unused]] size_t term_idx = 0) const override { + void + applyInPlaceShots([[maybe_unused]] StateVectorT &sv, + [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &ob_wires, + [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT("For SparseHamiltonian Observables, the applyInPlace method " "must be " "defined at the backend level."); From e08cb854e7b552321b3b6a3f1c92a4cdb5d62e3e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 16:37:25 -0500 Subject: [PATCH 43/76] add changelog and codecov for expval(obs) method --- .github/CHANGELOG.md | 3 + .../tests/Test_MeasurementsBase.cpp | 94 +++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index f5cfe8075b..8796fafb28 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add shots support for expectation value calculation for the observables (NamedObs, TensorProd and Hamiltonian) based on Pauli words, Identity and Hadamard in the C++ layer. All Lightning backends have this support now. +[(#556)](https://github.com/PennyLaneAI/pennylane-lightning/pull/556) + * `qml.QubitUnitary` operators can be included in a circuit differentiated with the adjoint method. Lightning handles circuits with arbitrary non-differentiable `qml.QubitUnitary` operators. 1,2-qubit `qml.QubitUnitary` operators with differentiable parameters can be differentiated using decomposition. [(#540)] (https://github.com/PennyLaneAI/pennylane-lightning/pull/540) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 477fc7ce42..91054703c2 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -245,6 +245,59 @@ TEST_CASE("Expval Shot- NamedObs", "[MeasurementsBase][Observables]") { } } +template void testHermitianObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = typename StateVectorT::ComplexT; + using MatrixT = std::vector; + + // Defining the State Vector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + const PrecisionT theta = M_PI / 2; + const PrecisionT real_term = std::cos(theta); + const PrecisionT imag_term = std::sin(theta); + + DYNAMIC_SECTION("Failed for Hermitian" + << StateVectorToName::name) { + std::vector> wires_list = {{0}, {1}, {2}}; + // Expected results calculated with Pennylane default.qubit: + std::vector exp_values_ref = { + 0.644217687237691, 0.4794255386042027, 0.29552020666133955}; + + MatrixT Hermitian_matrix{real_term, ComplexT{0, imag_term}, + ComplexT{0, -imag_term}, real_term}; + + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + HermitianObs obs(Hermitian_matrix, + wires_list[ind_wires]); + size_t num_shots = 1000; + std::vector shots_range = {}; + REQUIRE_THROWS_WITH( + Measurer.expval(obs, num_shots, shots_range), + Catch::Matchers::Contains( + "expval calculation is not supported by shots")); + } + } + + testHermitianObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot - HermitianObs ", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testHermitianObsExpvalShot(); + } +} + template void testHermitianObsExpval() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; @@ -508,4 +561,45 @@ TEST_CASE("Samples", "[MeasurementsBase]") { if constexpr (BACKEND_FOUND) { testSamples(); } +} + +template void testSparseHObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using ComplexT = typename StateVectorT::ComplexT; + + // Defining the State Vector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + auto sparseH = SparseHamiltonian::create( + {ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, + ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, + ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}}, + {7, 6, 5, 4, 3, 2, 1, 0}, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {0, 1, 2}); + + + DYNAMIC_SECTION("Failed for SparseH " + << StateVectorToName::name) { + size_t num_shots = 1000; + std::vector shots_range = {}; + REQUIRE_THROWS_WITH( + Measurer.expval(*sparseH, num_shots, shots_range), + Catch::Matchers::Contains( + "expval calculation is not supported by shots")); + } + + testSparseHObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot - SparseHObs ", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testSparseHObsExpvalShot(); + } } \ No newline at end of file From 2e495dba22bbfd0efaf6915ce5b058f6196b523b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 17:16:20 -0500 Subject: [PATCH 44/76] add shot_range coverage --- .../src/measurements/MeasurementsBase.hpp | 8 ++- .../tests/Test_MeasurementsBase.cpp | 49 +++++++++++++------ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 92ee5c98c0..67bee8a965 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -178,7 +178,11 @@ template class MeasurementsBase { auto sub_samples = _sample_state(obs, num_shots, shot_range, obs_wires, identity_wires, term_idx); - std::vector obs_samples(num_shots, 0); + size_t num_samples = num_shots; + if (!shot_range.empty()) { + num_samples = shot_range.size(); + } + std::vector obs_samples(num_samples, 0); size_t num_identity_obs = identity_wires.size(); if (!identity_wires.empty()) { @@ -191,7 +195,7 @@ template class MeasurementsBase { } } - for (size_t i = 0; i < num_shots; i++) { + for (size_t i = 0; i < num_samples; i++) { std::vector local_sample(obs_wires.size()); size_t idx = 0; for (auto &obs_wire : obs_wires) { diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 91054703c2..6d953d2536 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -209,21 +209,41 @@ template void testNamedObsExpvalShot() { std::vector> wires_list = {{0}, {1}, {2}}; std::vector obs_name = {"PauliX", "PauliY", "PauliZ", - "Hadamard"}; + "Hadamard", "Identity"}; // Expected results calculated with Pennylane default.qubit: std::vector> exp_values_ref = { {0.49272486, 0.42073549, 0.28232124}, {-0.64421768, -0.47942553, -0.29552020}, {0.58498357, 0.77015115, 0.91266780}, - {0.7620549436, 0.8420840225, 0.8449848566}}; - - size_t num_shots = 10000; - std::vector shots_range = {}; - + {0.7620549436, 0.8420840225, 0.8449848566}, + {1.0, 1.0, 1.0}}; for (size_t ind_obs = 0; ind_obs < obs_name.size(); ind_obs++) { DYNAMIC_SECTION(obs_name[ind_obs] << " - Varying wires" << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObs obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + PrecisionT result = + Measurer.expval(obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + } + } + + for (size_t ind_obs = 0; ind_obs < obs_name.size(); ind_obs++) { + DYNAMIC_SECTION(obs_name[ind_obs] + << " - Varying wires-with shots_range" + << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } for (size_t ind_wires = 0; ind_wires < wires_list.size(); ind_wires++) { NamedObs obs(obs_name[ind_obs], @@ -579,19 +599,18 @@ template void testSparseHObsExpvalShot() { auto sparseH = SparseHamiltonian::create( {ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, - ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, - ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}}, + ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}, + ComplexT{1.0, 0.0}, ComplexT{1.0, 0.0}}, {7, 6, 5, 4, 3, 2, 1, 0}, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {0, 1, 2}); - DYNAMIC_SECTION("Failed for SparseH " << StateVectorToName::name) { - size_t num_shots = 1000; - std::vector shots_range = {}; - REQUIRE_THROWS_WITH( - Measurer.expval(*sparseH, num_shots, shots_range), - Catch::Matchers::Contains( - "expval calculation is not supported by shots")); + size_t num_shots = 1000; + std::vector shots_range = {}; + REQUIRE_THROWS_WITH( + Measurer.expval(*sparseH, num_shots, shots_range), + Catch::Matchers::Contains( + "expval calculation is not supported by shots")); } testSparseHObsExpvalShot(); From 0acc096b8b3daf898688a7e9686509269dac37e5 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 17:28:00 -0500 Subject: [PATCH 45/76] tidy up code --- .../tests/Test_MeasurementsBase.cpp | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 6d953d2536..d6651c9c2b 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -287,25 +287,16 @@ template void testHermitianObsExpvalShot() { DYNAMIC_SECTION("Failed for Hermitian" << StateVectorToName::name) { - std::vector> wires_list = {{0}, {1}, {2}}; - // Expected results calculated with Pennylane default.qubit: - std::vector exp_values_ref = { - 0.644217687237691, 0.4794255386042027, 0.29552020666133955}; - MatrixT Hermitian_matrix{real_term, ComplexT{0, imag_term}, ComplexT{0, -imag_term}, real_term}; - for (size_t ind_wires = 0; ind_wires < wires_list.size(); - ind_wires++) { - HermitianObs obs(Hermitian_matrix, - wires_list[ind_wires]); - size_t num_shots = 1000; - std::vector shots_range = {}; - REQUIRE_THROWS_WITH( - Measurer.expval(obs, num_shots, shots_range), - Catch::Matchers::Contains( - "expval calculation is not supported by shots")); - } + HermitianObs obs(Hermitian_matrix, {0}); + size_t num_shots = 1000; + std::vector shots_range = {}; + REQUIRE_THROWS_WITH( + Measurer.expval(obs, num_shots, shots_range), + Catch::Matchers::Contains( + "expval calculation is not supported by shots")); } testHermitianObsExpvalShot(); From 4f5f6344f3f4254a51f96753537e77c02d5ff5f6 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 18:23:59 -0500 Subject: [PATCH 46/76] add more unit tests --- .../tests/Test_MeasurementsBase.cpp | 1 + .../core/src/observables/Observables.hpp | 22 +++---- .../observables/tests/Test_Observables.cpp | 60 +++++++++++++++++++ 3 files changed, 70 insertions(+), 13 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index d6651c9c2b..2bd7232eaf 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -297,6 +297,7 @@ template void testHermitianObsExpvalShot() { Measurer.expval(obs, num_shots, shots_range), Catch::Matchers::Contains( "expval calculation is not supported by shots")); + REQUIRE(obs.getCoeffs().size() == 0); } testHermitianObsExpvalShot(); diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index fe41b677be..8b7b72c4b0 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -182,12 +182,9 @@ class NamedObsBase : public Observable { sv.applyOperation("RY", wires_, false, {theta}); } else if (obs_name_ == "PauliZ") { } else if (obs_name_ == "Identity") { - if (!identify_wire.empty()) { - identify_wire.clear(); - } identify_wire.push_back(wires_[0]); } else { - PL_ABORT("Provided NamedObs is not supported for shots " + PL_ABORT("Provided NamedObs does not supported for shots " "calculation. Supported NamedObs are PauliX, PauliY, " "PauliZ, Identity and Hadamard."); } @@ -250,9 +247,8 @@ class HermitianObsBase : public Observable { [[maybe_unused]] std::vector &identify_wire, [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { - PL_ABORT( - "For Hermitian Observables with shots, the applyInPlace method is " - "not supported."); + PL_ABORT("For Hermitian Observables, the applyInPlaceShots method is " + "not supported."); } }; @@ -365,17 +361,17 @@ class TensorProdObsBase : public Observable { } void - applyInPlaceShots(StateVectorT &sv, std::vector &identify_wires, + applyInPlaceShots(StateVectorT &sv, std::vector &identity_wires, std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { - identify_wires.clear(); + identity_wires.clear(); ob_wires.clear(); for (const auto &ob : obs_) { std::vector identity_wire; std::vector ob_wire; ob->applyInPlaceShots(sv, identity_wire, ob_wire); if (!identity_wire.empty()) { - identify_wires.push_back(identity_wire[0]); + identity_wires.push_back(identity_wire[0]); } ob_wires.push_back(ob_wire[0]); } @@ -597,9 +593,9 @@ class SparseHamiltonianBase : public Observable { [[maybe_unused]] std::vector &identify_wire, [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { - PL_ABORT("For SparseHamiltonian Observables, the applyInPlace method " - "must be " - "defined at the backend level."); + PL_ABORT( + "For SparseHamiltonian Observables, the applyInPlaceShots method " + "is not supported."); } [[nodiscard]] auto getObsName() const -> std::string override { diff --git a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp index d0bb9799b1..475b9fc423 100644 --- a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp +++ b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp @@ -21,6 +21,7 @@ #include #include +#include #include /** * @file @@ -82,6 +83,7 @@ template struct StateVectorToName {}; template void testNamedObsBase() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; using NamedObsT = NamedObsBase; DYNAMIC_SECTION("Name of the Observable must be correct - " @@ -119,6 +121,24 @@ template void testNamedObsBase() { REQUIRE(ob1 != ob3); } + DYNAMIC_SECTION("Unsupported NamedObs for applyInPlaceShots") { + std::mt19937_64 re{1337}; + const size_t num_qubits = 3; + auto init_state = + createRandomStateVectorData(re, num_qubits); + + StateVectorT state_vector(init_state.data(), init_state.size()); + auto obs = NamedObsT("RY", {0}, {0.4}); + + std::vector identify_wire; + std::vector ob_wires; + + REQUIRE_THROWS_WITH( + obs.applyInPlaceShots(state_vector, identify_wire, ob_wires), + Catch::Matchers::Contains( + "Provided NamedObs does not supported for shots")); + } + testNamedObsBase(); } } @@ -133,6 +153,7 @@ template void testHermitianObsBase() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; using ComplexT = typename StateVectorT::ComplexT; + using PrecisionT = typename StateVectorT::PrecisionT; using HermitianObsT = HermitianObsBase; DYNAMIC_SECTION("HermitianObs only accepts correct arguments - " @@ -183,6 +204,27 @@ template void testHermitianObsBase() { REQUIRE(ob2 != ob3); } + DYNAMIC_SECTION("Failed for HermitianObs for applyInPlaceShots - " + << StateVectorToName::name) { + std::mt19937_64 re{1337}; + const size_t num_qubits = 3; + auto init_state = + createRandomStateVectorData(re, num_qubits); + + StateVectorT state_vector(init_state.data(), init_state.size()); + auto obs = + HermitianObsT{std::vector{1.0, 0.0, -1.0, 0.0}, {0}}; + + std::vector identify_wire; + std::vector ob_wires; + + REQUIRE_THROWS_WITH( + obs.applyInPlaceShots(state_vector, identify_wire, ob_wires), + Catch::Matchers::Contains( + "For Hermitian Observables, the applyInPlaceShots method " + "is not supported.")); + } + testHermitianObsBase(); } } @@ -535,6 +577,24 @@ template void testSparseHamiltonianBase() { LightningException); } + DYNAMIC_SECTION("SparseHamiltonianBase - applyInPlaceShots must fail - " + << StateVectorToName::name) { + auto init_state = + createRandomStateVectorData(re, num_qubits); + + StateVectorT state_vector(init_state.data(), init_state.size()); + + std::vector identify_wire; + std::vector ob_wires; + + REQUIRE_THROWS_WITH( + sparseH->applyInPlaceShots(state_vector, identify_wire, + ob_wires), + Catch::Matchers::Contains("For SparseHamiltonian Observables, " + "the applyInPlaceShots method " + "is not supported.")); + } + testSparseHamiltonianBase(); } } From fe042f649bd1576232a6cec946cde0731cce989c Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 18:30:07 -0500 Subject: [PATCH 47/76] fix typos --- .../core/src/observables/Observables.hpp | 16 ++++++++-------- .../src/observables/tests/Test_Observables.cpp | 12 ++++++------ .../lightning_gpu/observables/ObservablesGPU.hpp | 4 ++-- .../observables/ObservablesGPUMPI.hpp | 4 ++-- .../observables/ObservablesKokkos.hpp | 4 ++-- .../observables/ObservablesLQubit.hpp | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 8b7b72c4b0..94948c03fa 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -66,14 +66,14 @@ template class Observable { * place. * * @param sv Reference to StateVector object. - * @param identify_wires Reference to a std::vector object which stores + * @param identity_wires Reference to a std::vector object which stores * wires of Identity gates in the observable. * @param ob_wires Reference to a std::vector object which stores wires of * the observable. * @param term_idx Index of a Hamiltonian term. */ virtual void applyInPlaceShots(StateVectorT &sv, - std::vector &identify_wires, + std::vector &identity_wires, std::vector &ob_wires, size_t term_idx = 0) const = 0; @@ -165,11 +165,11 @@ class NamedObsBase : public Observable { } void - applyInPlaceShots(StateVectorT &sv, std::vector &identify_wire, + applyInPlaceShots(StateVectorT &sv, std::vector &identity_wire, std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { ob_wires.clear(); - identify_wire.clear(); + identity_wire.clear(); ob_wires.push_back(wires_[0]); if (obs_name_ == "PauliX") { @@ -182,7 +182,7 @@ class NamedObsBase : public Observable { sv.applyOperation("RY", wires_, false, {theta}); } else if (obs_name_ == "PauliZ") { } else if (obs_name_ == "Identity") { - identify_wire.push_back(wires_[0]); + identity_wire.push_back(wires_[0]); } else { PL_ABORT("Provided NamedObs does not supported for shots " "calculation. Supported NamedObs are PauliX, PauliY, " @@ -244,7 +244,7 @@ class HermitianObsBase : public Observable { void applyInPlaceShots([[maybe_unused]] StateVectorT &sv, - [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &identity_wire, [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT("For Hermitian Observables, the applyInPlaceShots method is " @@ -464,7 +464,7 @@ class HamiltonianBase : public Observable { void applyInPlaceShots([[maybe_unused]] StateVectorT &sv, - [[maybe_unused]] std::vector &identify_wires, + [[maybe_unused]] std::vector &identity_wires, [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT("For Hamiltonian Observables, the applyInPlace method must be " @@ -590,7 +590,7 @@ class SparseHamiltonianBase : public Observable { void applyInPlaceShots([[maybe_unused]] StateVectorT &sv, - [[maybe_unused]] std::vector &identify_wire, + [[maybe_unused]] std::vector &identity_wire, [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { PL_ABORT( diff --git a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp index 475b9fc423..a233e8dfbc 100644 --- a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp +++ b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp @@ -130,11 +130,11 @@ template void testNamedObsBase() { StateVectorT state_vector(init_state.data(), init_state.size()); auto obs = NamedObsT("RY", {0}, {0.4}); - std::vector identify_wire; + std::vector identity_wire; std::vector ob_wires; REQUIRE_THROWS_WITH( - obs.applyInPlaceShots(state_vector, identify_wire, ob_wires), + obs.applyInPlaceShots(state_vector, identity_wire, ob_wires), Catch::Matchers::Contains( "Provided NamedObs does not supported for shots")); } @@ -215,11 +215,11 @@ template void testHermitianObsBase() { auto obs = HermitianObsT{std::vector{1.0, 0.0, -1.0, 0.0}, {0}}; - std::vector identify_wire; + std::vector identity_wire; std::vector ob_wires; REQUIRE_THROWS_WITH( - obs.applyInPlaceShots(state_vector, identify_wire, ob_wires), + obs.applyInPlaceShots(state_vector, identity_wire, ob_wires), Catch::Matchers::Contains( "For Hermitian Observables, the applyInPlaceShots method " "is not supported.")); @@ -584,11 +584,11 @@ template void testSparseHamiltonianBase() { StateVectorT state_vector(init_state.data(), init_state.size()); - std::vector identify_wire; + std::vector identity_wire; std::vector ob_wires; REQUIRE_THROWS_WITH( - sparseH->applyInPlaceShots(state_vector, identify_wire, + sparseH->applyInPlaceShots(state_vector, identity_wire, ob_wires), Catch::Matchers::Contains("For SparseHamiltonian Observables, " "the applyInPlaceShots method " diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp index 5b08f912ed..b5a6c3deb0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPU.hpp @@ -210,11 +210,11 @@ class Hamiltonian final : public HamiltonianBase { // to work with void applyInPlaceShots(StateVectorT &sv, - std::vector &identify_wires, + std::vector &identity_wires, std::vector &ob_wires, size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + this->obs_[term_idx]->applyInPlaceShots(sv, identity_wires, ob_wires, term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp index 837862a96c..9595783421 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/observables/ObservablesGPUMPI.hpp @@ -217,11 +217,11 @@ class HamiltonianMPI final : public HamiltonianBase { // to work with void applyInPlaceShots(StateVectorT &sv, - std::vector &identify_wires, + std::vector &identity_wires, std::vector &ob_wires, size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + this->obs_[term_idx]->applyInPlaceShots(sv, identity_wires, ob_wires, term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp index c473ae70e2..44357eb9e5 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/observables/ObservablesKokkos.hpp @@ -201,11 +201,11 @@ class Hamiltonian final : public HamiltonianBase { // to work with void applyInPlaceShots(StateVectorT &sv, - std::vector &identify_wires, + std::vector &identity_wires, std::vector &ob_wires, size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + this->obs_[term_idx]->applyInPlaceShots(sv, identity_wires, ob_wires, term_idx); } }; diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp index f96cc82351..ce1aa1cca5 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/observables/ObservablesLQubit.hpp @@ -361,11 +361,11 @@ class Hamiltonian final : public HamiltonianBase { // to work with void applyInPlaceShots(StateVectorT &sv, - std::vector &identify_wires, + std::vector &identity_wires, std::vector &ob_wires, size_t term_idx) const override { ob_wires.clear(); - this->obs_[term_idx]->applyInPlaceShots(sv, identify_wires, ob_wires, + this->obs_[term_idx]->applyInPlaceShots(sv, identity_wires, ob_wires, term_idx); } }; From 06ecd0607964a4d278a99fd9ea8d110d9b5e0ab3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 20:44:12 -0500 Subject: [PATCH 48/76] add MPI Hamiltonian tests for shots --- .../mpi/Test_StateVectorCudaMPI_Expval.cpp | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp index b6fdab8737..0ce00079ce 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp @@ -351,6 +351,56 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs", } } +TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", + "[StateVectorCudaMPI_Expval]", float, double) { + using StateVectorT = StateVectorCudaMPI; + using ComplexT = StateVectorT::ComplexT; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t num_qubits = 3; + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + auto local_init_sv = mpi_manager.scatter(init_state, 0); + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(local_init_sv.data(), local_init_sv.size(), false); + + mpi_manager.Barrier(); + + auto m = MeasurementsMPI(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = HamiltonianMPI::create({0.3, 0.5}, {X0, Z1}); + size_t num_shots = 10000; + std::vector shot_range = {}; + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = TestType(-0.086); + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", "[StateVectorCudaMPI_Expval]", float, double) { using StateVectorT = StateVectorCudaMPI; @@ -397,6 +447,55 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", } } +TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shot", + "[StateVectorCudaMPI_Expval]", float, double) { + using StateVectorT = StateVectorCudaMPI; + using ComplexT = StateVectorT::ComplexT; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t num_qubits = 3; + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + auto local_init_sv = mpi_manager.scatter(init_state, 0); + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(local_init_sv.data(), local_init_sv.size(), false); + + auto m = MeasurementsMPI(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = TensorProdObsMPI::create({X0, Z1}); + size_t num_shots = 10000; + std::vector shot_range = {}; + + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = TestType(-0.36); + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + TEMPLATE_TEST_CASE("StateVectorCudaMPI::Hamiltonian_expval_Sparse", "[StateVectorCudaMPI_Expval]", double) { using StateVectorT = StateVectorCudaMPI; From 602f16cd6564fb6043f4f0285c6d7169bebd4515 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 16 Nov 2023 20:49:12 -0500 Subject: [PATCH 49/76] add HamBase tests for applyInPlaceShots --- .../src/observables/tests/Test_Observables.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp index a233e8dfbc..e1b0f2cb73 100644 --- a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp +++ b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp @@ -495,6 +495,22 @@ template void testHamiltonianBase() { REQUIRE_THROWS_AS(ham->applyInPlace(state_vector), LightningException); } + + DYNAMIC_SECTION("applyInPlaceShots must fail - " + << StateVectorToName::name) { + auto ham = + HamiltonianT::create({PrecisionT{1.0}, h, h}, {zz, x1, x2}); + auto st_data = createZeroState(2); + + StateVectorT state_vector(st_data.data(), st_data.size()); + + std::vector identity_wires; + std::vector ob_wires; + + REQUIRE_THROWS_AS(ham->applyInPlaceShots( + state_vector, identity_wires, ob_wires), + LightningException); + } } testHamiltonianBase(); } From e839cf2cbf79b75f447b731a82ab94e4d4f84c35 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 09:58:52 -0500 Subject: [PATCH 50/76] update based on comments --- .github/CHANGELOG.md | 2 +- .../src/measurements/MeasurementsBase.hpp | 30 +++++++++++-------- .../core/src/observables/Observables.hpp | 9 +++--- .../observables/tests/Test_Observables.cpp | 10 +++---- .../Test_StateVectorCudaManaged_Expval.cpp | 4 +-- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 8796fafb28..e26813ff9b 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add shots support for expectation value calculation for the observables (NamedObs, TensorProd and Hamiltonian) based on Pauli words, Identity and Hadamard in the C++ layer. All Lightning backends have this support now. +* Add shots support for expectation value calculation for given observables (`NamedObs`, `TensorProd` and `Hamiltonian`) based on Pauli words, `Identity` and `Hadamard` in the C++ layer by adding `measure_with_samples` to the measurement interface. All Lightning backends have this support now. [(#556)](https://github.com/PennyLaneAI/pennylane-lightning/pull/556) * `qml.QubitUnitary` operators can be included in a circuit differentiated with the adjoint method. Lightning handles circuits with arbitrary non-differentiable `qml.QubitUnitary` operators. 1,2-qubit `qml.QubitUnitary` operators with differentiable parameters can be differentiated using decomposition. diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 67bee8a965..eed529b0bd 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -127,12 +127,18 @@ template class MeasurementsBase { */ auto expval(const Observable &obs, const size_t &num_shots, const std::vector &shot_range = {}) -> PrecisionT { - PrecisionT result = 0; + PrecisionT result{0.0}; if (obs.getObsName().find("SparseHamiltonian") != std::string::npos) { PL_ABORT("For SparseHamiltonian Observables, expval calculation is " "not supported by shots"); } else if (obs.getObsName().find("Hermitian") != std::string::npos) { + // TODO support. This support requires an additional method to solve + // eigenpair and unitary matrices, and the results of eigenpair and + // unitary matrices data need to be added to the Hermitian class and + // public methods are need to access eigen values. Note the + // assumption that eigen values are -1 and 1 in the + // `measurement_with_sample` method should be updated as well. PL_ABORT("For Hermitian Observables, expval calculation is not " "supported by shots"); } else if (obs.getObsName().find("Hamiltonian") != std::string::npos) { @@ -151,7 +157,7 @@ template class MeasurementsBase { auto obs_samples = measure_with_samples(obs, num_shots, shot_range); result = std::accumulate(obs_samples.begin(), obs_samples.end(), 0.0); - result = result / obs_samples.size(); + result /= obs_samples.size(); } return result; } @@ -178,10 +184,8 @@ template class MeasurementsBase { auto sub_samples = _sample_state(obs, num_shots, shot_range, obs_wires, identity_wires, term_idx); - size_t num_samples = num_shots; - if (!shot_range.empty()) { - num_samples = shot_range.size(); - } + size_t num_samples = shot_range.empty() ? num_shots : shot_range.size(); + std::vector obs_samples(num_samples, 0); size_t num_identity_obs = identity_wires.size(); @@ -207,10 +211,10 @@ template class MeasurementsBase { // eigen values are `1` and `-1` for PauliX, PauliY, PauliZ, // Hadamard gates the eigen value for a eigen vector |00001> is // -1 since sum of the value at each bit position is odd - if ((static_cast(std::accumulate( - local_sample.begin() + num_identity_obs, - local_sample.end(), 0)) & - size_t{1}) == 1) { + size_t bitSum = static_cast( + std::accumulate(local_sample.begin() + num_identity_obs, + local_sample.end(), 0)); + if ((bitSum & size_t{1}) == 1) { obs_samples[i] = -1; } else { obs_samples[i] = 1; @@ -230,7 +234,8 @@ template class MeasurementsBase { * @param obs The observable to sample * @param obs_wires Observable wires. * @param identity_wires Wires of Identity gates - * @param term_idx Index of a Hamiltonian term + * @param term_idx Index of a Hamiltonian term. For other observables, its + * value is 0, which is set as default. * * @return a StateVectorT object */ @@ -261,7 +266,8 @@ template class MeasurementsBase { * default. * @param obs_wires Observable wires. * @param identity_wires Wires of Identity gates - * @param term_idx Index of a Hamiltonian term + * @param term_idx Index of a Hamiltonian term. For other observables, its + * value is 0, which is set as default. * * @return std::vector samples in std::vector */ diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 94948c03fa..45d8aedf4a 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -247,8 +247,8 @@ class HermitianObsBase : public Observable { [[maybe_unused]] std::vector &identity_wire, [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { - PL_ABORT("For Hermitian Observables, the applyInPlaceShots method is " - "not supported."); + PL_ABORT("Hermitian observables do not support applyInPlaceShots " + "method."); } }; @@ -593,9 +593,8 @@ class SparseHamiltonianBase : public Observable { [[maybe_unused]] std::vector &identity_wire, [[maybe_unused]] std::vector &ob_wires, [[maybe_unused]] size_t term_idx = 0) const override { - PL_ABORT( - "For SparseHamiltonian Observables, the applyInPlaceShots method " - "is not supported."); + PL_ABORT("SparseHamiltonian observables do not the applyInPlaceShots " + "method."); } [[nodiscard]] auto getObsName() const -> std::string override { diff --git a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp index e1b0f2cb73..c928fba3d4 100644 --- a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp +++ b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp @@ -220,9 +220,8 @@ template void testHermitianObsBase() { REQUIRE_THROWS_WITH( obs.applyInPlaceShots(state_vector, identity_wire, ob_wires), - Catch::Matchers::Contains( - "For Hermitian Observables, the applyInPlaceShots method " - "is not supported.")); + Catch::Matchers::Contains("Hermitian observables do not " + "support applyInPlaceShots method.")); } testHermitianObsBase(); @@ -606,9 +605,8 @@ template void testSparseHamiltonianBase() { REQUIRE_THROWS_WITH( sparseH->applyInPlaceShots(state_vector, identity_wire, ob_wires), - Catch::Matchers::Contains("For SparseHamiltonian Observables, " - "the applyInPlaceShots method " - "is not supported.")); + Catch::Matchers::Contains("SparseHamiltonian observables do " + "not the applyInPlaceShots method.")); } testSparseHamiltonianBase(); diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp index e5bd7dce79..026d0c0a03 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp @@ -398,13 +398,13 @@ TEMPLATE_TEST_CASE( auto X0 = std::make_shared>( "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( + auto I1 = std::make_shared>( "Identity", std::vector{1}); size_t num_shots = 10000; std::vector shot_range = {}; - auto ob = TensorProdObs::create({X0, Z1}); + auto ob = TensorProdObs::create({X0, I1}); auto res_shots = m.expval(*ob, num_shots, shot_range); auto expected = m.expval(*ob); From 740881395ddfdcbbf9e9adacb284774bd054ed4f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 10:16:01 -0500 Subject: [PATCH 51/76] add more unit tests --- .../src/measurements/MeasurementsBase.hpp | 1 + .../mpi/Test_StateVectorCudaMPI_Expval.cpp | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index eed529b0bd..879377b3d7 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -130,6 +130,7 @@ template class MeasurementsBase { PrecisionT result{0.0}; if (obs.getObsName().find("SparseHamiltonian") != std::string::npos) { + // SparseHamiltonian does not support samples in pennylane. PL_ABORT("For SparseHamiltonian Observables, expval calculation is " "not supported by shots"); } else if (obs.getObsName().find("Hermitian") != std::string::npos) { diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp index 0ce00079ce..7f67d5633f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp @@ -496,6 +496,56 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shot", } } +TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots with Identity", + "[StateVectorCudaMPI_Expval]", float, double) { + using StateVectorT = StateVectorCudaMPI; + using ComplexT = StateVectorT::ComplexT; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t num_qubits = 3; + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + SECTION("Using expval") { + std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, + {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, + {0.3, 0.4}, {0.4, 0.5}}; + auto local_init_sv = mpi_manager.scatter(init_state, 0); + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(local_init_sv.data(), local_init_sv.size(), false); + + auto m = MeasurementsMPI(sv); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + + auto ob = TensorProdObsMPI::create({X0, I1}); + size_t num_shots = 10000; + std::vector shot_range = {}; + + auto res = m.expval(*ob, num_shots, shot_range); + auto expected = m.expval(*ob); + REQUIRE(expected == Approx(res).margin(5e-2)); + } +} + + TEMPLATE_TEST_CASE("StateVectorCudaMPI::Hamiltonian_expval_Sparse", "[StateVectorCudaMPI_Expval]", double) { using StateVectorT = StateVectorCudaMPI; From 00be785da4a1cc8c2ae3f59f088779b19163c980 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 10:46:59 -0500 Subject: [PATCH 52/76] move tests for non-distributed backends to base --- .../tests/Test_MeasurementsBase.cpp | 148 +++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 2bd7232eaf..9e5e13c4d0 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -187,7 +187,7 @@ template void testNamedObsExpval() { } } -TEST_CASE("Expval Shot - NamedObs", "[MeasurementsBase][Observables]") { +TEST_CASE("Expval - NamedObs", "[MeasurementsBase][Observables]") { if constexpr (BACKEND_FOUND) { testNamedObsExpval(); } @@ -387,6 +387,95 @@ TEST_CASE("Expval - HermitianObs", "[MeasurementsBase][Observables]") { } } +template void testTensorProdObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = StateVectorT::ComplexT; + + // Defining the State Vector that will be measured. + std::vector statevector_data{ + {0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, {0.1, 0.2}, + {0.2, 0.2}, {0.3, 0.3}, {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + DYNAMIC_SECTION(" - Without shots_range" + << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = TensorProdObs::create({X0, Z1}); + PrecisionT expected = PrecisionT(-0.36); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" - With Identity but no shots_range" + << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = TensorProdObs::create({X0, I1}); + PrecisionT expected = Measurer.expval(*obs); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With shots_range" + << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = TensorProdObs::create({X0, Z1}); + PrecisionT expected = PrecisionT(-0.36); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With Identity and shots_range" + << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = TensorProdObs::create({X0, I1}); + PrecisionT expected = Measurer.expval(*obs); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + testTensorProdObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot- TensorProdObs", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testTensorProdObsExpvalShot(); + } +} + template void testNamedObsVar() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; @@ -575,6 +664,63 @@ TEST_CASE("Samples", "[MeasurementsBase]") { } } +template void testHamiltonianObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = typename StateVectorT::ComplexT; + + // Defining the State Vector that will be measured. + std::vector statevector_data{ + {0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, {0.1, 0.2}, + {0.2, 0.2}, {0.3, 0.3}, {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); + + DYNAMIC_SECTION("Without shots_range " + << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + + auto res = Measurer.expval(*ob, num_shots, shots_range); + auto expected = PrecisionT(-0.086); + REQUIRE(expected == Approx(res).margin(5e-2)); + } + + DYNAMIC_SECTION("With shots_range " + << StateVectorToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } + + auto res = Measurer.expval(*ob, num_shots, shots_range); + auto expected = PrecisionT(-0.086); + REQUIRE(expected == Approx(res).margin(5e-2)); + } + + testHamiltonianObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot - HamiltonianObs ", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testHamiltonianObsExpvalShot(); + } +} + template void testSparseHObsExpvalShot() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; From 6c4dfbd9e515c1b96681a5ef7d8fa48f7957f802 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 16:32:55 +0000 Subject: [PATCH 53/76] move all unit tests into the base class --- .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 228 ++++++++++++++++++ .../Test_StateVectorCudaManaged_Expval.cpp | 6 +- .../mpi/Test_StateVectorCudaMPI_Expval.cpp | 10 +- .../tests/Test_StateVectorKokkos_Expval.cpp | 4 +- .../tests/Test_MeasurementsLQubit.cpp | 3 +- 5 files changed, 242 insertions(+), 9 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index af2f90477e..cce10132cd 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -365,6 +365,234 @@ TEST_CASE("Expval - HermitianObs", "[MeasurementsBase][Observables]") { } } +template void testTensorProdObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using ComplexT = typename StateVectorT::ComplexT; + using PrecisionT = typename StateVectorT::PrecisionT; + + // Defining the State Vector that will be measured. + std::vector statevector_data{ + {0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, {0.1, 0.2}, + {0.2, 0.2}, {0.3, 0.3}, {0.3, 0.4}, {0.4, 0.5}}; + + size_t num_qubits = 3; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + auto sv_data_local = mpi_manager.scatter(statevector_data, 0); + + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + // Initializing the measurements class. + // This object attaches to the statevector allowing several measures. + MeasurementsMPI Measurer(sv); + + DYNAMIC_SECTION(" - Without shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = TensorProdObsMPI::create({X0, Z1}); + PrecisionT expected = PrecisionT(-0.36); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" - With Identity but no shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = TensorProdObsMPI::create({X0, I1}); + PrecisionT expected = Measurer.expval(*obs); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = TensorProdObsMPI::create({X0, Z1}); + PrecisionT expected = PrecisionT(-0.36); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With Identity and shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = TensorProdObsMPI::create({X0, I1}); + PrecisionT expected = Measurer.expval(*obs); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + testTensorProdObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot- TensorProdObs", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testTensorProdObsExpvalShot(); + } +} + +template void testHamiltonianObsExpvalShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using ComplexT = typename StateVectorT::ComplexT; + using PrecisionT = typename StateVectorT::PrecisionT; + + // Defining the State Vector that will be measured. + std::vector statevector_data{ + {0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, {0.1, 0.2}, + {0.2, 0.2}, {0.3, 0.3}, {0.3, 0.4}, {0.4, 0.5}}; + + size_t num_qubits = 3; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + auto sv_data_local = mpi_manager.scatter(statevector_data, 0); + + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + // Initializing the measurements class. + // This object attaches to the statevector allowing several measures. + MeasurementsMPI Measurer(sv); + + DYNAMIC_SECTION(" - Without shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = + HamiltonianMPI::create({0.3, 0.5}, {X0, Z1}); + PrecisionT expected = PrecisionT(-0.086); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" - With Identity but no shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range = {}; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = + HamiltonianMPI::create({0.3, 0.5}, {X0, I1}); + PrecisionT expected = Measurer.expval(*obs); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = + HamiltonianMPI::create({0.3, 0.5}, {X0, Z1}); + PrecisionT expected = PrecisionT(-0.086); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With Identity and shots_range" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + std::vector shots_range; + for (size_t i = 0; i < num_shots; i += 2) { + shots_range.push_back(i); + } + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = + HamiltonianMPI::create({0.3, 0.5}, {X0, I1}); + PrecisionT expected = Measurer.expval(*obs); + PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + testHamiltonianObsExpvalShot(); + } +} + +TEST_CASE("Expval Shot- HamiltonianObs", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testHamiltonianObsExpvalShot(); + } +} + template void testNamedObsVar() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp index 026d0c0a03..01688cc5d2 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp @@ -308,7 +308,7 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs", CHECK(expected == Approx(res)); } } - +/* TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", "[StateVectorCudaManaged_Expval]", float, double) { using StateVectorT = StateVectorCudaManaged; @@ -333,6 +333,7 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", REQUIRE(expected == Approx(res).margin(5e-2)); } } +*/ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", "[StateVectorCudaManaged_Expval]", float, double) { @@ -356,7 +357,7 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", CHECK(expected == Approx(res)); } } - +/* TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots", "[StateVectorCudaManaged_Expval]", float, double) { using StateVectorT = StateVectorCudaManaged; @@ -411,6 +412,7 @@ TEMPLATE_TEST_CASE( REQUIRE(expected == Approx(res_shots).margin(5e-2)); } } +*/ TEMPLATE_TEST_CASE("StateVectorCudaManaged::Hamiltonian_expval_Sparse", "[StateVectorCudaManaged_Expval]", float, double) { diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp index 7f67d5633f..0970095ac0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp @@ -350,7 +350,7 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs", CHECK(expected == Approx(res)); } } - +/* TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", "[StateVectorCudaMPI_Expval]", float, double) { using StateVectorT = StateVectorCudaMPI; @@ -400,6 +400,7 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", REQUIRE(expected == Approx(res).margin(5e-2)); } } +*/ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", "[StateVectorCudaMPI_Expval]", float, double) { @@ -446,7 +447,7 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", CHECK(expected == Approx(res)); } } - +/* TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shot", "[StateVectorCudaMPI_Expval]", float, double) { using StateVectorT = StateVectorCudaMPI; @@ -496,7 +497,8 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shot", } } -TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots with Identity", +TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots with +Identity", "[StateVectorCudaMPI_Expval]", float, double) { using StateVectorT = StateVectorCudaMPI; using ComplexT = StateVectorT::ComplexT; @@ -544,7 +546,7 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots with Identity" REQUIRE(expected == Approx(res).margin(5e-2)); } } - +*/ TEMPLATE_TEST_CASE("StateVectorCudaMPI::Hamiltonian_expval_Sparse", "[StateVectorCudaMPI_Expval]", double) { diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp index 7a9891e399..e02e8b8692 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp @@ -380,7 +380,7 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", CHECK(expected == Approx(res)); } } - +/* TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots", "[StateVectorKokkos_Expval]", float, double) { using StateVectorT = StateVectorKokkos; @@ -434,7 +434,7 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", REQUIRE(expected == Approx(res).margin(5e-2)); } } - +*/ TEMPLATE_TEST_CASE("Test expectation value of NQubit Hermitian", "[StateVectorKokkos_Expval]", float, double) { using ComplexT = StateVectorKokkos::ComplexT; diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 2d3116c65d..76967f9702 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -118,7 +118,7 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(1e-6)); } } - +/* TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of TensorProdObs shots", "[StateVectorLQubit_Expval]", (StateVectorLQubitManaged, StateVectorLQubitRaw), @@ -176,6 +176,7 @@ TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of HamiltonianObs shot", REQUIRE(expected == Approx(res).margin(5e-2)); } } +*/ TEMPLATE_PRODUCT_TEST_CASE("Variances", "[Measurements]", (StateVectorLQubitManaged, StateVectorLQubitRaw), From 0d07d9c85e7036a7dbd1e9d62ceb0da36ecd03ec Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 17:22:23 +0000 Subject: [PATCH 54/76] move getTotalNumQubits to base and tidy up code --- .../tests/Test_MeasurementsBase.cpp | 8 +- .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 8 +- .../src/simulators/base/StateVectorBase.hpp | 9 ++ .../lightning_gpu/StateVectorCudaManaged.hpp | 7 - .../Test_StateVectorCudaManaged_Expval.cpp | 82 ---------- .../mpi/Test_StateVectorCudaMPI_Expval.cpp | 151 ------------------ .../lightning_kokkos/StateVectorKokkos.hpp | 5 - .../tests/Test_StateVectorKokkos_Expval.cpp | 54 ------- .../StateVectorLQubitManaged.hpp | 7 - .../lightning_qubit/StateVectorLQubitRaw.hpp | 7 - .../tests/Test_MeasurementsLQubit.cpp | 59 ------- 11 files changed, 17 insertions(+), 380 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 9e5e13c4d0..2f6d8adce8 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -413,8 +413,8 @@ template void testTensorProdObsExpvalShot() { auto Z1 = std::make_shared>( "PauliZ", std::vector{1}); auto obs = TensorProdObs::create({X0, Z1}); - PrecisionT expected = PrecisionT(-0.36); - PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + auto expected = PrecisionT(-0.36); + auto result = Measurer.expval(*obs, num_shots, shots_range); REQUIRE(expected == Approx(result).margin(5e-2)); } @@ -444,8 +444,8 @@ template void testTensorProdObsExpvalShot() { auto Z1 = std::make_shared>( "PauliZ", std::vector{1}); auto obs = TensorProdObs::create({X0, Z1}); - PrecisionT expected = PrecisionT(-0.36); - PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + auto expected = PrecisionT(-0.36); + auto result = Measurer.expval(*obs, num_shots, shots_range); REQUIRE(expected == Approx(result).margin(5e-2)); } diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index cce10132cd..7996c029c8 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -414,8 +414,8 @@ template void testTensorProdObsExpvalShot() { auto Z1 = std::make_shared>( "PauliZ", std::vector{1}); auto obs = TensorProdObsMPI::create({X0, Z1}); - PrecisionT expected = PrecisionT(-0.36); - PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + auto expected = PrecisionT(-0.36); + auto result = Measurer.expval(*obs, num_shots, shots_range); REQUIRE(expected == Approx(result).margin(5e-2)); } @@ -445,8 +445,8 @@ template void testTensorProdObsExpvalShot() { auto Z1 = std::make_shared>( "PauliZ", std::vector{1}); auto obs = TensorProdObsMPI::create({X0, Z1}); - PrecisionT expected = PrecisionT(-0.36); - PrecisionT result = Measurer.expval(*obs, num_shots, shots_range); + auto expected = PrecisionT(-0.36); + auto result = Measurer.expval(*obs, num_shots, shots_range); REQUIRE(expected == Approx(result).margin(5e-2)); } diff --git a/pennylane_lightning/core/src/simulators/base/StateVectorBase.hpp b/pennylane_lightning/core/src/simulators/base/StateVectorBase.hpp index 727447f8e6..0baa89d0ae 100644 --- a/pennylane_lightning/core/src/simulators/base/StateVectorBase.hpp +++ b/pennylane_lightning/core/src/simulators/base/StateVectorBase.hpp @@ -66,6 +66,15 @@ template class StateVectorBase { return num_qubits_; } + /** + * @brief Get the total number of qubits of the simulated system. + * + * @return std::size_t + */ + [[nodiscard]] auto getTotalNumQubits() const -> size_t { + return num_qubits_; + } + /** * @brief Get the size of the statevector * diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp index ed7d77472d..7f1fac2652 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp @@ -144,13 +144,6 @@ class StateVectorCudaManaged ~StateVectorCudaManaged() = default; - /** - * @brief Get the total number of wires. - */ - auto getTotalNumQubits() const -> size_t { - return BaseType::getNumQubits(); - } - /** * @brief Set value for a single element of the state-vector on device. This * method is implemented by cudaMemcpy. diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp index 01688cc5d2..36f1f1f128 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/Test_StateVectorCudaManaged_Expval.cpp @@ -308,32 +308,6 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs", CHECK(expected == Approx(res)); } } -/* -TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", - "[StateVectorCudaManaged_Expval]", float, double) { - using StateVectorT = StateVectorCudaManaged; - using ComplexT = StateVectorT::ComplexT; - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - StateVectorT sv{init_state.data(), init_state.size()}; - auto m = Measurements(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - - auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); - size_t num_shots = 10000; - std::vector shot_range = {}; - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = TestType(-0.086); - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} -*/ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", "[StateVectorCudaManaged_Expval]", float, double) { @@ -357,62 +331,6 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", CHECK(expected == Approx(res)); } } -/* -TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots", - "[StateVectorCudaManaged_Expval]", float, double) { - using StateVectorT = StateVectorCudaManaged; - using ComplexT = StateVectorT::ComplexT; - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - StateVectorT sv{init_state.data(), init_state.size()}; - auto m = Measurements(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - - size_t num_shots = 10000; - std::vector shot_range = {}; - - auto ob = TensorProdObs::create({X0, Z1}); - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = TestType(-0.36); - - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} - -TEMPLATE_TEST_CASE( - "Test expectation value of TensorProdObs shots with Identity", - "[StateVectorCudaManaged_Expval]", float, double) { - using StateVectorT = StateVectorCudaManaged; - using ComplexT = StateVectorT::ComplexT; - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - StateVectorT sv{init_state.data(), init_state.size()}; - auto m = Measurements(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto I1 = std::make_shared>( - "Identity", std::vector{1}); - - size_t num_shots = 10000; - std::vector shot_range = {}; - - auto ob = TensorProdObs::create({X0, I1}); - auto res_shots = m.expval(*ob, num_shots, shot_range); - auto expected = m.expval(*ob); - - REQUIRE(expected == Approx(res_shots).margin(5e-2)); - } -} -*/ TEMPLATE_TEST_CASE("StateVectorCudaManaged::Hamiltonian_expval_Sparse", "[StateVectorCudaManaged_Expval]", float, double) { diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp index 0970095ac0..b6fdab8737 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/tests/mpi/Test_StateVectorCudaMPI_Expval.cpp @@ -350,57 +350,6 @@ TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs", CHECK(expected == Approx(res)); } } -/* -TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", - "[StateVectorCudaMPI_Expval]", float, double) { - using StateVectorT = StateVectorCudaMPI; - using ComplexT = StateVectorT::ComplexT; - - MPIManager mpi_manager(MPI_COMM_WORLD); - REQUIRE(mpi_manager.getSize() == 2); - - size_t num_qubits = 3; - size_t mpi_buffersize = 1; - - size_t nGlobalIndexBits = - std::bit_width(static_cast(mpi_manager.getSize())) - 1; - size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; - - int nDevices = 0; - cudaGetDeviceCount(&nDevices); - REQUIRE(nDevices >= 2); - int deviceId = mpi_manager.getRank() % nDevices; - cudaSetDevice(deviceId); - DevTag dt_local(deviceId, 0); - mpi_manager.Barrier(); - - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - auto local_init_sv = mpi_manager.scatter(init_state, 0); - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(local_init_sv.data(), local_init_sv.size(), false); - - mpi_manager.Barrier(); - - auto m = MeasurementsMPI(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - - auto ob = HamiltonianMPI::create({0.3, 0.5}, {X0, Z1}); - size_t num_shots = 10000; - std::vector shot_range = {}; - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = TestType(-0.086); - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} -*/ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", "[StateVectorCudaMPI_Expval]", float, double) { @@ -447,106 +396,6 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", CHECK(expected == Approx(res)); } } -/* -TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shot", - "[StateVectorCudaMPI_Expval]", float, double) { - using StateVectorT = StateVectorCudaMPI; - using ComplexT = StateVectorT::ComplexT; - - MPIManager mpi_manager(MPI_COMM_WORLD); - REQUIRE(mpi_manager.getSize() == 2); - - size_t num_qubits = 3; - size_t mpi_buffersize = 1; - - size_t nGlobalIndexBits = - std::bit_width(static_cast(mpi_manager.getSize())) - 1; - size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; - - int nDevices = 0; - cudaGetDeviceCount(&nDevices); - REQUIRE(nDevices >= 2); - int deviceId = mpi_manager.getRank() % nDevices; - cudaSetDevice(deviceId); - DevTag dt_local(deviceId, 0); - mpi_manager.Barrier(); - - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - auto local_init_sv = mpi_manager.scatter(init_state, 0); - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(local_init_sv.data(), local_init_sv.size(), false); - - auto m = MeasurementsMPI(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - - auto ob = TensorProdObsMPI::create({X0, Z1}); - size_t num_shots = 10000; - std::vector shot_range = {}; - - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = TestType(-0.36); - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} - -TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots with -Identity", - "[StateVectorCudaMPI_Expval]", float, double) { - using StateVectorT = StateVectorCudaMPI; - using ComplexT = StateVectorT::ComplexT; - - MPIManager mpi_manager(MPI_COMM_WORLD); - REQUIRE(mpi_manager.getSize() == 2); - - size_t num_qubits = 3; - size_t mpi_buffersize = 1; - - size_t nGlobalIndexBits = - std::bit_width(static_cast(mpi_manager.getSize())) - 1; - size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; - - int nDevices = 0; - cudaGetDeviceCount(&nDevices); - REQUIRE(nDevices >= 2); - int deviceId = mpi_manager.getRank() % nDevices; - cudaSetDevice(deviceId); - DevTag dt_local(deviceId, 0); - mpi_manager.Barrier(); - - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - auto local_init_sv = mpi_manager.scatter(init_state, 0); - StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, - nLocalIndexBits); - sv.CopyHostDataToGpu(local_init_sv.data(), local_init_sv.size(), false); - - auto m = MeasurementsMPI(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto I1 = std::make_shared>( - "Identity", std::vector{1}); - - auto ob = TensorProdObsMPI::create({X0, I1}); - size_t num_shots = 10000; - std::vector shot_range = {}; - - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = m.expval(*ob); - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} -*/ TEMPLATE_TEST_CASE("StateVectorCudaMPI::Hamiltonian_expval_Sparse", "[StateVectorCudaMPI_Expval]", double) { diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp index 8dedce9c39..f33d3a8730 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/StateVectorKokkos.hpp @@ -115,11 +115,6 @@ class StateVectorKokkos final init_generators_indices_(); }; - /** - * @brief Get the total number of wires. - */ - auto getTotalNumQubits() const -> size_t { return this->getNumQubits(); } - /** * @brief Init zeros for the state-vector on device. */ diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp index e02e8b8692..63204a5109 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/tests/Test_StateVectorKokkos_Expval.cpp @@ -380,61 +380,7 @@ TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs", CHECK(expected == Approx(res)); } } -/* -TEMPLATE_TEST_CASE("Test expectation value of TensorProdObs shots", - "[StateVectorKokkos_Expval]", float, double) { - using StateVectorT = StateVectorKokkos; - using PrecisionT = typename StateVectorT::PrecisionT; - using ComplexT = StateVectorT::ComplexT; - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - StateVectorT sv{init_state.data(), init_state.size()}; - auto m = Measurements(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - - size_t num_shots = 10000; - std::vector shot_range = {}; - - auto ob = TensorProdObs::create({X0, Z1}); - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = PrecisionT(-0.36); - - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} - -TEMPLATE_TEST_CASE("Test expectation value of HamiltonianObs shot", - "[StateVectorKokkos_Expval]", float, double) { - using StateVectorT = StateVectorKokkos; - using PrecisionT = typename StateVectorT::PrecisionT; - using ComplexT = StateVectorT::ComplexT; - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - StateVectorT sv{init_state.data(), init_state.size()}; - auto m = Measurements(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); - size_t num_shots = 10000; - std::vector shot_range = {}; - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = PrecisionT(-0.086); - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} -*/ TEMPLATE_TEST_CASE("Test expectation value of NQubit Hermitian", "[StateVectorKokkos_Expval]", float, double) { using ComplexT = StateVectorKokkos::ComplexT; diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp index f31890240d..add76efeb0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp @@ -139,13 +139,6 @@ class StateVectorLQubitManaged final ~StateVectorLQubitManaged() = default; - /** - * @brief Get the total number of wires. - */ - [[nodiscard]] auto getTotalNumQubits() const -> size_t { - return log2PerfectPower(data_.size()); - } - [[nodiscard]] auto getData() -> ComplexT * { return data_.data(); } [[nodiscard]] auto getData() const -> const ComplexT * { diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp index e5eeac87fc..167a0b22f1 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitRaw.hpp @@ -86,13 +86,6 @@ class StateVectorLQubitRaw final "The size of provided data must be a power of 2."); } - /** - * @brief Get the total number of wires. - */ - [[nodiscard]] auto getTotalNumQubits() const -> size_t { - return log2PerfectPower(length_); - } - /** * @brief Get the underlying data pointer. * diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 76967f9702..a30dbd38e9 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -118,65 +118,6 @@ TEMPLATE_PRODUCT_TEST_CASE("Expected Values", "[Measurements]", REQUIRE_THAT(exp_values, Catch::Approx(exp_values_ref).margin(1e-6)); } } -/* -TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of TensorProdObs shots", - "[StateVectorLQubit_Expval]", - (StateVectorLQubitManaged, StateVectorLQubitRaw), - (float, double)) { - using StateVectorT = TestType; - using PrecisionT = typename StateVectorT::PrecisionT; - using ComplexT = StateVectorT::ComplexT; - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - StateVectorT sv{init_state.data(), init_state.size()}; - auto m = Measurements(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - - size_t num_shots = 1000; - std::vector shot_range = {}; - - auto ob = TensorProdObs::create({X0, Z1}); - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = PrecisionT(-0.36); - - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} - -TEMPLATE_PRODUCT_TEST_CASE("Test expectation value of HamiltonianObs shot", - "[StateVectorLQubit_Expval]", - (StateVectorLQubitManaged, StateVectorLQubitRaw), - (float, double)) { - using StateVectorT = TestType; - using PrecisionT = typename StateVectorT::PrecisionT; - using ComplexT = StateVectorT::ComplexT; - SECTION("Using expval") { - std::vector init_state{{0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, - {0.1, 0.2}, {0.2, 0.2}, {0.3, 0.3}, - {0.3, 0.4}, {0.4, 0.5}}; - StateVectorT sv{init_state.data(), init_state.size()}; - auto m = Measurements(sv); - - auto X0 = std::make_shared>( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared>( - "PauliZ", std::vector{1}); - - auto ob = Hamiltonian::create({0.3, 0.5}, {X0, Z1}); - size_t num_shots = 1000; - std::vector shot_range = {}; - auto res = m.expval(*ob, num_shots, shot_range); - auto expected = PrecisionT(-0.086); - REQUIRE(expected == Approx(res).margin(5e-2)); - } -} -*/ TEMPLATE_PRODUCT_TEST_CASE("Variances", "[Measurements]", (StateVectorLQubitManaged, StateVectorLQubitRaw), From 055d6b306148105ca9469cc5c1e9276d6517900e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 17:26:53 +0000 Subject: [PATCH 55/76] tidy up code --- .../lightning_qubit/measurements/MeasurementsLQubit.hpp | 2 +- .../lightning_qubit/measurements/tests/CMakeLists.txt | 1 - .../measurements/tests/Test_MeasurementsLQubit.cpp | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) 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 e58f369251..e4571a6b59 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -271,7 +271,7 @@ class Measurements final /** * @brief Expectation value for a Observable with shots * - * @param ob Observable + * @param obs Observable * @param shots Vector of shot number to measurement * @return Floating point expected value of the observable. */ diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt index 79b3b18e8a..1ea6861b8a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/CMakeLists.txt @@ -18,7 +18,6 @@ add_library(lightning_qubit_measurements_tests INTERFACE) target_link_libraries(lightning_qubit_measurements_tests INTERFACE Catch2::Catch2 lightning_measurements lightning_qubit_measurements - lightning_qubit_observables ) ProcessTestOptions(lightning_qubit_measurements_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index a30dbd38e9..35e7280be1 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -20,7 +20,6 @@ #include #include "MeasurementsLQubit.hpp" -#include "ObservablesLQubit.hpp" #include "StateVectorLQubitManaged.hpp" #include "StateVectorLQubitRaw.hpp" #include "Util.hpp" @@ -32,11 +31,9 @@ /// @cond DEV namespace { using namespace Pennylane::Util; -using namespace Pennylane::Observables; using namespace Pennylane::LightningQubit; using namespace Pennylane::LightningQubit::Measures; -using namespace Pennylane::LightningQubit::Observables; }; // namespace /// @endcond From 1a92ebf72f3f653ceded158805157831d7578545 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 17:27:52 +0000 Subject: [PATCH 56/76] revert changes in Test_MeasurementLQ --- .../measurements/tests/Test_MeasurementsLQubit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp index 35e7280be1..b4be45e99a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/tests/Test_MeasurementsLQubit.cpp @@ -34,6 +34,7 @@ using namespace Pennylane::Util; using namespace Pennylane::LightningQubit; using namespace Pennylane::LightningQubit::Measures; + }; // namespace /// @endcond From 2c2971396e6ef08dbccf263e1ddd8ffd6be6511a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 15:41:24 -0500 Subject: [PATCH 57/76] initial commit --- .../src/measurements/MeasurementsBase.hpp | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 879377b3d7..4de02451a2 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -27,6 +27,15 @@ /// @cond DEV namespace { using namespace Pennylane::Observables; + +auto sample_to_str(std::vector &sample) -> std::string { + std::string str; + for (auto &element : sample) { + str += std::to_string(element); + } + return str; +} + } // namespace /// @endcond @@ -228,6 +237,151 @@ template class MeasurementsBase { return obs_samples; } + /** + * @brief Probability of each computational basis state for an observable. + * + * @param obs An observable object. + * @param num_shots Number of shots used to generate samples + * + * @return Floating point std::vector with probabilities. + * The basis columns are rearranged according to wires. + */ + auto var(const Observable &obs, const size_t &num_shots) { + auto square_mean = expval(obs, num_shots, {}); + square_mean *= square_mean; + + PrecisionT mean_square; + + if (obs.getObsName().find("Hamiltonian") == std::string::npos) { + mean_square = 1; + } /*else{ + //Need to verify for Hamiltonian + auto coeffs = obs.getCoeffs(); + } + */ + return mean_square - square_mean; + } + + /** + * @brief Probability of each computational basis state for an observable. + * + * @param obs An observable object. + * @param num_shots Number of shots used to generate samples + * + * @return Floating point std::vector with probabilities. + * The basis columns are rearranged according to wires. + */ + auto probs(const Observable &obs) { + PL_ABORT_IF( + obs.getObsName().find("Hamiltonian") != std::string::npos, + "Hamiltonian and Sparse Hamiltonian do not support samples()."); + std::vector obs_wires; + std::vector identity_wires; + auto sv = _preprocess_state(obs, obs_wires, identity_wires); + Derived measure(sv); + return measure.probs(obs_wires); + } + + /** + * @brief Return samples of a observable + * + * @param obs The observable to sample + * @param num_shots Number of shots used to generate samples + * + * @return std::vector samples in std::vector + */ + auto sample(const Observable &obs, const size_t &num_shots) { + PL_ABORT_IF( + obs.getObsName().find("Hamiltonian") != std::string::npos, + "Hamiltonian and Sparse Hamiltonian do not support samples()."); + std::vector obs_wires; + std::vector identity_wires; + std::vector shot_range = {}; + return _sample_state(obs, num_shots, shot_range, obs_wires, + identity_wires); + } + + /** + * @brief Return generated samples + * + * @param num_shots Number of shots used to generate samples + * + * @return std::vector samples in std::vector + */ + auto sample(const size_t &num_shots) { + PL_ABORT_IF( + obs.getObsName().find("Hamiltonian") != std::string::npos, + "Hamiltonian and Sparse Hamiltonian do not support samples()."); + std::vector obs_wires; + std::vector identity_wires; + std::vector shot_range = {}; + Derived measure(_statevector); + return measure.generate_samples(num_shots); + } + + /** + * @brief Groups the samples into a dictionary showing number of occurences + * for each possible outcome. + * + * @param obs The observable to sample + * @param num_shots number of wires the sampled observable was performed on + * + * @return std::unordered_map with format ``{'outcome': + * num_occurences}`` + */ + auto counts(const Observable &obs, const size_t &num_shots) + -> std::unordered_map { + std::unordered_map outcome_map; + std::vector shot_range = {}; + auto sample_data = sample(obs, num_shots, shot_range); + size_t num_obs_wires = obs.getWires(); + for (size_t i = 0; i < num_shots; i++) { + auto local_sample = + std::vector(samples.begin() + i * num_obs_wires, + samples.begin() + (i + 1) * num_obs_wires - 1); + std::string key = sample_to_str(local_sample); + auto it = outcome_map.find(key); + if (it != outcome_map.end()) { + it->second += 1; + } else { + outcome_map[key] = 1; + } + } + return outcome_map; + } + + /** + * @brief Groups the samples into a dictionary showing number of occurences + * for each possible outcome. + * + * @param num_shots number of wires the sampled observable was performed on + * + * @return std::unordered_map with format ``{'outcome': + * num_occurences}`` + */ + auto counts(const size_t &num_shots) + -> std::unordered_map { + std::unordered_map outcome_map; + + Derived measure(_statevector); + auto sample_data = measure.generate_samples(num_shots); + + size_t num_obs_wires = obs.getWires(); + for (size_t i = 0; i < num_shots; i++) { + auto local_sample = + std::vector(samples.begin() + i * num_obs_wires, + samples.begin() + (i + 1) * num_obs_wires - 1); + std::string key = sample_to_str(local_sample); + auto it = outcome_map.find(key); + if (it != outcome_map.end()) { + it->second += 1; + } else { + outcome_map[key] = 1; + } + } + return outcome_map; + } + private: /** * @brief Return preprocess state with a observable From 42ab1cc2b43d598d347a13f4ec1da8b8924a7af8 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 17:30:47 -0500 Subject: [PATCH 58/76] tidy up code --- .../core/src/measurements/MeasurementsBase.hpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 4de02451a2..6be31ac0e3 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -35,7 +35,6 @@ auto sample_to_str(std::vector &sample) -> std::string { } return str; } - } // namespace /// @endcond @@ -309,12 +308,6 @@ template class MeasurementsBase { * @return std::vector samples in std::vector */ auto sample(const size_t &num_shots) { - PL_ABORT_IF( - obs.getObsName().find("Hamiltonian") != std::string::npos, - "Hamiltonian and Sparse Hamiltonian do not support samples()."); - std::vector obs_wires; - std::vector identity_wires; - std::vector shot_range = {}; Derived measure(_statevector); return measure.generate_samples(num_shots); } @@ -337,8 +330,8 @@ template class MeasurementsBase { size_t num_obs_wires = obs.getWires(); for (size_t i = 0; i < num_shots; i++) { auto local_sample = - std::vector(samples.begin() + i * num_obs_wires, - samples.begin() + (i + 1) * num_obs_wires - 1); + std::vector(sample_data.begin() + i * num_obs_wires, + sample_data.begin() + (i + 1) * num_obs_wires - 1); std::string key = sample_to_str(local_sample); auto it = outcome_map.find(key); if (it != outcome_map.end()) { @@ -366,11 +359,11 @@ template class MeasurementsBase { Derived measure(_statevector); auto sample_data = measure.generate_samples(num_shots); - size_t num_obs_wires = obs.getWires(); + size_t num_wires = _statevector.getTotalNumQubits(); for (size_t i = 0; i < num_shots; i++) { auto local_sample = - std::vector(samples.begin() + i * num_obs_wires, - samples.begin() + (i + 1) * num_obs_wires - 1); + std::vector(sample_data.begin() + i * num_wires, + sample_data.begin() + (i + 1) * num_wires - 1); std::string key = sample_to_str(local_sample); auto it = outcome_map.find(key); if (it != outcome_map.end()) { From 92571cbb36c6f298a37325507b2aa49ba3a3d72b Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Fri, 17 Nov 2023 22:32:47 +0000 Subject: [PATCH 59/76] 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 226ada7853..e3668fdf7b 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.34.0-dev8" +__version__ = "0.34.0-dev9" From 77cba24fb21512f7e8e9dacc654aefb5c8c6e68e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 17 Nov 2023 21:05:12 -0500 Subject: [PATCH 60/76] add var obs tests --- .../src/measurements/MeasurementsBase.hpp | 40 +++--- .../tests/Test_MeasurementsBase.cpp | 121 ++++++++++++++++++ .../measurements/MeasurementsLQubit.hpp | 14 ++ 3 files changed, 160 insertions(+), 15 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 6be31ac0e3..83f99abf2b 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -28,13 +28,15 @@ namespace { using namespace Pennylane::Observables; -auto sample_to_str(std::vector &sample) -> std::string { +/* +auto sample_to_str(const std::vector &sample) -> std::string { std::string str; for (auto &element : sample) { str += std::to_string(element); } return str; } +*/ } // namespace /// @endcond @@ -246,19 +248,27 @@ template class MeasurementsBase { * The basis columns are rearranged according to wires. */ auto var(const Observable &obs, const size_t &num_shots) { - auto square_mean = expval(obs, num_shots, {}); - square_mean *= square_mean; - - PrecisionT mean_square; - if (obs.getObsName().find("Hamiltonian") == std::string::npos) { - mean_square = 1; - } /*else{ - //Need to verify for Hamiltonian - auto coeffs = obs.getCoeffs(); - } - */ - return mean_square - square_mean; + auto square_mean = expval(obs, num_shots, {}); + PrecisionT result = 1 - square_mean * square_mean; + return result; + } else { + auto coeffs = obs.getCoeffs(); + PrecisionT result{0.0}; + size_t obs_term_idx = 0; + for (const auto &coeff : coeffs) { + std::vector shot_range = {}; + auto obs_samples = measure_with_samples( + obs, num_shots, shot_range, obs_term_idx); + PrecisionT expval_per_term = std::accumulate( + obs_samples.begin(), obs_samples.end(), 0.0); + auto term_mean = expval_per_term / obs_samples.size(); + + result += coeff * coeff * (1 - term_mean * term_mean); + obs_term_idx++; + } + return result; + } } /** @@ -332,7 +342,7 @@ template class MeasurementsBase { auto local_sample = std::vector(sample_data.begin() + i * num_obs_wires, sample_data.begin() + (i + 1) * num_obs_wires - 1); - std::string key = sample_to_str(local_sample); + auto key = sample_to_str(local_sample); auto it = outcome_map.find(key); if (it != outcome_map.end()) { it->second += 1; @@ -364,7 +374,7 @@ template class MeasurementsBase { auto local_sample = std::vector(sample_data.begin() + i * num_wires, sample_data.begin() + (i + 1) * num_wires - 1); - std::string key = sample_to_str(local_sample); + auto key = sample_to_str(local_sample); auto it = outcome_map.find(key); if (it != outcome_map.end()) { it->second += 1; diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 2f6d8adce8..f5d101dab3 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -511,6 +511,20 @@ template void testNamedObsVar() { REQUIRE(expected == Approx(result).margin(1e-6)); } } + + DYNAMIC_SECTION(obs_name[ind_obs] + << " Shots - Varying wires" + << StateVectorToName::name) { + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObs obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + size_t num_shots = 10000; + PrecisionT result = Measurer.var(obs, num_shots); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + } } testNamedObsVar(); } @@ -598,6 +612,58 @@ TEST_CASE("Var - HermitianObs", "[MeasurementsBase][Observables]") { } } +template void testTensorProdObsVarShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = StateVectorT::ComplexT; + + // Defining the State Vector that will be measured. + std::vector statevector_data{ + {0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, {0.1, 0.2}, + {0.2, 0.2}, {0.3, 0.3}, {0.3, 0.4}, {0.4, 0.5}}; + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + DYNAMIC_SECTION(" Without Identity" + << StateVectorToName::name) { + size_t num_shots = 10000; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = TensorProdObs::create({X0, Z1}); + auto expected = Measurer.var(*obs); + auto result = Measurer.var(*obs, num_shots); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With Identity" + << StateVectorToName::name) { + size_t num_shots = 10000; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = TensorProdObs::create({X0, I1}); + PrecisionT expected = Measurer.var(*obs); + PrecisionT result = Measurer.var(*obs, num_shots); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + testTensorProdObsVarShot(); + } +} + +TEST_CASE("Var Shot- TensorProdObs", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testTensorProdObsVarShot(); + } +} template void testSamples() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; @@ -721,6 +787,61 @@ TEST_CASE("Expval Shot - HamiltonianObs ", "[MeasurementsBase][Observables]") { } } +template void testHamiltonianObsVarShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + // using PrecisionT = typename StateVectorT::PrecisionT; + // using ComplexT = typename StateVectorT::ComplexT; + + // Defining the State Vector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + DYNAMIC_SECTION("YZ" << StateVectorToName::name) { + auto Y0 = std::make_shared>( + "PauliY", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = Hamiltonian::create({0.5, 0.5}, {Y0, Z1}); + + size_t num_shots = 10000; + + auto res = Measurer.var(*ob, num_shots); + auto expected = Measurer.var(*ob); + REQUIRE(expected == Approx(res).margin(5e-2)); + } + + DYNAMIC_SECTION("YI" << StateVectorToName::name) { + auto Y0 = std::make_shared>( + "PauliY", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + + auto ob = Hamiltonian::create({0.5, 0.5}, {Y0, I1}); + + size_t num_shots = 10000; + + auto res = Measurer.var(*ob, num_shots); + auto expected = Measurer.var(*ob); + REQUIRE(expected == Approx(res).margin(5e-2)); + } + + testHamiltonianObsVarShot(); + } +} + +TEST_CASE("Var Shot - HamiltonianObs ", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testHamiltonianObsVarShot(); + } +} + template void testSparseHObsExpvalShot() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; 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 e1d3ef551d..8780f65341 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -282,6 +282,20 @@ class Measurements final return BaseType::expval(obs, num_shots, shot_range); } + /** + * @brief Expectation value for a Observable with shots + * + * @param obs Observable + * @param num_shots Number of shots. + * + * @return Floating point expected value of the observable. + */ + + auto var(const Observable &obs, const size_t &num_shots) + -> PrecisionT { + return BaseType::var(obs, num_shots); + } + /** * @brief Variance value for a general Observable * From ecf4683978825c280c52b923d1fed9f6804cbb14 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 20 Nov 2023 13:07:18 -0500 Subject: [PATCH 61/76] add tests for prob for all backend and var for MPI --- .../tests/Test_MeasurementsBase.cpp | 155 ++++++++ .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 355 ++++++++++++++++++ .../measurements/MeasurementsGPU.hpp | 26 ++ .../measurements/MeasurementsGPUMPI.hpp | 26 ++ .../measurements/MeasurementsKokkos.hpp | 26 ++ .../measurements/MeasurementsLQubit.hpp | 12 + 6 files changed, 600 insertions(+) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index f5d101dab3..d5096d978c 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -147,6 +147,161 @@ TEST_CASE("Probabilities", "[MeasurementsBase]") { } } +template void testProbabilitiesObs() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + + const size_t num_qubits = 3; + + // Defining the Statevector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + StateVectorT sv(statevector_data.data(), statevector_data.size()); + + DYNAMIC_SECTION("Test PauliX" + << StateVectorToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObs obs("PauliX", {i}); + Measurements Measurer_shots(statevector); + + sv.applyOperation("Hadamard", {i}, false); + + Measurements Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test PauliY" + << StateVectorToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObs obs("PauliY", {i}); + Measurements Measurer_shots(statevector); + + sv.applyOperations({"PauliZ", "S", "Hadamard"}, {{i}, {i}, {i}}, + {false, false, false}); + + Measurements Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test PauliZ" + << StateVectorToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObs obs("PauliZ", {i}); + Measurements Measurer_shots(statevector); + + Measurements Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test Hadamard" + << StateVectorToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObs obs("Hadamard", {i}); + Measurements Measurer_shots(statevector); + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", {i}, false, {theta}); + + Measurements Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test Identity" + << StateVectorToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObs obs("Identity", {i}); + Measurements Measurer_shots(statevector); + + Measurements Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test TensorProd XYZ" + << StateVectorToName::name) { + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto Y2 = std::make_shared>( + "PauliY", std::vector{2}); + auto obs = TensorProdObs::create({X0, Z1, Y2}); + + Measurements Measurer_shots(statevector); + + sv.applyOperations({"Hadamard", "PauliZ", "S", "Hadamard"}, + {{0}, {2}, {2}, {2}}, + {false, false, false, false}); + + Measurements Measurer(sv); + + auto prob_shots = Measurer_shots.probs(*obs); + auto prob = Measurer.probs({0, 1, 2}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + + DYNAMIC_SECTION("Test TensorProd YHI" + << StateVectorToName::name) { + auto Y0 = std::make_shared>( + "PauliY", std::vector{0}); + auto H1 = std::make_shared>( + "Hadamard", std::vector{1}); + auto I2 = std::make_shared>( + "Identity", std::vector{2}); + auto obs = TensorProdObs::create({Y0, H1, I2}); + + Measurements Measurer_shots(statevector); + + sv.applyOperations({"PauliZ", "S", "Hadamard"}, {{0}, {0}, {0}}, + {false, false, false}); + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", {1}, false, {theta}); + + Measurements Measurer(sv); + + auto prob_shots = Measurer_shots.probs(*obs); + auto prob = Measurer.probs({0, 1, 2}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + + testProbabilitiesObs(); + } +} + +TEST_CASE("Probabilities Obs shots", "[MeasurementsBase]") { + if constexpr (BACKEND_FOUND) { + testProbabilitiesObs(); + } +} + template void testNamedObsExpval() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index 7996c029c8..d794d7841e 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -117,6 +117,191 @@ TEST_CASE("Probabilities", "[MeasurementsBase]") { } } +template void testProbabilitiesObs() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + + const size_t num_qubits = 3; + + // Defining the Statevector that will be measured. + auto statevector_data = + createNonTrivialState>(); + + size_t num_qubits = 3; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + auto sv_data_local = mpi_manager.scatter(statevector_data, 0); + + StateVectorT statevector(mpi_manager, dt_local, mpi_buffersize, + nGlobalIndexBits, nLocalIndexBits); + statevector.CopyHostDataToGpu(sv_data_local.data(), + sv_data_local.size(), false); + mpi_manager.Barrier(); + + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + + mpi_manager.Barrier(); + + DYNAMIC_SECTION("Test PauliX" + << StateVectorMPIToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObsMPI obs("PauliX", {i}); + MeasurementsMPI Measurer_shots(statevector); + + sv.applyOperation("Hadamard", {i}, false); + + MeasurementsMPI Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test PauliY" + << StateVectorMPIToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObsMPI obs("PauliY", {i}); + MeasurementsMPI Measurer_shots(statevector); + + sv.applyOperations({"PauliZ", "S", "Hadamard"}, {{i}, {i}, {i}}, + {false, false, false}); + + MeasurementsMPI Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test PauliZ" + << StateVectorMPIToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObsMPI obs("PauliZ", {i}); + MeasurementsMPI Measurer_shots(statevector); + + MeasurementsMPI Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test Hadamard" + << StateVectorMPIToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObsMPI obs("Hadamard", {i}); + MeasurementsMPI Measurer_shots(statevector); + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", {i}, false, {theta}); + + MeasurementsMPI Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test Identity" + << StateVectorMPIToName::name) { + for (size_t i = 0; i < num_qubits; i++) { + NamedObsMPI obs("Identity", {i}); + MeasurementsMPI Measurer_shots(statevector); + + MeasurementsMPI Measurer(sv); + + auto prob_shots = Measurer_shots.probs(obs); + auto prob = Measurer.probs({i}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + } + + DYNAMIC_SECTION("Test TensorProd XYZ" + << StateVectorMPIToName::name) { + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto Y2 = std::make_shared>( + "PauliY", std::vector{2}); + auto obs = TensorProdObsMPI::create({X0, Z1, Y2}); + + MeasurementsMPI Measurer_shots(statevector); + + sv.applyOperations({"Hadamard", "PauliZ", "S", "Hadamard"}, + {{0}, {2}, {2}, {2}}, + {false, false, false, false}); + + MeasurementsMPI Measurer(sv); + + auto prob_shots = Measurer_shots.probs(*obs); + auto prob = Measurer.probs({0, 1, 2}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + + DYNAMIC_SECTION("Test TensorProd YHI" + << StateVectorMPIToName::name) { + auto Y0 = std::make_shared>( + "PauliY", std::vector{0}); + auto H1 = std::make_shared>( + "Hadamard", std::vector{1}); + auto I2 = std::make_shared>( + "Identity", std::vector{2}); + auto obs = TensorProdObsMPI::create({Y0, H1, I2}); + + MeasurementsMPI Measurer_shots(statevector); + + sv.applyOperations({"PauliZ", "S", "Hadamard"}, {{0}, {0}, {0}}, + {false, false, false}); + const PrecisionT theta = -M_PI / 4.0; + sv.applyOperation("RY", {1}, false, {theta}); + + MeasurementsMPI Measurer(sv); + + auto prob_shots = Measurer_shots.probs(*obs); + auto prob = Measurer.probs({0, 1, 2}); + + REQUIRE_THAT(prob_shots, Catch::Approx(prob).margin(1e-6)); + } + + testProbabilitiesObs(); + } +} + +TEST_CASE("Probabilities Obs shots", "[MeasurementsBase]") { + if constexpr (BACKEND_FOUND) { + testProbabilitiesObs(); + } +} + template void testNamedObsExpval() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; @@ -653,6 +838,20 @@ template void testNamedObsVar() { REQUIRE(expected == Approx(result).margin(1e-6)); } } + + DYNAMIC_SECTION(obs_name[ind_obs] + << " Shots - Varying wires" + << StateVectorMPIToName::name) { + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObsMPI obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + size_t num_shots = 10000; + PrecisionT result = Measurer.var(obs); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + } } testNamedObsVar(); } @@ -765,6 +964,83 @@ TEST_CASE("Var - HermitianObs", "[MeasurementsBase][Observables]") { } } +template void testTensorProdObsVarShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + using ComplexT = StateVectorT::ComplexT; + + // Defining the State Vector that will be measured. + std::vector statevector_data{ + {0.0, 0.0}, {0.0, 0.1}, {0.1, 0.1}, {0.1, 0.2}, + {0.2, 0.2}, {0.3, 0.3}, {0.3, 0.4}, {0.4, 0.5}}; + + size_t num_qubits = 3; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + auto sv_data_local = mpi_manager.scatter(statevector_data, 0); + + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + MeasurementsMPI Measurer(sv); + + DYNAMIC_SECTION(" Without Identity" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + auto obs = TensorProdObsMPI::create({X0, Z1}); + auto expected = Measurer.var(*obs); + auto result = Measurer.var(*obs, num_shots); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + DYNAMIC_SECTION(" With Identity" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + auto X0 = std::make_shared>( + "PauliX", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + auto obs = TensorProdObsMPI::create({X0, I1}); + PrecisionT expected = Measurer.var(*obs); + PrecisionT result = Measurer.var(*obs, num_shots); + REQUIRE(expected == Approx(result).margin(5e-2)); + } + + testTensorProdObsVarShot(); + } +} + +TEST_CASE("Var Shot- TensorProdObs", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testTensorProdObsVarShot(); + } +} + template void testSamples() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; @@ -852,4 +1128,83 @@ TEST_CASE("Samples", "[MeasurementsBase]") { if constexpr (BACKEND_FOUND) { testSamples(); } +} + +template void testHamiltonianObsVarShot() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + // using PrecisionT = typename StateVectorT::PrecisionT; + // using ComplexT = typename StateVectorT::ComplexT; + + // Defining the State Vector that will be measured. + size_t num_qubits = 3; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + auto sv_data_local = mpi_manager.scatter(statevector_data, 0); + + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + MeasurementsMPI Measurer(sv); + + DYNAMIC_SECTION("YZ" << StateVectorMPIToName::name) { + auto Y0 = std::make_shared>( + "PauliY", std::vector{0}); + auto Z1 = std::make_shared>( + "PauliZ", std::vector{1}); + + auto ob = + HamiltonianMPI::create({0.5, 0.5}, {Y0, Z1}); + + size_t num_shots = 10000; + + auto res = Measurer.var(*ob, num_shots); + auto expected = Measurer.var(*ob); + REQUIRE(expected == Approx(res).margin(5e-2)); + } + + DYNAMIC_SECTION("YI" << StateVectorMPIToName::name) { + auto Y0 = std::make_shared>( + "PauliY", std::vector{0}); + auto I1 = std::make_shared>( + "Identity", std::vector{1}); + + auto ob = + HamiltonianMPI::create({0.5, 0.5}, {Y0, I1}); + + size_t num_shots = 10000; + + auto res = Measurer.var(*ob, num_shots); + auto expected = Measurer.var(*ob); + REQUIRE(expected == Approx(res).margin(5e-2)); + } + + testHamiltonianObsVarShot(); + } +} + +TEST_CASE("Var Shot - HamiltonianObs ", "[MeasurementsBase][Observables]") { + if constexpr (BACKEND_FOUND) { + testHamiltonianObsVarShot(); + } } \ No newline at end of file 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 78ab5b53e8..cc6651b0a0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -153,6 +153,18 @@ class Measurements final return this->probs(wires); } + /** + * @brief Probabilities of each computational basis state. + * + * @param obs Observable + * + * @return Floating point std::vector with probabilities + * in lexicographic order. + */ + std::vector probs(const Observable &obs) { + return BaseType::probs(obs); + } + /** * @brief Utility method for samples. * @@ -631,6 +643,20 @@ class Measurements final return (mean_square - squared_mean); }; + /** + * @brief Expectation value for a Observable with shots + * + * @param obs Observable + * @param num_shots Number of shots. + * + * @return Floating point expected value of the observable. + */ + + auto var(const Observable &obs, const size_t &num_shots) + -> PrecisionT { + return BaseType::var(obs, num_shots); + } + private: /** * @brief Utility method for expectation value calculations. diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp index c4bac79435..96d8d46712 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp @@ -209,6 +209,18 @@ class MeasurementsMPI final return this->probs(wires); } + /** + * @brief Probabilities of each computational basis state. + * + * @param obs Observable + * + * @return Floating point std::vector with probabilities + * in lexicographic order. + */ + std::vector probs(const Observable &obs) { + return BaseType::probs(obs); + } + /** * @brief Utility method for samples. * @@ -734,5 +746,19 @@ class MeasurementsMPI final return mean_square - squared_mean * squared_mean; }; + + /** + * @brief Expectation value for a Observable with shots + * + * @param obs Observable + * @param num_shots Number of shots. + * + * @return Floating point expected value of the observable. + */ + + auto var(const Observable &obs, const size_t &num_shots) + -> PrecisionT { + return BaseType::var(obs, num_shots); + } }; // class Measurements } // namespace Pennylane::LightningGPU::Measures \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp index e4212d5b15..9989bf77f6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp @@ -457,6 +457,20 @@ class Measurements final return (mean_square - squared_mean); }; + /** + * @brief Expectation value for a Observable with shots + * + * @param obs Observable + * @param num_shots Number of shots. + * + * @return Floating point expected value of the observable. + */ + + auto var(const Observable &obs, const size_t &num_shots) + -> PrecisionT { + return BaseType::var(obs, num_shots); + } + /** * @brief Probabilities of each computational basis state. * @@ -592,6 +606,18 @@ class Measurements final } } + /** + * @brief Probabilities of each computational basis state. + * + * @param obs Observable + * + * @return Floating point std::vector with probabilities + * in lexicographic order. + */ + std::vector probs(const Observable &obs) { + return BaseType::probs(obs); + } + /** * @brief Inverse transform sampling method for samples. * Reference https://en.wikipedia.org/wiki/Inverse_transform_sampling 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 8780f65341..c8a1969062 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -134,6 +134,18 @@ class Measurements final return probabilities; } + /** + * @brief Probabilities of each computational basis state. + * + * @param obs Observable + * + * @return Floating point std::vector with probabilities + * in lexicographic order. + */ + std::vector probs(const Observable &obs) { + return BaseType::probs(obs); + } + /** * @brief Expected value of an observable. * From 38748b3b0ce6cc99595541342d553399e5895800 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 20 Nov 2023 10:47:39 -0800 Subject: [PATCH 62/76] quick fix --- .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index d794d7841e..4457e70ae9 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -128,8 +128,6 @@ template void testProbabilitiesObs() { auto statevector_data = createNonTrivialState>(); - size_t num_qubits = 3; - MPIManager mpi_manager(MPI_COMM_WORLD); REQUIRE(mpi_manager.getSize() == 2); @@ -848,7 +846,7 @@ template void testNamedObsVar() { wires_list[ind_wires]); PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; size_t num_shots = 10000; - PrecisionT result = Measurer.var(obs); + PrecisionT result = Measurer.var(obs, num_shots); REQUIRE(expected == Approx(result).margin(5e-2)); } } @@ -1133,8 +1131,10 @@ TEST_CASE("Samples", "[MeasurementsBase]") { template void testHamiltonianObsVarShot() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; - // using PrecisionT = typename StateVectorT::PrecisionT; - // using ComplexT = typename StateVectorT::ComplexT; + using PrecisionT = typename StateVectorT::PrecisionT; + + auto statevector_data = + createNonTrivialState>(); // Defining the State Vector that will be measured. size_t num_qubits = 3; From e3bb395690149f59214a3d3d61d26d027489830d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 20 Nov 2023 14:59:04 -0500 Subject: [PATCH 63/76] add unit tests for counts & samples obs --- .../src/measurements/MeasurementsBase.hpp | 14 ++-- .../tests/Test_MeasurementsBase.cpp | 80 +++++++++++++++++++ 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 83f99abf2b..816baa7b62 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -306,8 +306,9 @@ template class MeasurementsBase { std::vector obs_wires; std::vector identity_wires; std::vector shot_range = {}; - return _sample_state(obs, num_shots, shot_range, obs_wires, - identity_wires); + size_t term_idx = 0; + + return measure_with_samples(obs, num_shots, shot_range, term_idx); } /** @@ -334,15 +335,12 @@ template class MeasurementsBase { */ auto counts(const Observable &obs, const size_t &num_shots) -> std::unordered_map { - std::unordered_map outcome_map; + std::unordered_map outcome_map; std::vector shot_range = {}; - auto sample_data = sample(obs, num_shots, shot_range); + auto sample_data = sample(obs, num_shots); size_t num_obs_wires = obs.getWires(); for (size_t i = 0; i < num_shots; i++) { - auto local_sample = - std::vector(sample_data.begin() + i * num_obs_wires, - sample_data.begin() + (i + 1) * num_obs_wires - 1); - auto key = sample_to_str(local_sample); + auto key = sample_data[i]; auto it = outcome_map.find(key); if (it != outcome_map.end()) { it->second += 1; diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index d5096d978c..9a797c09a4 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -885,6 +885,86 @@ TEST_CASE("Samples", "[MeasurementsBase]") { } } +template void testSamplesCountsObs() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + + // Defining the State Vector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measurements class. + // This object attaches to the statevector allowing several + // measurements. + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + Measurements Measurer(statevector); + + std::vector> wires_list = {{0}, {1}, {2}}; + std::vector obs_name = {"PauliX", "PauliY", "PauliZ", + "Hadamard", "Identity"}; + // Expected results calculated with Pennylane default.qubit: + std::vector> exp_values_ref = { + {0.49272486, 0.42073549, 0.28232124}, + {-0.64421768, -0.47942553, -0.29552020}, + {0.58498357, 0.77015115, 0.91266780}, + {0.7620549436, 0.8420840225, 0.8449848566}, + {1.0, 1.0, 1.0}}; + for (size_t ind_obs = 0; ind_obs < obs_name.size(); ind_obs++) { + DYNAMIC_SECTION(obs_name[ind_obs] + << " SampleObs - Varying wires" + << StateVectorToName::name) { + size_t num_shots = 10000; + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObs obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + auto samples = Measurer.sample(obs, num_shots); + + PrecisionT result = 0.0; + for (auto &it : samples) { + result += it; + } + result /= num_shots; + + REQUIRE(expected == Approx(result).margin(5e-2)); + } + } + + DYNAMIC_SECTION(obs_name[ind_obs] + << " CountsObs - Varying wires" + << StateVectorToName::name) { + size_t num_shots = 10000; + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObs obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + auto samples = Measurer.counts(obs, num_shots); + + PrecisionT result = 0.0; + for (auto &it : samples) { + result += it.first * it.second; + } + result /= num_shots; + + REQUIRE(expected == Approx(result).margin(5e-2)); + } + } + } + testSamplesCountsObs(); + } +} + +TEST_CASE("Samples Obs", "[MeasurementsBase]") { + if constexpr (BACKEND_FOUND) { + testSamplesCountsObs(); + } +} + template void testHamiltonianObsExpvalShot() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; From 0ee73cbd829b5353ec370efef57537f9ce08bd94 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 20 Nov 2023 17:17:06 -0500 Subject: [PATCH 64/76] add more sample() & counts() unit tests --- .../src/measurements/MeasurementsBase.hpp | 22 +-- .../tests/Test_MeasurementsBase.cpp | 142 +++++++++++++++++- 2 files changed, 148 insertions(+), 16 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 816baa7b62..a55976d7cb 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -27,16 +27,6 @@ /// @cond DEV namespace { using namespace Pennylane::Observables; - -/* -auto sample_to_str(const std::vector &sample) -> std::string { - std::string str; - for (auto &element : sample) { - str += std::to_string(element); - } - return str; -} -*/ } // namespace /// @endcond @@ -334,11 +324,10 @@ template class MeasurementsBase { * num_occurences}`` */ auto counts(const Observable &obs, const size_t &num_shots) - -> std::unordered_map { + -> std::unordered_map { std::unordered_map outcome_map; std::vector shot_range = {}; auto sample_data = sample(obs, num_shots); - size_t num_obs_wires = obs.getWires(); for (size_t i = 0; i < num_shots; i++) { auto key = sample_data[i]; auto it = outcome_map.find(key); @@ -371,8 +360,13 @@ template class MeasurementsBase { for (size_t i = 0; i < num_shots; i++) { auto local_sample = std::vector(sample_data.begin() + i * num_wires, - sample_data.begin() + (i + 1) * num_wires - 1); - auto key = sample_to_str(local_sample); + sample_data.begin() + (i + 1) * num_wires); + + std::string key; + for (auto &element : local_sample) { + key += std::to_string(element); + } + auto it = outcome_map.find(key); if (it != outcome_map.end()) { it->second += 1; diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 9a797c09a4..50d278c330 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -19,6 +19,8 @@ namespace { using Pennylane::Util::isApproxEqual; } // namespace /// @endcond +#include +#include #ifdef _ENABLE_PLQUBIT constexpr bool BACKEND_FOUND = true; @@ -914,7 +916,7 @@ template void testSamplesCountsObs() { {1.0, 1.0, 1.0}}; for (size_t ind_obs = 0; ind_obs < obs_name.size(); ind_obs++) { DYNAMIC_SECTION(obs_name[ind_obs] - << " SampleObs - Varying wires" + << " Sample Obs - Varying wires" << StateVectorToName::name) { size_t num_shots = 10000; for (size_t ind_wires = 0; ind_wires < wires_list.size(); @@ -935,7 +937,7 @@ template void testSamplesCountsObs() { } DYNAMIC_SECTION(obs_name[ind_obs] - << " CountsObs - Varying wires" + << " Counts Obs - Varying wires" << StateVectorToName::name) { size_t num_shots = 10000; for (size_t ind_wires = 0; ind_wires < wires_list.size(); @@ -955,6 +957,142 @@ template void testSamplesCountsObs() { } } } + + DYNAMIC_SECTION("samples() without obs" + << StateVectorToName::name) { + constexpr size_t twos[] = { + 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, + 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, + 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, + 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, + 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, + 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, + 1U << 30U, 1U << 31U}; + + // Defining the State Vector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measurements class. + // This object attaches to the statevector allowing several + // measurements. + Measurements Measurer(statevector); + + std::vector expected_probabilities = { + 0.67078706, 0.03062806, 0.0870997, 0.00397696, + 0.17564072, 0.00801973, 0.02280642, 0.00104134}; + + size_t num_qubits = 3; + size_t N = std::pow(2, num_qubits); + size_t num_samples = 100000; + auto &&samples = Measurer.sample(num_samples); + + std::vector counts(N, 0); + std::vector samples_decimal(num_samples, 0); + + // convert samples to decimal and then bin them in counts + for (size_t i = 0; i < num_samples; i++) { + for (size_t j = 0; j < num_qubits; j++) { + if (samples[i * num_qubits + j] != 0) { + samples_decimal[i] += twos[(num_qubits - 1 - j)]; + } + } + counts[samples_decimal[i]] += 1; + } + + // compute estimated probabilities from histogram + std::vector probabilities(counts.size()); + for (size_t i = 0; i < counts.size(); i++) { + probabilities[i] = counts[i] / (PrecisionT)num_samples; + } + + DYNAMIC_SECTION("No Observable provided - " + << StateVectorToName::name) { + REQUIRE_THAT(probabilities, + Catch::Approx(expected_probabilities).margin(.05)); + } + } + + DYNAMIC_SECTION("counts() without obs" + << StateVectorToName::name) { + constexpr size_t twos[] = { + 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, + 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, + 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, + 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, + 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, + 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, + 1U << 30U, 1U << 31U}; + + std::vector expected_keys = { + "000", "001", "010", "011", "100", "101", "110", "111"}; + + // Defining the State Vector that will be measured. + auto statevector_data = createNonTrivialState(); + StateVectorT statevector(statevector_data.data(), + statevector_data.size()); + + // Initializing the measurements class. + // This object attaches to the statevector allowing several + // measurements. + Measurements Measurer(statevector); + + std::vector expected_probabilities = { + 0.67078706, 0.03062806, 0.0870997, 0.00397696, + 0.17564072, 0.00801973, 0.02280642, 0.00104134}; + + size_t num_qubits = 3; + size_t N = std::pow(2, num_qubits); + size_t num_samples = 100000; + + auto &&counts_sample = Measurer.counts(num_samples); + + std::vector counts(N, 0); + + // convert samples to decimal and then bin them in counts + for (auto &it : counts_sample) { + std::vector localBits(num_qubits, 10); + auto key = it.first; + + bool found = false; + + auto iter = + std::find(expected_keys.begin(), expected_keys.end(), key); + + if (iter != expected_keys.end()) { + found = true; + } + + REQUIRE(found == true); + + size_t idx = 0; + size_t decimal_idx = 0; + for (char &c : key) { + if (c == '1') { + localBits[idx] = 1; + decimal_idx += twos[(num_qubits - 1 - idx)]; + } else if (c == '0') { + localBits[idx] = 0; + } + idx++; + } + for (auto &bit : localBits) { + REQUIRE(bit * (bit - 1) == 0); + } + counts[decimal_idx] = it.second; + } + + // compute estimated probabilities from histogram + std::vector probabilities(counts.size()); + for (size_t i = 0; i < counts.size(); i++) { + probabilities[i] = counts[i] / (PrecisionT)num_samples; + } + + REQUIRE_THAT(probabilities, + Catch::Approx(expected_probabilities).margin(.05)); + } + testSamplesCountsObs(); } } From 531f3860ba6e74be0add9e5a1954b08834bbe3e1 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 20 Nov 2023 14:40:50 -0800 Subject: [PATCH 65/76] add sample counts tests for mpi backend --- .../tests/Test_MeasurementsBase.cpp | 20 -- .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 218 ++++++++++++++++++ 2 files changed, 218 insertions(+), 20 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 50d278c330..6aa881992f 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -969,16 +969,6 @@ template void testSamplesCountsObs() { 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, 1U << 30U, 1U << 31U}; - // Defining the State Vector that will be measured. - auto statevector_data = createNonTrivialState(); - StateVectorT statevector(statevector_data.data(), - statevector_data.size()); - - // Initializing the measurements class. - // This object attaches to the statevector allowing several - // measurements. - Measurements Measurer(statevector); - std::vector expected_probabilities = { 0.67078706, 0.03062806, 0.0870997, 0.00397696, 0.17564072, 0.00801973, 0.02280642, 0.00104134}; @@ -1028,16 +1018,6 @@ template void testSamplesCountsObs() { std::vector expected_keys = { "000", "001", "010", "011", "100", "101", "110", "111"}; - // Defining the State Vector that will be measured. - auto statevector_data = createNonTrivialState(); - StateVectorT statevector(statevector_data.data(), - statevector_data.size()); - - // Initializing the measurements class. - // This object attaches to the statevector allowing several - // measurements. - Measurements Measurer(statevector); - std::vector expected_probabilities = { 0.67078706, 0.03062806, 0.0870997, 0.00397696, 0.17564072, 0.00801973, 0.02280642, 0.00104134}; diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index 4457e70ae9..392db93dfe 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -1128,6 +1128,224 @@ TEST_CASE("Samples", "[MeasurementsBase]") { } } +template void testSamplesCountsObs() { + if constexpr (!std::is_same_v) { + using StateVectorT = typename TypeList::Type; + using PrecisionT = typename StateVectorT::PrecisionT; + + // Defining the State Vector that will be measured. + auto statevector_data = + createNonTrivialState>(); + + size_t num_qubits = 3; + + MPIManager mpi_manager(MPI_COMM_WORLD); + REQUIRE(mpi_manager.getSize() == 2); + + size_t mpi_buffersize = 1; + + size_t nGlobalIndexBits = + std::bit_width(static_cast(mpi_manager.getSize())) - 1; + size_t nLocalIndexBits = num_qubits - nGlobalIndexBits; + + int nDevices = 0; + cudaGetDeviceCount(&nDevices); + REQUIRE(nDevices >= 2); + int deviceId = mpi_manager.getRank() % nDevices; + cudaSetDevice(deviceId); + DevTag dt_local(deviceId, 0); + mpi_manager.Barrier(); + + auto sv_data_local = mpi_manager.scatter(statevector_data, 0); + + StateVectorT sv(mpi_manager, dt_local, mpi_buffersize, nGlobalIndexBits, + nLocalIndexBits); + sv.CopyHostDataToGpu(sv_data_local.data(), sv_data_local.size(), false); + mpi_manager.Barrier(); + + // Initializing the measures class. + // This object attaches to the statevector allowing several measures. + MeasurementsMPI Measurer(sv); + + std::vector> wires_list = {{0}, {1}, {2}}; + std::vector obs_name = {"PauliX", "PauliY", "PauliZ", + "Hadamard", "Identity"}; + // Expected results calculated with Pennylane default.qubit: + std::vector> exp_values_ref = { + {0.49272486, 0.42073549, 0.28232124}, + {-0.64421768, -0.47942553, -0.29552020}, + {0.58498357, 0.77015115, 0.91266780}, + {0.7620549436, 0.8420840225, 0.8449848566}, + {1.0, 1.0, 1.0}}; + for (size_t ind_obs = 0; ind_obs < obs_name.size(); ind_obs++) { + DYNAMIC_SECTION(obs_name[ind_obs] + << " Sample Obs - Varying wires" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObsMPI obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + auto samples = Measurer.sample(obs, num_shots); + + PrecisionT result = 0.0; + for (auto &it : samples) { + result += it; + } + result /= num_shots; + + REQUIRE(expected == Approx(result).margin(5e-2)); + } + } + + DYNAMIC_SECTION(obs_name[ind_obs] + << " Counts Obs - Varying wires" + << StateVectorMPIToName::name) { + size_t num_shots = 10000; + for (size_t ind_wires = 0; ind_wires < wires_list.size(); + ind_wires++) { + NamedObsMPI obs(obs_name[ind_obs], + wires_list[ind_wires]); + PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; + auto samples = Measurer.counts(obs, num_shots); + + PrecisionT result = 0.0; + for (auto &it : samples) { + result += it.first * it.second; + } + result /= num_shots; + + REQUIRE(expected == Approx(result).margin(5e-2)); + } + } + } + + DYNAMIC_SECTION("samples() without obs" + << StateVectorMPIToName::name) { + constexpr size_t twos[] = { + 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, + 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, + 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, + 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, + 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, + 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, + 1U << 30U, 1U << 31U}; + + std::vector expected_probabilities = { + 0.67078706, 0.03062806, 0.0870997, 0.00397696, + 0.17564072, 0.00801973, 0.02280642, 0.00104134}; + + size_t num_qubits = 3; + size_t N = std::pow(2, num_qubits); + size_t num_samples = 100000; + auto &&samples = Measurer.sample(num_samples); + + std::vector counts(N, 0); + std::vector samples_decimal(num_samples, 0); + + // convert samples to decimal and then bin them in counts + for (size_t i = 0; i < num_samples; i++) { + for (size_t j = 0; j < num_qubits; j++) { + if (samples[i * num_qubits + j] != 0) { + samples_decimal[i] += twos[(num_qubits - 1 - j)]; + } + } + counts[samples_decimal[i]] += 1; + } + + // compute estimated probabilities from histogram + std::vector probabilities(counts.size()); + for (size_t i = 0; i < counts.size(); i++) { + probabilities[i] = counts[i] / (PrecisionT)num_samples; + } + + DYNAMIC_SECTION("No Observable provided - " + << StateVectorMPIToName::name) { + REQUIRE_THAT(probabilities, + Catch::Approx(expected_probabilities).margin(.05)); + } + } + + DYNAMIC_SECTION("counts() without obs" + << StateVectorMPIToName::name) { + constexpr size_t twos[] = { + 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, + 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, + 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, + 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, + 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, + 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, + 1U << 30U, 1U << 31U}; + + std::vector expected_keys = { + "000", "001", "010", "011", "100", "101", "110", "111"}; + + std::vector expected_probabilities = { + 0.67078706, 0.03062806, 0.0870997, 0.00397696, + 0.17564072, 0.00801973, 0.02280642, 0.00104134}; + + size_t num_qubits = 3; + size_t N = std::pow(2, num_qubits); + size_t num_samples = 100000; + + auto &&counts_sample = Measurer.counts(num_samples); + + std::vector counts(N, 0); + + // convert samples to decimal and then bin them in counts + for (auto &it : counts_sample) { + std::vector localBits(num_qubits, 10); + auto key = it.first; + + bool found = false; + + auto iter = + std::find(expected_keys.begin(), expected_keys.end(), key); + + if (iter != expected_keys.end()) { + found = true; + } + + REQUIRE(found == true); + + size_t idx = 0; + size_t decimal_idx = 0; + for (char &c : key) { + if (c == '1') { + localBits[idx] = 1; + decimal_idx += twos[(num_qubits - 1 - idx)]; + } else if (c == '0') { + localBits[idx] = 0; + } + idx++; + } + for (auto &bit : localBits) { + REQUIRE(bit * (bit - 1) == 0); + } + counts[decimal_idx] = it.second; + } + + // compute estimated probabilities from histogram + std::vector probabilities(counts.size()); + for (size_t i = 0; i < counts.size(); i++) { + probabilities[i] = counts[i] / (PrecisionT)num_samples; + } + + REQUIRE_THAT(probabilities, + Catch::Approx(expected_probabilities).margin(.05)); + } + + testSamplesCountsObs(); + } +} + +TEST_CASE("Samples Obs", "[MeasurementsBase]") { + if constexpr (BACKEND_FOUND) { + testSamplesCountsObs(); + } +} + template void testHamiltonianObsVarShot() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; From e23a3494a8bcb090c866e72dc410a6f4c645723f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 20 Nov 2023 18:14:23 -0500 Subject: [PATCH 66/76] make format --- .../src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index 392db93dfe..7a0b3ca4ec 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -1185,7 +1185,7 @@ template void testSamplesCountsObs() { for (size_t ind_wires = 0; ind_wires < wires_list.size(); ind_wires++) { NamedObsMPI obs(obs_name[ind_obs], - wires_list[ind_wires]); + wires_list[ind_wires]); PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; auto samples = Measurer.sample(obs, num_shots); @@ -1206,7 +1206,7 @@ template void testSamplesCountsObs() { for (size_t ind_wires = 0; ind_wires < wires_list.size(); ind_wires++) { NamedObsMPI obs(obs_name[ind_obs], - wires_list[ind_wires]); + wires_list[ind_wires]); PrecisionT expected = exp_values_ref[ind_obs][ind_wires]; auto samples = Measurer.counts(obs, num_shots); From a8cb9bcc7b0f3c04d9945d4be0beaa4389f3cac7 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 20 Nov 2023 18:15:35 -0500 Subject: [PATCH 67/76] Trigger MPI CI From f2c79230f676acf2c1bca2bdf4532011b73d1c1e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 21 Nov 2023 09:05:53 -0500 Subject: [PATCH 68/76] tidy up code --- .../src/measurements/MeasurementsBase.hpp | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index a55976d7cb..1fa57fc564 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -242,23 +242,22 @@ template class MeasurementsBase { auto square_mean = expval(obs, num_shots, {}); PrecisionT result = 1 - square_mean * square_mean; return result; - } else { - auto coeffs = obs.getCoeffs(); - PrecisionT result{0.0}; - size_t obs_term_idx = 0; - for (const auto &coeff : coeffs) { - std::vector shot_range = {}; - auto obs_samples = measure_with_samples( - obs, num_shots, shot_range, obs_term_idx); - PrecisionT expval_per_term = std::accumulate( - obs_samples.begin(), obs_samples.end(), 0.0); - auto term_mean = expval_per_term / obs_samples.size(); + } + auto coeffs = obs.getCoeffs(); + PrecisionT result{0.0}; + size_t obs_term_idx = 0; + for (const auto &coeff : coeffs) { + std::vector shot_range = {}; + auto obs_samples = + measure_with_samples(obs, num_shots, shot_range, obs_term_idx); + PrecisionT expval_per_term = + std::accumulate(obs_samples.begin(), obs_samples.end(), 0.0); + auto term_mean = expval_per_term / obs_samples.size(); - result += coeff * coeff * (1 - term_mean * term_mean); - obs_term_idx++; - } - return result; + result += coeff * coeff * (1 - term_mean * term_mean); + obs_term_idx++; } + return result; } /** From 17539d92024df286a54a44b1c623ed0b080fe1aa Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 21 Nov 2023 10:05:13 -0500 Subject: [PATCH 69/76] add changelogs and tidy up unit tests --- .github/CHANGELOG.md | 3 ++ .../src/measurements/MeasurementsBase.hpp | 47 ++++++++++++------- .../tests/Test_MeasurementsBase.cpp | 36 ++++---------- .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 33 ++++--------- 4 files changed, 53 insertions(+), 66 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index d40aad0c43..4f20aa9001 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add shots support for variance value, probs, sample, counts calculation for given observables (`NamedObs`, `TensorProd` and `Hamiltonian`) based on Pauli words, `Identity` and `Hadamard` in the C++ layer. All Lightning backends support this support feature. +[(#561)](https://github.com/PennyLaneAI/pennylane-lightning/pull/561) + * Add shots support for expectation value calculation for given observables (`NamedObs`, `TensorProd` and `Hamiltonian`) based on Pauli words, `Identity` and `Hadamard` in the C++ layer by adding `measure_with_samples` to the measurement interface. All Lightning backends support this support feature. [(#556)](https://github.com/PennyLaneAI/pennylane-lightning/pull/556) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 1fa57fc564..0b29fa3b84 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -229,20 +229,26 @@ template class MeasurementsBase { } /** - * @brief Probability of each computational basis state for an observable. + * @brief Calculate the variance for an observable with the number of shots. * * @param obs An observable object. * @param num_shots Number of shots used to generate samples * - * @return Floating point std::vector with probabilities. - * The basis columns are rearranged according to wires. + * @return Variance of the given observable. */ auto var(const Observable &obs, const size_t &num_shots) { if (obs.getObsName().find("Hamiltonian") == std::string::npos) { + // Branch for NamedObs and TensorProd observables auto square_mean = expval(obs, num_shots, {}); - PrecisionT result = 1 - square_mean * square_mean; + PrecisionT result = + 1 - square_mean * + square_mean; //`1` used here is because Eigenvalues for + // Paulis, Hadamard and Identity are {-1, + // 1}. Need to change based on eigen values + // when add Hermitian support. return result; } + // Branch for Hamiltonian observables auto coeffs = obs.getCoeffs(); PrecisionT result{0.0}; size_t obs_term_idx = 0; @@ -254,7 +260,13 @@ template class MeasurementsBase { std::accumulate(obs_samples.begin(), obs_samples.end(), 0.0); auto term_mean = expval_per_term / obs_samples.size(); - result += coeff * coeff * (1 - term_mean * term_mean); + result += + coeff * coeff * + (1 - term_mean * + term_mean); //`1` used here is because Eigenvalues for + // Paulis, Hadamard and Identity are {-1, + // 1}. Need to change based on eigen values + // when add Hermitian support. obs_term_idx++; } return result; @@ -281,14 +293,15 @@ template class MeasurementsBase { } /** - * @brief Return samples of a observable + * @brief Return samples drawn from eigenvalues of the observable * - * @param obs The observable to sample + * @param obs The observable object to sample * @param num_shots Number of shots used to generate samples * - * @return std::vector samples in std::vector + * @return samples of eigenvalues of the observable */ - auto sample(const Observable &obs, const size_t &num_shots) { + auto sample(const Observable &obs, const size_t &num_shots) + -> std::vector { PL_ABORT_IF( obs.getObsName().find("Hamiltonian") != std::string::npos, "Hamiltonian and Sparse Hamiltonian do not support samples()."); @@ -301,26 +314,26 @@ template class MeasurementsBase { } /** - * @brief Return generated samples + * @brief Return the raw basis state samples * * @param num_shots Number of shots used to generate samples * - * @return std::vector samples in std::vector + * @return the raw basis state samples */ - auto sample(const size_t &num_shots) { + auto sample(const size_t &num_shots) -> std::vector { Derived measure(_statevector); return measure.generate_samples(num_shots); } /** - * @brief Groups the samples into a dictionary showing number of occurences - * for each possible outcome. + * @brief Groups the eigen values of samples into a dictionary showing + * number of occurences for each possible outcome with the number of shots. * * @param obs The observable to sample * @param num_shots number of wires the sampled observable was performed on * - * @return std::unordered_map with format ``{'outcome': - * num_occurences}`` + * @return std::unordered_map with format + * ``{'EigenValue': num_occurences}`` */ auto counts(const Observable &obs, const size_t &num_shots) -> std::unordered_map { @@ -341,7 +354,7 @@ template class MeasurementsBase { /** * @brief Groups the samples into a dictionary showing number of occurences - * for each possible outcome. + * for each possible outcome with the number of shots. * * @param num_shots number of wires the sampled observable was performed on * diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index 6aa881992f..fb5980c595 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -897,9 +897,14 @@ template void testSamplesCountsObs() { StateVectorT statevector(statevector_data.data(), statevector_data.size()); - // Initializing the measurements class. - // This object attaches to the statevector allowing several - // measurements. + constexpr size_t twos[] = { + 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, 1U << 5U, + 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, 1U << 10U, 1U << 11U, + 1U << 12U, 1U << 13U, 1U << 14U, 1U << 15U, 1U << 16U, 1U << 17U, + 1U << 18U, 1U << 19U, 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, + 1U << 24U, 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, + 1U << 30U, 1U << 31U}; + // Initializing the measures class. // This object attaches to the statevector allowing several measures. Measurements Measurer(statevector); @@ -960,15 +965,6 @@ template void testSamplesCountsObs() { DYNAMIC_SECTION("samples() without obs" << StateVectorToName::name) { - constexpr size_t twos[] = { - 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, - 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, - 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, - 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, - 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, - 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, - 1U << 30U, 1U << 31U}; - std::vector expected_probabilities = { 0.67078706, 0.03062806, 0.0870997, 0.00397696, 0.17564072, 0.00801973, 0.02280642, 0.00104134}; @@ -997,24 +993,12 @@ template void testSamplesCountsObs() { probabilities[i] = counts[i] / (PrecisionT)num_samples; } - DYNAMIC_SECTION("No Observable provided - " - << StateVectorToName::name) { - REQUIRE_THAT(probabilities, - Catch::Approx(expected_probabilities).margin(.05)); - } + REQUIRE_THAT(probabilities, + Catch::Approx(expected_probabilities).margin(.05)); } DYNAMIC_SECTION("counts() without obs" << StateVectorToName::name) { - constexpr size_t twos[] = { - 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, - 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, - 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, - 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, - 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, - 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, - 1U << 30U, 1U << 31U}; - std::vector expected_keys = { "000", "001", "010", "011", "100", "101", "110", "111"}; diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index 7a0b3ca4ec..57e4730413 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -1167,6 +1167,14 @@ template void testSamplesCountsObs() { // This object attaches to the statevector allowing several measures. MeasurementsMPI Measurer(sv); + constexpr size_t twos[] = { + 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, 1U << 5U, + 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, 1U << 10U, 1U << 11U, + 1U << 12U, 1U << 13U, 1U << 14U, 1U << 15U, 1U << 16U, 1U << 17U, + 1U << 18U, 1U << 19U, 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, + 1U << 24U, 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, + 1U << 30U, 1U << 31U}; + std::vector> wires_list = {{0}, {1}, {2}}; std::vector obs_name = {"PauliX", "PauliY", "PauliZ", "Hadamard", "Identity"}; @@ -1223,15 +1231,6 @@ template void testSamplesCountsObs() { DYNAMIC_SECTION("samples() without obs" << StateVectorMPIToName::name) { - constexpr size_t twos[] = { - 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, - 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, - 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, - 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, - 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, - 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, - 1U << 30U, 1U << 31U}; - std::vector expected_probabilities = { 0.67078706, 0.03062806, 0.0870997, 0.00397696, 0.17564072, 0.00801973, 0.02280642, 0.00104134}; @@ -1260,24 +1259,12 @@ template void testSamplesCountsObs() { probabilities[i] = counts[i] / (PrecisionT)num_samples; } - DYNAMIC_SECTION("No Observable provided - " - << StateVectorMPIToName::name) { - REQUIRE_THAT(probabilities, - Catch::Approx(expected_probabilities).margin(.05)); - } + REQUIRE_THAT(probabilities, + Catch::Approx(expected_probabilities).margin(.05)); } DYNAMIC_SECTION("counts() without obs" << StateVectorMPIToName::name) { - constexpr size_t twos[] = { - 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, 1U << 4U, - 1U << 5U, 1U << 6U, 1U << 7U, 1U << 8U, 1U << 9U, - 1U << 10U, 1U << 11U, 1U << 12U, 1U << 13U, 1U << 14U, - 1U << 15U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, - 1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 24U, - 1U << 25U, 1U << 26U, 1U << 27U, 1U << 28U, 1U << 29U, - 1U << 30U, 1U << 31U}; - std::vector expected_keys = { "000", "001", "010", "011", "100", "101", "110", "111"}; From b42d42d0ac230741e65eb7d73c511eadb4cdfe1a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 21 Nov 2023 10:20:22 -0500 Subject: [PATCH 70/76] update docstring --- .../core/src/measurements/MeasurementsBase.hpp | 3 +-- .../lightning_gpu/measurements/MeasurementsGPU.hpp | 14 +++++++------- .../measurements/MeasurementsGPUMPI.hpp | 10 +++++----- .../measurements/MeasurementsKokkos.hpp | 10 +++++----- .../measurements/MeasurementsLQubit.hpp | 10 +++++----- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 0b29fa3b84..373be05ea3 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -273,10 +273,9 @@ template class MeasurementsBase { } /** - * @brief Probability of each computational basis state for an observable. + * @brief Probabilities of each computational basis state for an observable. * * @param obs An observable object. - * @param num_shots Number of shots used to generate samples * * @return Floating point std::vector with probabilities. * The basis columns are rearranged according to wires. 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 cc6651b0a0..e994879222 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -154,9 +154,9 @@ class Measurements final } /** - * @brief Probabilities of each computational basis state. + * @brief Probability of each computational basis state for an observable. * - * @param obs Observable + * @param obs An observable object. * * @return Floating point std::vector with probabilities * in lexicographic order. @@ -476,9 +476,9 @@ class Measurements final } /** - * @brief Calculate variance of a general Observable. + * @brief Calculate variance of a general observable. * - * @param ob Observable. + * @param ob An observable object. * @return Variance with respect to the given observable. */ auto var(const Observable &ob) -> PrecisionT { @@ -644,12 +644,12 @@ class Measurements final }; /** - * @brief Expectation value for a Observable with shots + * @brief Calculate the variance for an observable with the number of shots. * - * @param obs Observable + * @param obs An observable object. * @param num_shots Number of shots. * - * @return Floating point expected value of the observable. + * @return Variance of the given observable. */ auto var(const Observable &obs, const size_t &num_shots) diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp index 96d8d46712..ab6c3cc5e9 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp @@ -210,9 +210,9 @@ class MeasurementsMPI final } /** - * @brief Probabilities of each computational basis state. + * @brief Probabilities of each computational basis state for an observable. * - * @param obs Observable + * @param obs An observable object. * * @return Floating point std::vector with probabilities * in lexicographic order. @@ -748,12 +748,12 @@ class MeasurementsMPI final }; /** - * @brief Expectation value for a Observable with shots + * @brief Calculate the variance for an observable with the number of shots. * - * @param obs Observable + * @param obs An observable object. * @param num_shots Number of shots. * - * @return Floating point expected value of the observable. + * @return Variance of the given observable. */ auto var(const Observable &obs, const size_t &num_shots) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp index 9989bf77f6..e6cd27fedb 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp @@ -458,12 +458,12 @@ class Measurements final }; /** - * @brief Expectation value for a Observable with shots + * @brief Calculate the variance for an observable with the number of shots. * - * @param obs Observable + * @param obs An observable object. * @param num_shots Number of shots. * - * @return Floating point expected value of the observable. + * @return Variance of the given observable. */ auto var(const Observable &obs, const size_t &num_shots) @@ -607,9 +607,9 @@ class Measurements final } /** - * @brief Probabilities of each computational basis state. + * @brief Probabilities of each computational basis state for an observable. * - * @param obs Observable + * @param obs An observable object. * * @return Floating point std::vector with probabilities * in lexicographic order. 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 c8a1969062..685d8edbec 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -135,9 +135,9 @@ class Measurements final } /** - * @brief Probabilities of each computational basis state. + * @brief Probabilities of each computational basis state for an observable. * - * @param obs Observable + * @param obs An observable object. * * @return Floating point std::vector with probabilities * in lexicographic order. @@ -295,12 +295,12 @@ class Measurements final } /** - * @brief Expectation value for a Observable with shots + * @brief Calculate the variance for an observable with the number of shots. * - * @param obs Observable + * @param obs An observable object. * @param num_shots Number of shots. * - * @return Floating point expected value of the observable. + * @return Variance of the given observable. */ auto var(const Observable &obs, const size_t &num_shots) From 674dc8cb2c4ddb661aa85ab3709e8917fffd3c70 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 21 Nov 2023 10:33:02 -0500 Subject: [PATCH 71/76] fix typo --- .../core/src/measurements/tests/Test_MeasurementsBase.cpp | 4 ++-- .../src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp | 4 ++-- .../simulators/lightning_gpu/measurements/MeasurementsGPU.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index fb5980c595..e280dd59a5 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -1028,6 +1028,7 @@ template void testSamplesCountsObs() { found = true; } + // keys in the map should be found in expected_keys REQUIRE(found == true); size_t idx = 0; @@ -1042,6 +1043,7 @@ template void testSamplesCountsObs() { idx++; } for (auto &bit : localBits) { + // bit values should be either 0 or 1 REQUIRE(bit * (bit - 1) == 0); } counts[decimal_idx] = it.second; @@ -1127,8 +1129,6 @@ TEST_CASE("Expval Shot - HamiltonianObs ", "[MeasurementsBase][Observables]") { template void testHamiltonianObsVarShot() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; - // using PrecisionT = typename StateVectorT::PrecisionT; - // using ComplexT = typename StateVectorT::ComplexT; // Defining the State Vector that will be measured. auto statevector_data = createNonTrivialState(); diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index 57e4730413..29b03af80a 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -1293,7 +1293,7 @@ template void testSamplesCountsObs() { if (iter != expected_keys.end()) { found = true; } - + // keys in the map should be found in expected_keys REQUIRE(found == true); size_t idx = 0; @@ -1308,6 +1308,7 @@ template void testSamplesCountsObs() { idx++; } for (auto &bit : localBits) { + // bit values should be either 0 or 1 REQUIRE(bit * (bit - 1) == 0); } counts[decimal_idx] = it.second; @@ -1341,7 +1342,6 @@ template void testHamiltonianObsVarShot() { auto statevector_data = createNonTrivialState>(); - // Defining the State Vector that will be measured. size_t num_qubits = 3; MPIManager mpi_manager(MPI_COMM_WORLD); 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 e994879222..05f52c99ed 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -154,7 +154,7 @@ class Measurements final } /** - * @brief Probability of each computational basis state for an observable. + * @brief Probabilities of each computational basis state for an observable. * * @param obs An observable object. * From 3f70c2abd900427118b34b0d689df2fa04141d5e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 24 Nov 2023 16:15:39 -0500 Subject: [PATCH 72/76] update return type of counts & tidy up code --- .../src/measurements/MeasurementsBase.hpp | 18 +++++------ .../tests/Test_MeasurementsBase.cpp | 30 +------------------ .../tests/mpi/Test_MeasurementsBaseMPI.cpp | 30 +------------------ 3 files changed, 9 insertions(+), 69 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 373be05ea3..f315d8181c 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -337,7 +337,6 @@ template class MeasurementsBase { auto counts(const Observable &obs, const size_t &num_shots) -> std::unordered_map { std::unordered_map outcome_map; - std::vector shot_range = {}; auto sample_data = sample(obs, num_shots); for (size_t i = 0; i < num_shots; i++) { auto key = sample_data[i]; @@ -357,15 +356,12 @@ template class MeasurementsBase { * * @param num_shots number of wires the sampled observable was performed on * - * @return std::unordered_map with format ``{'outcome': + * @return std::unordered_map with format ``{'outcome': * num_occurences}`` */ - auto counts(const size_t &num_shots) - -> std::unordered_map { - std::unordered_map outcome_map; - - Derived measure(_statevector); - auto sample_data = measure.generate_samples(num_shots); + auto counts(const size_t &num_shots) -> std::unordered_map { + std::unordered_map outcome_map; + auto sample_data = sample(num_shots); size_t num_wires = _statevector.getTotalNumQubits(); for (size_t i = 0; i < num_shots; i++) { @@ -373,9 +369,9 @@ template class MeasurementsBase { std::vector(sample_data.begin() + i * num_wires, sample_data.begin() + (i + 1) * num_wires); - std::string key; - for (auto &element : local_sample) { - key += std::to_string(element); + size_t key = 0; + for (size_t i = 0; i < local_sample.size(); i++) { + key += local_sample[i] << (local_sample.size() - 1 - i); } auto it = outcome_map.find(key); diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index e280dd59a5..62827198c9 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -1016,37 +1016,9 @@ template void testSamplesCountsObs() { // convert samples to decimal and then bin them in counts for (auto &it : counts_sample) { - std::vector localBits(num_qubits, 10); auto key = it.first; - bool found = false; - - auto iter = - std::find(expected_keys.begin(), expected_keys.end(), key); - - if (iter != expected_keys.end()) { - found = true; - } - - // keys in the map should be found in expected_keys - REQUIRE(found == true); - - size_t idx = 0; - size_t decimal_idx = 0; - for (char &c : key) { - if (c == '1') { - localBits[idx] = 1; - decimal_idx += twos[(num_qubits - 1 - idx)]; - } else if (c == '0') { - localBits[idx] = 0; - } - idx++; - } - for (auto &bit : localBits) { - // bit values should be either 0 or 1 - REQUIRE(bit * (bit - 1) == 0); - } - counts[decimal_idx] = it.second; + counts[key] = it.second; } // compute estimated probabilities from histogram diff --git a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp index 29b03af80a..babdcc19d0 100644 --- a/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp +++ b/pennylane_lightning/core/src/measurements/tests/mpi/Test_MeasurementsBaseMPI.cpp @@ -1282,36 +1282,8 @@ template void testSamplesCountsObs() { // convert samples to decimal and then bin them in counts for (auto &it : counts_sample) { - std::vector localBits(num_qubits, 10); auto key = it.first; - - bool found = false; - - auto iter = - std::find(expected_keys.begin(), expected_keys.end(), key); - - if (iter != expected_keys.end()) { - found = true; - } - // keys in the map should be found in expected_keys - REQUIRE(found == true); - - size_t idx = 0; - size_t decimal_idx = 0; - for (char &c : key) { - if (c == '1') { - localBits[idx] = 1; - decimal_idx += twos[(num_qubits - 1 - idx)]; - } else if (c == '0') { - localBits[idx] = 0; - } - idx++; - } - for (auto &bit : localBits) { - // bit values should be either 0 or 1 - REQUIRE(bit * (bit - 1) == 0); - } - counts[decimal_idx] = it.second; + counts[key] = it.second; } // compute estimated probabilities from histogram From 70b208d6c245c9ea682f4bcf765f2f17fa141612 Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Fri, 24 Nov 2023 21:45:50 +0000 Subject: [PATCH 73/76] 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 1038a32aa1..beda02daad 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.34.0-dev10" +__version__ = "0.34.0-dev11" From 20366b941bd4a582099adc024d0da3921cb9f8cf Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 24 Nov 2023 17:55:00 -0500 Subject: [PATCH 74/76] update brief of probs(obs) --- pennylane_lightning/core/src/measurements/MeasurementsBase.hpp | 2 +- .../simulators/lightning_gpu/measurements/MeasurementsGPU.hpp | 2 +- .../lightning_gpu/measurements/MeasurementsGPUMPI.hpp | 2 +- .../lightning_kokkos/measurements/MeasurementsKokkos.hpp | 2 +- .../lightning_qubit/measurements/MeasurementsLQubit.hpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index f315d8181c..137df084f3 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -273,7 +273,7 @@ template class MeasurementsBase { } /** - * @brief Probabilities of each computational basis state for an observable. + * @brief Probabilities to measure rotated basis states. * * @param obs An observable object. * 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 05f52c99ed..3fb62f0d2f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -154,7 +154,7 @@ class Measurements final } /** - * @brief Probabilities of each computational basis state for an observable. + * @brief Probabilities to measure rotated basis states. * * @param obs An observable object. * diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp index ab6c3cc5e9..4cc4747248 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPUMPI.hpp @@ -210,7 +210,7 @@ class MeasurementsMPI final } /** - * @brief Probabilities of each computational basis state for an observable. + * @brief Probabilities to measure rotated basis states. * * @param obs An observable object. * diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp index e6cd27fedb..dd6ab8ba3c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/measurements/MeasurementsKokkos.hpp @@ -472,7 +472,7 @@ class Measurements final } /** - * @brief Probabilities of each computational basis state. + * @brief Probabilities to measure rotated basis states. * * @return Floating point std::vector with probabilities * in lexicographic order. 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 685d8edbec..b3edc4c23b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/measurements/MeasurementsLQubit.hpp @@ -135,7 +135,7 @@ class Measurements final } /** - * @brief Probabilities of each computational basis state for an observable. + * @brief Probabilities to measure rotated basis states. * * @param obs An observable object. * From 7101e5f56028d4438b747fcc76af767ecd2388c2 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 28 Nov 2023 14:59:32 -0500 Subject: [PATCH 75/76] update based on comments --- .../core/src/measurements/MeasurementsBase.hpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index 137df084f3..f83586136b 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -297,7 +297,7 @@ template class MeasurementsBase { * @param obs The observable object to sample * @param num_shots Number of shots used to generate samples * - * @return samples of eigenvalues of the observable + * @return Samples of eigenvalues of the observable */ auto sample(const Observable &obs, const size_t &num_shots) -> std::vector { @@ -317,7 +317,7 @@ template class MeasurementsBase { * * @param num_shots Number of shots used to generate samples * - * @return the raw basis state samples + * @return Raw basis state samples */ auto sample(const size_t &num_shots) -> std::vector { Derived measure(_statevector); @@ -329,7 +329,7 @@ template class MeasurementsBase { * number of occurences for each possible outcome with the number of shots. * * @param obs The observable to sample - * @param num_shots number of wires the sampled observable was performed on + * @param num_shots Number of wires the sampled observable was performed on * * @return std::unordered_map with format * ``{'EigenValue': num_occurences}`` @@ -354,7 +354,7 @@ template class MeasurementsBase { * @brief Groups the samples into a dictionary showing number of occurences * for each possible outcome with the number of shots. * - * @param num_shots number of wires the sampled observable was performed on + * @param num_shots Number of wires the sampled observable was performed on * * @return std::unordered_map with format ``{'outcome': * num_occurences}`` @@ -365,13 +365,9 @@ template class MeasurementsBase { size_t num_wires = _statevector.getTotalNumQubits(); for (size_t i = 0; i < num_shots; i++) { - auto local_sample = - std::vector(sample_data.begin() + i * num_wires, - sample_data.begin() + (i + 1) * num_wires); - size_t key = 0; - for (size_t i = 0; i < local_sample.size(); i++) { - key += local_sample[i] << (local_sample.size() - 1 - i); + for (size_t j = 0; j < num_wires; j++) { + key += sample_data[i * num_wires + j] << (num_wires - 1 - j); } auto it = outcome_map.find(key); From 76317e18af1906b02e63f9d9baf8cf7e88aac2ad Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 28 Nov 2023 15:01:55 -0500 Subject: [PATCH 76/76] fix typo --- pennylane_lightning/core/src/measurements/MeasurementsBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp index f83586136b..e4252cd493 100644 --- a/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp +++ b/pennylane_lightning/core/src/measurements/MeasurementsBase.hpp @@ -325,7 +325,7 @@ template class MeasurementsBase { } /** - * @brief Groups the eigen values of samples into a dictionary showing + * @brief Groups the eigenvalues of samples into a dictionary showing * number of occurences for each possible outcome with the number of shots. * * @param obs The observable to sample