From 9a0604aaa0641642d0410fac2c21263fae4e68bf Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 16 Jul 2024 20:36:16 +0000 Subject: [PATCH 001/227] init commit --- .../measurements/MeasurementsTNCuda.hpp | 40 ++++- .../tncuda/measurements/tests/CMakeLists.txt | 3 +- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 153 ++++++++++++++++++ .../src/utils/cuda_utils/cuGates_host.hpp | 12 +- 4 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 9a28a757c3..c6d78d4743 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -58,6 +58,26 @@ template class MeasurementsTNCuda { explicit MeasurementsTNCuda(const TensorNetT &tensor_network) : tensor_network_(tensor_network){}; + /** + * @brief Calculate var value for a general Observable. + * + * @param obs An Observable object. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + */ + auto var(ObservableTNCuda &obs, + const int32_t numHyperSamples = 1) -> PrecisionT { + auto expectation_val = expval(obs, numHyperSamples); + + const bool val_cal = true; + auto tnObs2Operator = + ObservableTNCudaOperator(tensor_network_, obs, val_cal); + auto expectation_squared_obs = + expval_(tnObs2Operator.getTNOperator(), numHyperSamples); + + return expectation_squared_obs - expectation_val*expectation_val; + } + /** * @brief Calculate expectation value for a general Observable. * @@ -72,6 +92,24 @@ template class MeasurementsTNCuda { auto tnoperator = ObservableTNCudaOperator(tensor_network_, obs); + return expval_(tnoperator.getTNOperator(), numHyperSamples); + } + + private: + /** + * @brief Calculate expectation value for a general ObservableTNCudaOperator + * object. + * + * @param obs An ObservableTNCudaOperator object. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Expectation value with respect to the given + * ObservableTNCudaOperator object. + */ + + auto expval_(cutensornetNetworkOperator_t tnoperator, + const int32_t numHyperSamples) -> PrecisionT { ComplexT expectation_val{0.0, 0.0}; ComplexT state_norm2{0.0, 0.0}; @@ -80,7 +118,7 @@ template class MeasurementsTNCuda { PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateExpectation( /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), /* cutensornetState_t */ tensor_network_.getQuantumState(), - /* cutensornetNetworkOperator_t */ tnoperator.getTNOperator(), + /* cutensornetNetworkOperator_t */ tnoperator, /* cutensornetStateExpectation_t * */ &expectation)); PL_CUTENSORNET_IS_SUCCESS(cutensornetExpectationConfigure( diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt index 8948335406..9ed838c230 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt @@ -30,7 +30,8 @@ target_sources(${PL_BACKEND}_measurements_tests INTERFACE runner_${PL_BACKEND}_m ################################################################################ # Define targets ################################################################################ -set(TEST_SOURCES Test_MPSTNCuda_Expval.cpp) +set(TEST_SOURCES Test_MPSTNCuda_Expval.cpp + Test_MPSTNCuda_Var.cpp) add_executable(${PL_BACKEND}_measurements_test_runner ${TEST_SOURCES}) target_link_libraries(${PL_BACKEND}_measurements_test_runner PRIVATE ${PL_BACKEND}_measurements_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp new file mode 100644 index 0000000000..d51f15775d --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -0,0 +1,153 @@ +// Copyright 2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "MPSTNCuda.hpp" +#include "MeasurementsTNCuda.hpp" +#include "TNCudaGateCache.hpp" +#include "cuda_helpers.hpp" + +/// @cond DEV +namespace { +using namespace Pennylane::LightningTensor::TNCuda::Measures; +using namespace Pennylane::LightningTensor::TNCuda::Observables; +} // namespace +/// @endcond + +TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, + double) { + using TensorNetT = MPSTNCuda; + using NamedObsT = NamedObsTNCuda; + + std::size_t bondDim = GENERATE(2, 3, 4, 5); + std::size_t num_qubits = 2; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + auto measure = MeasurementsTNCuda(mps_state); + + SECTION("var(PauliX[0])") { + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.7}, {0.7}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); + auto ob = NamedObsT("PauliX", {0}); + auto res = measure.var(ob); + auto expected = TestType(0.7572222074); + CHECK(res == Approx(expected)); + } + + SECTION("var(PauliY[0])") { + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.7}, {0.7}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); + auto ob = NamedObsT("PauliY", {0}); + auto res = measure.var(ob); + auto expected = TestType(0.5849835715); + CHECK(res == Approx(expected)); + } + + SECTION("var(PauliZ[0])") { + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.7}, {0.7}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); + auto ob = NamedObsT("PauliZ", {1}); + auto res = measure.var(ob); + auto expected = TestType(0.4068672016); + CHECK(res == Approx(expected)); + } +} + +TEMPLATE_TEST_CASE("Test variance of HermitianObs", + "[MPSTNCuda_Var]", float, double) { + using TensorNetT = MPSTNCuda; + using ComplexT = typename TensorNetT::ComplexT; + using HermitianObsT = HermitianObsTNCuda; + + + std::size_t bondDim = GENERATE(2, 3, 4, 5); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + auto measure = MeasurementsTNCuda(mps_state); + + SECTION("Using var") { + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}, {"RX"}, {"RY"}}, + {{0}, {0}, {1}, {1}, {2}, {2}}, + {{false}, {false}, {false}, {false}, {false}, {false}}, + {{0.7}, {0.7}, {0.5}, {0.5}, {0.3}, {0.3}}); + + const TestType theta = M_PI / 2; + const TestType c = std::cos(theta / 2); + const TestType js = std::sin(-theta / 2); + std::vector matrix(16, 0); + matrix[0] = c; + matrix[1] = ComplexT{0, js}; + matrix[4] = ComplexT{0, js}; + matrix[5] = c; + matrix[10] = ComplexT{1, 0}; + matrix[15] = ComplexT{1, 0}; + + auto ob = HermitianObsT(matrix, {0, 2}); + auto res = measure.var(ob); + auto expected = TestType(0.4103533486); + CHECK(res == Approx(expected)); + } +} + +TEMPLATE_TEST_CASE("Test variance of TensorProdObs", + "[MPSTNCuda_Var]", float, double) { + using TensorNetT = MPSTNCuda; + using NamedObsT = NamedObsTNCuda; + using TensorProdObsT = TensorProdObsTNCuda; + + std::size_t bondDim = GENERATE(2, 3, 4, 5); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + auto measure = MeasurementsTNCuda(mps_state); + + SECTION("Using var") { + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto X0 = std::make_shared( + "PauliX", std::vector{0}); + auto Z1 = std::make_shared( + "PauliZ", std::vector{1}); + + auto ob = TensorProdObsT::create({X0, Z1}); + auto res = measure.var(*ob); + auto expected = TestType(0.836679); + CHECK(expected == Approx(res)); + } +} diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp index 95b3b21fbb..1c4ddd4831 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp @@ -1542,7 +1542,17 @@ template class DynamicGateDataAccess { {"CY", []() -> std::vector { return cuGates::getCY(); }}, {"CZ", []() -> std::vector { return cuGates::getCZ(); }}, {"CSWAP", - []() -> std::vector { return cuGates::getCSWAP(); }}}; + []() -> std::vector { return cuGates::getCSWAP(); }}, + {"Identity_squared", + []() -> std::vector { return cuGates::getIdentity(); }}, + {"PauliX_squared", + []() -> std::vector { return cuGates::getIdentity(); }}, + {"PauliY_squared", + []() -> std::vector { return cuGates::getIdentity(); }}, + {"PauliZ_squared", + []() -> std::vector { return cuGates::getIdentity(); }}, + {"Hadamard_squared", + []() -> std::vector { return cuGates::getIdentity(); }}}; // TODO: Need changes to support to the controlled gate tensor API once the // API is finalized in cutensornet lib. From a3059ff9cbd5d5f66d4ac361aa6bb026973f2071 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 16 Jul 2024 20:38:48 +0000 Subject: [PATCH 002/227] make format --- .../measurements/MeasurementsTNCuda.hpp | 2 +- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index c6d78d4743..b5c4b3888c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -75,7 +75,7 @@ template class MeasurementsTNCuda { auto expectation_squared_obs = expval_(tnObs2Operator.getTNOperator(), numHyperSamples); - return expectation_squared_obs - expectation_val*expectation_val; + return expectation_squared_obs - expectation_val * expectation_val; } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index d51f15775d..60f15b49ee 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -81,13 +81,12 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, } } -TEMPLATE_TEST_CASE("Test variance of HermitianObs", - "[MPSTNCuda_Var]", float, double) { +TEMPLATE_TEST_CASE("Test variance of HermitianObs", "[MPSTNCuda_Var]", float, + double) { using TensorNetT = MPSTNCuda; using ComplexT = typename TensorNetT::ComplexT; using HermitianObsT = HermitianObsTNCuda; - std::size_t bondDim = GENERATE(2, 3, 4, 5); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -121,12 +120,12 @@ TEMPLATE_TEST_CASE("Test variance of HermitianObs", } } -TEMPLATE_TEST_CASE("Test variance of TensorProdObs", - "[MPSTNCuda_Var]", float, double) { +TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, + double) { using TensorNetT = MPSTNCuda; using NamedObsT = NamedObsTNCuda; using TensorProdObsT = TensorProdObsTNCuda; - + std::size_t bondDim = GENERATE(2, 3, 4, 5); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -140,10 +139,10 @@ TEMPLATE_TEST_CASE("Test variance of TensorProdObs", {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - auto X0 = std::make_shared( - "PauliX", std::vector{0}); - auto Z1 = std::make_shared( - "PauliZ", std::vector{1}); + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto Z1 = + std::make_shared("PauliZ", std::vector{1}); auto ob = TensorProdObsT::create({X0, Z1}); auto res = measure.var(*ob); From 9e83c44719ec4eb8ee31eb2e914be6dec530d819 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 17 Jul 2024 17:14:50 +0000 Subject: [PATCH 003/227] add unit tests for HermitianObs --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 58 ++++++--- .../tncuda/observables/ObservablesTNCuda.hpp | 1 + .../observables/ObservablesTNCudaOperator.hpp | 113 +++++++++++++++++- .../core/src/utils/cuda_utils/LinearAlg.hpp | 29 +++++ 4 files changed, 182 insertions(+), 19 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 60f15b49ee..0b66807d6a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -95,31 +95,25 @@ TEMPLATE_TEST_CASE("Test variance of HermitianObs", "[MPSTNCuda_Var]", float, auto measure = MeasurementsTNCuda(mps_state); - SECTION("Using var") { - mps_state.applyOperations( + mps_state.applyOperations( {{"RX"}, {"RY"}, {"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}, {2}, {2}}, {{false}, {false}, {false}, {false}, {false}, {false}}, {{0.7}, {0.7}, {0.5}, {0.5}, {0.3}, {0.3}}); + mps_state.append_mps_final_state(); + + SECTION("Target at 1 wire") { + std::vector matrix= { + {2.5, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {3.8, 0.0}}; - const TestType theta = M_PI / 2; - const TestType c = std::cos(theta / 2); - const TestType js = std::sin(-theta / 2); - std::vector matrix(16, 0); - matrix[0] = c; - matrix[1] = ComplexT{0, js}; - matrix[4] = ComplexT{0, js}; - matrix[5] = c; - matrix[10] = ComplexT{1, 0}; - matrix[15] = ComplexT{1, 0}; - - auto ob = HermitianObsT(matrix, {0, 2}); + auto ob = HermitianObsT(matrix, {0}); auto res = measure.var(ob); - auto expected = TestType(0.4103533486); + auto expected = TestType(0.2779180584);//from default.qubit CHECK(res == Approx(expected)); } } + TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, double) { using TensorNetT = MPSTNCuda; @@ -138,6 +132,8 @@ TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, mps_state.applyOperations( {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + mps_state.append_mps_final_state(); auto X0 = std::make_shared("PauliX", std::vector{0}); @@ -150,3 +146,35 @@ TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, CHECK(expected == Approx(res)); } } + +TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", + "[MPSTNCuda_Var]", float, double) { + using TensorNetT = MPSTNCuda; + using NamedObsT = NamedObsTNCuda; + using TensorProdObsT = TensorProdObsTNCuda; + using HamiltonianObsT = HamiltonianTNCuda; + SECTION("Using XZ") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto Z1 = + std::make_shared("PauliZ", std::vector{1}); + + auto ob_term = TensorProdObsT::create({X0, Z1}); + + auto ob = HamiltonianObsT::create({TestType{0.5}}, {ob_term}); + auto res = m.var(*ob); + CHECK(res == Approx(0.836679*0.25)); + } +} \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp index 3db2825e7b..446582db8f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp @@ -241,6 +241,7 @@ class HermitianObsTNCuda : public ObservableTNCuda { */ HermitianObsTNCuda(MatrixT matrix, std::vector wires) : matrix_{std::move(matrix)}, wires_{std::move(wires)} { + //PL_ABORT_IF(wires_.size() != 1, "Number of Hermitian target wires must be 1."); PL_ASSERT(matrix_.size() == Pennylane::Util::exp2(2 * wires_.size())); BaseType::coeffs_.emplace_back(PrecisionT{1.0}); BaseType::numTensors_.emplace_back(std::size_t{1}); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 3ceeae4e01..45ed617291 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -18,6 +18,7 @@ #include #include +#include "LinearAlg.hpp" #include "ObservablesTNCuda.hpp" #include "TensorCuda.hpp" #include "Util.hpp" @@ -65,6 +66,7 @@ template class ObservableTNCudaOperator { std::tuple, std::size_t>; private: + SharedCublasCaller cublascaller_; cutensornetNetworkOperator_t obsOperator_{ nullptr}; // cutensornetNetworkOperator operator @@ -87,6 +89,8 @@ template class ObservableTNCudaOperator { std::vector ids_; // ids for each term in the graph + const bool var_cal_ = false; + private: /** * @brief Hasher for observable key. @@ -243,8 +247,108 @@ template class ObservableTNCudaOperator { tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); - appendTNOperator_(coeff, numTensors, numModes_.back().data(), - modesPtr_.back().data(), + appendTNOperator_(obsOperator_, coeff, numTensors, + numModes_.back().data(), modesPtr_.back().data(), + tensorDataPtr_.back().data()); + } + } + + ObservableTNCudaOperator(const TensorNetT &tensor_network, + ObservableTNCuda &obs, + const bool var_cal) + : cublascaller_(make_shared_cublas_caller()), + tensor_network_{tensor_network}, + numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { + PL_ABORT_IF(var_cal == false, + "var_cal should be true for this constructor"); + PL_ABORT_IF_NOT( + numObsTerms_ == 1, + "Only one observable term is allowed for variance calculation"); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateNetworkOperator( + /* const cutensornetHandle_t */ tensor_network.getTNCudaHandle(), + /* int32_t */ static_cast(tensor_network.getNumQubits()), + /* const int64_t stateModeExtents */ + reinterpret_cast(const_cast( + tensor_network.getQubitDims().data())), + /* cudaDataType_t */ tensor_network.getCudaDataType(), + /* cutensornetNetworkOperator_t */ &obsOperator_)); + + numTensors_ = obs.getNumTensors(); // number of tensors in each term + + for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { + auto coeff = cuDoubleComplex{ + static_cast(obs.getCoeffs()[term_idx]*obs.getCoeffs()[term_idx]), 0.0}; + auto numTensors = numTensors_[term_idx]; + + coeffs_.emplace_back(coeff); + + // number of state modes of each tensor in each term + numModes_.emplace_back(cast_vector( + obs.getNumStateModes()[term_idx])); + + // modes initialization + vector2D modes_per_term; + for (std::size_t tensor_idx = 0; tensor_idx < numTensors; + tensor_idx++) { + modes_per_term.emplace_back( + cuUtil::NormalizeCastIndices( + obs.getStateModes()[term_idx][tensor_idx], + tensor_network.getNumQubits())); + } + modes_.emplace_back(modes_per_term); + + // modes pointer initialization + vector1D modesPtrPerTerm; + for (std::size_t tensor_idx = 0; tensor_idx < modes_.back().size(); + tensor_idx++) { + modesPtrPerTerm.emplace_back(modes_.back()[tensor_idx].data()); + } + modesPtr_.emplace_back(modesPtrPerTerm); + + // tensor data initialization + vector1D tensorDataPtrPerTerm_; + for (std::size_t tensor_idx = 0; tensor_idx < numTensors; + tensor_idx++) { + auto metaData = obs.getMetaData()[term_idx][tensor_idx]; + + auto obsName = std::get<0>(metaData); + auto param = std::get<1>(metaData); + auto hermitianMatrix = std::get<2>(metaData); + std::size_t hash_val = 0; + + if (!hermitianMatrix.empty()) { + hash_val = MatrixHasher()(hermitianMatrix); + } + auto obs2Name = obsName + "_squared"; + auto obs2Key = std::make_tuple(obs2Name, param, hash_val); + if (device_obs_cache_.find(obs2Key) == + device_obs_cache_.end()) { + if (hermitianMatrix.empty()) { + add_obs_(obs2Name, param); + } else { + auto hermitianMatrix_cu = + cuUtil::complexToCu(hermitianMatrix); + + add_obs_(obs2Key, hermitianMatrix_cu); + + square_matrix_CUDA_device( + const_cast(get_obs_device_ptr_(obs2Key)), + Pennylane::Util::log2(hermitianMatrix_cu.size()), + Pennylane::Util::log2(hermitianMatrix_cu.size()), + tensor_network_.getDevTag().getDeviceID(), + tensor_network_.getDevTag().getStreamID(), + *cublascaller_); + } + } + tensorDataPtrPerTerm_.emplace_back( + get_obs_device_ptr_(obs2Key)); + } + + tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); + + appendTNOperator_(obsOperator_, coeff, numTensors, + numModes_.back().data(), modesPtr_.back().data(), tensorDataPtr_.back().data()); } } @@ -273,7 +377,8 @@ template class ObservableTNCudaOperator { * @param stateModes State modes of each tensor in the product. * @param tensorDataPtr Pointer to the data of each tensor in the product. */ - void appendTNOperator_(const cuDoubleComplex &coeff, + void appendTNOperator_(cutensornetNetworkOperator_t &tnOperator, + const cuDoubleComplex &coeff, const std::size_t numTensors, const int32_t *numStateModes, const int32_t **stateModes, @@ -281,7 +386,7 @@ template class ObservableTNCudaOperator { int64_t id; PL_CUTENSORNET_IS_SUCCESS(cutensornetNetworkOperatorAppendProduct( /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), - /* cutensornetNetworkOperator_t */ getTNOperator(), + /* cutensornetNetworkOperator_t */ tnOperator, /* cuDoubleComplex coefficient*/ coeff, /* int32_t numTensors */ static_cast(numTensors), /* const int32_t numStateModes[] */ numStateModes, diff --git a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp index 51d9970f88..b32c9a7c0c 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp @@ -80,6 +80,35 @@ class CublasCaller { cublasHandle_t handle; }; +/** + * @brief cuBLAS backed square the matrix for GPU data. + * + * @tparam T Complex data-type. Accepts cuFloatComplex and cuDoubleComplex + * @param mat Device data pointer. + * @param row_size Size of the matrix row. + * @param col_size Size of the matrix column. + * @param dev_id the device on which the function should be executed. + * @param stream_id the CUDA stream on which the operation should be executed. + * @param cublas the CublasCaller object that manages the cuBLAS handle. + */ +template +inline void square_matrix_CUDA_device(T *mat, const int row_size, + const int col_size, DevTypeID dev_id, + cudaStream_t stream_id, + const CublasCaller &cublas) { + const T alpha{1.0, 0.0}; + const T beta{0.0, 0.0}; + if constexpr (std::is_same_v) { + cublas.call(cublasCgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, + row_size, row_size, col_size, &alpha, mat, row_size, mat, + col_size, &beta, mat, row_size); + } else if constexpr (std::is_same_v) { + cublas.call(cublasZgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, + row_size, row_size, col_size, &alpha, mat, row_size, mat, + col_size, &beta, mat, row_size); + } +} + /** * @brief cuBLAS backed inner product for GPU data. * From a92992836541e6d2a5b8488f5db7fc8b6f2b2ce5 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 15 Jul 2024 21:16:53 +0000 Subject: [PATCH 004/227] initial commit --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 818ff1b25d..727222ed34 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "../../scipy.libs/"; + scipyPathStr = currentPathStr + "/../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From 3af11ac9822ca593983ff09749b01fdf042da98b Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 17 Jul 2024 18:18:59 +0000 Subject: [PATCH 005/227] Auto update version from '0.38.0-dev9' to '0.38.0-dev10' --- 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 0ddab39d02..76b178d200 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.38.0-dev9" +__version__ = "0.38.0-dev10" From 425126b9632d001a54a4a25752ad380a8aff1a42 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 17 Jul 2024 18:21:36 +0000 Subject: [PATCH 006/227] make format --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 21 +++++++++---------- .../tncuda/observables/ObservablesTNCuda.hpp | 3 ++- .../observables/ObservablesTNCudaOperator.hpp | 6 ++++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 0b66807d6a..45bb94aad4 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -96,24 +96,23 @@ TEMPLATE_TEST_CASE("Test variance of HermitianObs", "[MPSTNCuda_Var]", float, auto measure = MeasurementsTNCuda(mps_state); mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}, {"RX"}, {"RY"}}, - {{0}, {0}, {1}, {1}, {2}, {2}}, - {{false}, {false}, {false}, {false}, {false}, {false}}, - {{0.7}, {0.7}, {0.5}, {0.5}, {0.3}, {0.3}}); + {{"RX"}, {"RY"}, {"RX"}, {"RY"}, {"RX"}, {"RY"}}, + {{0}, {0}, {1}, {1}, {2}, {2}}, + {{false}, {false}, {false}, {false}, {false}, {false}}, + {{0.7}, {0.7}, {0.5}, {0.5}, {0.3}, {0.3}}); mps_state.append_mps_final_state(); SECTION("Target at 1 wire") { - std::vector matrix= { + std::vector matrix = { {2.5, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {3.8, 0.0}}; auto ob = HermitianObsT(matrix, {0}); auto res = measure.var(ob); - auto expected = TestType(0.2779180584);//from default.qubit + auto expected = TestType(0.2779180584); // from default.qubit CHECK(res == Approx(expected)); } } - TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, double) { using TensorNetT = MPSTNCuda; @@ -132,7 +131,7 @@ TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, mps_state.applyOperations( {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - + mps_state.append_mps_final_state(); auto X0 = @@ -147,8 +146,8 @@ TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, } } -TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", - "[MPSTNCuda_Var]", float, double) { +TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, + double) { using TensorNetT = MPSTNCuda; using NamedObsT = NamedObsTNCuda; using TensorProdObsT = TensorProdObsTNCuda; @@ -175,6 +174,6 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", auto ob = HamiltonianObsT::create({TestType{0.5}}, {ob_term}); auto res = m.var(*ob); - CHECK(res == Approx(0.836679*0.25)); + CHECK(res == Approx(0.836679 * 0.25)); } } \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp index 446582db8f..4d9ce89667 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCuda.hpp @@ -241,7 +241,8 @@ class HermitianObsTNCuda : public ObservableTNCuda { */ HermitianObsTNCuda(MatrixT matrix, std::vector wires) : matrix_{std::move(matrix)}, wires_{std::move(wires)} { - //PL_ABORT_IF(wires_.size() != 1, "Number of Hermitian target wires must be 1."); + // PL_ABORT_IF(wires_.size() != 1, "Number of Hermitian target wires + // must be 1."); PL_ASSERT(matrix_.size() == Pennylane::Util::exp2(2 * wires_.size())); BaseType::coeffs_.emplace_back(PrecisionT{1.0}); BaseType::numTensors_.emplace_back(std::size_t{1}); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 45ed617291..0cf330e042 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -277,8 +277,10 @@ template class ObservableTNCudaOperator { numTensors_ = obs.getNumTensors(); // number of tensors in each term for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { - auto coeff = cuDoubleComplex{ - static_cast(obs.getCoeffs()[term_idx]*obs.getCoeffs()[term_idx]), 0.0}; + auto coeff = + cuDoubleComplex{static_cast(obs.getCoeffs()[term_idx] * + obs.getCoeffs()[term_idx]), + 0.0}; auto numTensors = numTensors_[term_idx]; coeffs_.emplace_back(coeff); From 99c3b9eba687f4ea1b385d46985e980cff3f0f72 Mon Sep 17 00:00:00 2001 From: Shuli Shu <31480676+multiphaseCFD@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:19:05 -0400 Subject: [PATCH 007/227] Add GPU device compute capability check for LTensor (#803) ### Before submitting Please complete the following checklist when submitting a PR: - [ ] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [ ] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [ ] Ensure that the test suite passes, by running `make test`. - [x] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [x] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** Add GPU device compute capability check. L-Tensor has device compute capability check like L-GPU now. [SC-69118] **Description of the Change:** **Benefits:** Error will be raised when running `lightning.tensor` on a unsupported GPU. **Possible Drawbacks:** **Related GitHub Issues:** https://github.com/PennyLaneAI/pennylane-lightning/issues/799 --------- Co-authored-by: ringo-but-quantum --- .github/CHANGELOG.md | 3 +++ pennylane_lightning/lightning_tensor/lightning_tensor.py | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 7411cd98f2..f9b61fa81f 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -15,6 +15,9 @@ ### Improvements +* Add GPU device compute capability check for Lightning-Tensor. + [(#803)](https://github.com/PennyLaneAI/pennylane-lightning/pull/803) + * Refactor CUDA utils Python bindings to a separate module. [(#801)](https://github.com/PennyLaneAI/pennylane-lightning/pull/801) diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 8862604677..a7212e58d5 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -39,7 +39,14 @@ try: # pylint: disable=import-error, unused-import - from pennylane_lightning.lightning_tensor_ops import backend_info + from pennylane_lightning.lightning_tensor_ops import ( + backend_info, + get_gpu_arch, + is_gpu_supported, + ) + + if not is_gpu_supported(): # pragma: no cover + raise ValueError(f"CUDA device is an unsupported version: {get_gpu_arch()}") LT_CPP_BINARY_AVAILABLE = True except ImportError: From 6da1e254ba98848e61a80aa73c69de284e5284fc Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 17 Jul 2024 18:41:55 +0000 Subject: [PATCH 008/227] Auto update version from '0.38.0-dev10' to '0.38.0-dev11' --- 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 76b178d200..2aa597931d 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.38.0-dev10" +__version__ = "0.38.0-dev11" From 3877ebf067a3ffec2fbb2556769421e7ad918f7f Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 18 Jul 2024 02:51:22 +0000 Subject: [PATCH 009/227] Auto update version from '0.38.0-dev11' to '0.38.0-dev12' --- 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 2aa597931d..52575c8282 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.38.0-dev11" +__version__ = "0.38.0-dev12" From 1b127338c30c3ed3cc8087f4e6f8a3ae4a5b6dfa Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 15:55:18 +0000 Subject: [PATCH 010/227] make format --- .../tncuda/measurements/MeasurementsTNCuda.hpp | 8 +++++++- .../tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp | 2 +- .../tncuda/observables/ObservablesTNCudaOperator.hpp | 1 + pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index b5c4b3888c..912d92a297 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -61,13 +61,19 @@ template class MeasurementsTNCuda { /** * @brief Calculate var value for a general Observable. * + * Current implementation ensure that only one cutensornetNetworkOperator_t + * object is attached to the circuit. + * * @param obs An Observable object. * @param numHyperSamples Number of hyper samples to use in the calculation * and is default as 1. */ auto var(ObservableTNCuda &obs, const int32_t numHyperSamples = 1) -> PrecisionT { - auto expectation_val = expval(obs, numHyperSamples); + auto expectation_val = + expval(obs, numHyperSamples); // The cutensornetNetworkOperator_t + // object created in expval() will be + // released after the function call. const bool val_cal = true; auto tnObs2Operator = diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 45bb94aad4..3c1307c90a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -176,4 +176,4 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto res = m.var(*ob); CHECK(res == Approx(0.836679 * 0.25)); } -} \ No newline at end of file +} diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 0cf330e042..28c61f60c1 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -253,6 +253,7 @@ template class ObservableTNCudaOperator { } } + // ObservableTNCudaOperator ctor specifically for variance calculation. ObservableTNCudaOperator(const TensorNetT &tensor_network, ObservableTNCuda &obs, const bool var_cal) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 727222ed34..818ff1b25d 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "/../../scipy.libs/"; + scipyPathStr = currentPathStr + "../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From afa67c9be606b25b75fccf24c036b1dfcab3ee94 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 16:00:33 +0000 Subject: [PATCH 011/227] add more complex Hermitian matrix --- .../tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 3c1307c90a..4416d885db 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -104,11 +104,11 @@ TEMPLATE_TEST_CASE("Test variance of HermitianObs", "[MPSTNCuda_Var]", float, SECTION("Target at 1 wire") { std::vector matrix = { - {2.5, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {3.8, 0.0}}; + {2.5, 0.0}, {1.0, 1.0}, {1.0, -1.0}, {3.8, 0.0}}; auto ob = HermitianObsT(matrix, {0}); auto res = measure.var(ob); - auto expected = TestType(0.2779180584); // from default.qubit + auto expected = TestType(1.8499002205); // from default.qubit CHECK(res == Approx(expected)); } } From 49e529f711072d79ce3d0f04e2d2f5c9d58550ea Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 17:03:24 +0000 Subject: [PATCH 012/227] add python and pybind layer --- .../core/src/bindings/Bindings.hpp | 19 ++++++++---- .../lightning_tensor/_measurements.py | 29 ++++++++++++++++++- tests/test_measurements.py | 4 --- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/pennylane_lightning/core/src/bindings/Bindings.hpp b/pennylane_lightning/core/src/bindings/Bindings.hpp index fe72f1bb86..f1b7acf167 100644 --- a/pennylane_lightning/core/src/bindings/Bindings.hpp +++ b/pennylane_lightning/core/src/bindings/Bindings.hpp @@ -727,12 +727,19 @@ template void registerLightningTensorBackendAgnosticMeasurements(PyClass &pyclass) { using MeasurementsT = MeasurementsTNCuda; using ObservableT = ObservableTNCuda; - pyclass.def( - "expval", - [](MeasurementsT &M, const std::shared_ptr &ob) { - return M.expval(*ob); - }, - "Expected value of an observable object."); + pyclass + .def( + "expval", + [](MeasurementsT &M, const std::shared_ptr &ob) { + return M.expval(*ob); + }, + "Expected value of an observable object.") + .def( + "var", + [](MeasurementsT &M, const std::shared_ptr &ob) { + return M.var(*ob); + }, + "Variance of an observable object."); } /** diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index f5149f0e61..68ee750a52 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -25,7 +25,7 @@ import numpy as np import pennylane as qml -from pennylane.measurements import ExpectationMP, MeasurementProcess, StateMeasurement +from pennylane.measurements import ExpectationMP, MeasurementProcess, StateMeasurement, VarianceMP from pennylane.tape import QuantumScript from pennylane.typing import Result, TensorLike @@ -83,6 +83,28 @@ def expval(self, measurementprocess: MeasurementProcess): )._ob(measurementprocess.obs) return self._measurement_lightning.expval(ob_serialized) + def var(self, measurementprocess: MeasurementProcess): + """Variance of the supplied observable contained in the MeasurementProcess. + + Args: + measurementprocess (StateMeasurement): measurement to apply to the state + + Returns: + Variance of the observable + """ + + if isinstance(measurementprocess.obs, qml.SparseHamiltonian): + raise NotImplementedError("Sparse Hamiltonian Observables are not supported.") + + if isinstance(measurementprocess.obs, qml.Hermitian): + if len(measurementprocess.obs.wires) > 1: + raise ValueError("The number of Hermitian observables target wires should be 1.") + + ob_serialized = QuantumScriptSerializer( + self._tensornet.device_name, self.dtype == np.complex64 + )._ob(measurementprocess.obs) + return self._measurement_lightning.var(ob_serialized) + def get_measurement_function( self, measurementprocess: MeasurementProcess ) -> Callable[[MeasurementProcess, TensorLike], TensorLike]: @@ -98,6 +120,11 @@ def get_measurement_function( if isinstance(measurementprocess, ExpectationMP): return self.expval + if isinstance(measurementprocess, VarianceMP): + # if isinstance(measurementprocess.obs, (qml.Identity, qml.Projector)): + # return self.state_diagonalizing_gates + return self.var + raise NotImplementedError( "Does not support current measurement. Only ExpectationMP measurements are supported." ) diff --git a/tests/test_measurements.py b/tests/test_measurements.py index 927354dd19..0e00a90d5d 100644 --- a/tests/test_measurements.py +++ b/tests/test_measurements.py @@ -387,10 +387,6 @@ def circuit(): circuit() -@pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support var()", -) class TestVar: """Tests for the var function""" From e97107e4484cb3800f1a6d6ab97c1530eb351c59 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 17:41:41 +0000 Subject: [PATCH 013/227] add more py unit tests --- .../lightning_tensor/test_gates_and_expval.py | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index cfeffa90fc..ee40731fe6 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -239,8 +239,8 @@ def circuit_expval(): with pytest.raises(DeviceError): circuit_expval() - def test_expval_sparseH(self): - """Test that expval is chosen for a variety of different expectation values.""" + def test_measurement_sparseH_not_supported(self): + """Test that expval/var of SparseH is not supported.""" with qml.queuing.AnnotatedQueue() as q: qml.expval(qml.SparseHamiltonian(qml.PauliX.compute_sparse_matrix(), wires=0)) @@ -250,6 +250,29 @@ def test_expval_sparseH(self): with pytest.raises(NotImplementedError, match="Sparse Hamiltonians are not supported."): m.expval(q.queue[0]) + with pytest.raises( + NotImplementedError, match="Sparse Hamiltonian Observables are not supported." + ): + m.var(q.queue[0]) + + def test_measurement_hermitian_not_supported(self): + """Test that expval/var of Hermitian with 1+ wires is not supported.""" + with qml.queuing.AnnotatedQueue() as q: + qml.expval(qml.Hermitian(np.eye(4), wires=[0, 1])) + + tensornet = LightningTensorNet(4, 10) + m = LightningTensorMeasurements(tensornet) + + with pytest.raises( + ValueError, match="The number of Hermitian observables target wires should be 1." + ): + m.expval(q.queue[0]) + + with pytest.raises( + ValueError, match="The number of Hermitian observables target wires should be 1." + ): + m.var(q.queue[0]) + def test_measurement_shot_not_supported(self): """Test shots measurement error for measure_tensor_network.""" obs = [ From 85a9bd5dc7d3dfee9579810f81ab771602f71d10 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 18:35:29 +0000 Subject: [PATCH 014/227] add more unit tests --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 24 ++++++++++++++++++- .../src/utils/cuda_utils/cuGates_host.hpp | 6 ++--- .../lightning_tensor/test_gates_and_expval.py | 18 +++++++++----- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 4416d885db..4a31afca2b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -47,6 +47,17 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, auto measure = MeasurementsTNCuda(mps_state); + SECTION("var(Identity[0])") { + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.7}, {0.7}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); + auto ob = NamedObsT("Identity", {0}); + auto res = measure.var(ob); + auto expected = TestType(0); + CHECK(res == Approx(expected).margin(1e-7)); + } + SECTION("var(PauliX[0])") { mps_state.applyOperations( {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, @@ -69,7 +80,7 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, CHECK(res == Approx(expected)); } - SECTION("var(PauliZ[0])") { + SECTION("var(PauliZ[1])") { mps_state.applyOperations( {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, {{false}, {false}, {false}, {false}}, {{0.7}, {0.7}, {0.5}, {0.5}}); @@ -79,6 +90,17 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, auto expected = TestType(0.4068672016); CHECK(res == Approx(expected)); } + + SECTION("var(Hadamard[1])") { + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.7}, {0.7}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); + auto ob = NamedObsT("Hadamard", {1}); + auto res = measure.var(ob); + auto expected = TestType(0.2908944989); + CHECK(res == Approx(expected)); + } } TEMPLATE_TEST_CASE("Test variance of HermitianObs", "[MPSTNCuda_Var]", float, diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp index 1c4ddd4831..e8ad56c1fd 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp @@ -1541,8 +1541,6 @@ template class DynamicGateDataAccess { []() -> std::vector { return cuGates::getToffoli(); }}, {"CY", []() -> std::vector { return cuGates::getCY(); }}, {"CZ", []() -> std::vector { return cuGates::getCZ(); }}, - {"CSWAP", - []() -> std::vector { return cuGates::getCSWAP(); }}, {"Identity_squared", []() -> std::vector { return cuGates::getIdentity(); }}, {"PauliX_squared", @@ -1552,7 +1550,9 @@ template class DynamicGateDataAccess { {"PauliZ_squared", []() -> std::vector { return cuGates::getIdentity(); }}, {"Hadamard_squared", - []() -> std::vector { return cuGates::getIdentity(); }}}; + []() -> std::vector { return cuGates::getIdentity(); }}, + {"CSWAP", + []() -> std::vector { return cuGates::getCSWAP(); }}}; // TODO: Need changes to support to the controlled gate tensor API once the // API is finalized in cutensornet lib. diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index ee40731fe6..a805edb272 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -241,37 +241,43 @@ def circuit_expval(): def test_measurement_sparseH_not_supported(self): """Test that expval/var of SparseH is not supported.""" - with qml.queuing.AnnotatedQueue() as q: + with qml.queuing.AnnotatedQueue() as q0: qml.expval(qml.SparseHamiltonian(qml.PauliX.compute_sparse_matrix(), wires=0)) + with qml.queuing.AnnotatedQueue() as q1: + qml.var(qml.SparseHamiltonian(qml.PauliX.compute_sparse_matrix(), wires=0)) + tensornet = LightningTensorNet(4, 10) m = LightningTensorMeasurements(tensornet) with pytest.raises(NotImplementedError, match="Sparse Hamiltonians are not supported."): - m.expval(q.queue[0]) + m.expval(q0.queue[0]) with pytest.raises( NotImplementedError, match="Sparse Hamiltonian Observables are not supported." ): - m.var(q.queue[0]) + m.var(q1.queue[0]) def test_measurement_hermitian_not_supported(self): """Test that expval/var of Hermitian with 1+ wires is not supported.""" - with qml.queuing.AnnotatedQueue() as q: + with qml.queuing.AnnotatedQueue() as q0: qml.expval(qml.Hermitian(np.eye(4), wires=[0, 1])) + with qml.queuing.AnnotatedQueue() as q1: + qml.var(qml.Hermitian(np.eye(4), wires=[0, 1])) + tensornet = LightningTensorNet(4, 10) m = LightningTensorMeasurements(tensornet) with pytest.raises( ValueError, match="The number of Hermitian observables target wires should be 1." ): - m.expval(q.queue[0]) + m.expval(q0.queue[0]) with pytest.raises( ValueError, match="The number of Hermitian observables target wires should be 1." ): - m.var(q.queue[0]) + m.var(q1.queue[0]) def test_measurement_shot_not_supported(self): """Test shots measurement error for measure_tensor_network.""" From 93ff20f32410d0fee4e18cbe9b84bc037c323159 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 19:26:12 +0000 Subject: [PATCH 015/227] add changelog --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 4ee8cd92eb..00e975541e 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add `var` support to `lightning.tensor`. + [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) + ### Breaking changes * Remove `NDpermuter.hpp` which is no longer required. From fa2c8fb5e760d334e3a2bf0401cff7a056754e95 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 19:47:47 +0000 Subject: [PATCH 016/227] tidy up C++ --- .../observables/ObservablesTNCudaOperator.hpp | 137 ++++-------------- 1 file changed, 30 insertions(+), 107 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 28c61f60c1..9a4a179256 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -172,9 +172,17 @@ template class ObservableTNCudaOperator { public: ObservableTNCudaOperator(const TensorNetT &tensor_network, - ObservableTNCuda &obs) + ObservableTNCuda &obs, + const bool var_cal = false) : tensor_network_{tensor_network}, - numObsTerms_(obs.getNumTensors().size()) { + numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { + if (var_cal) { + PL_ABORT_IF_NOT( + numObsTerms_ == 1, + "Only one observable term is allowed for variance calculation"); + cublascaller_ = make_shared_cublas_caller(); + } + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateNetworkOperator( /* const cutensornetHandle_t */ tensor_network.getTNCudaHandle(), /* int32_t */ static_cast(tensor_network.getNumQubits()), @@ -187,8 +195,11 @@ template class ObservableTNCudaOperator { numTensors_ = obs.getNumTensors(); // number of tensors in each term for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { - auto coeff = cuDoubleComplex{ - static_cast(obs.getCoeffs()[term_idx]), 0.0}; + PrecisionT coeff_real = obs.getCoeffs()[term_idx]; + if (var_cal) { + coeff_real = coeff_real * coeff_real; + } + auto coeff = cuDoubleComplex{static_cast(coeff_real), 0.0}; auto numTensors = numTensors_[term_idx]; coeffs_.emplace_back(coeff); @@ -223,6 +234,9 @@ template class ObservableTNCudaOperator { auto metaData = obs.getMetaData()[term_idx][tensor_idx]; auto obsName = std::get<0>(metaData); + if (var_cal) { + obsName = obsName + "_squared"; + } auto param = std::get<1>(metaData); auto hermitianMatrix = std::get<2>(metaData); std::size_t hash_val = 0; @@ -240,6 +254,18 @@ template class ObservableTNCudaOperator { auto hermitianMatrix_cu = cuUtil::complexToCu(hermitianMatrix); add_obs_(obsKey, hermitianMatrix_cu); + if (var_cal) { + square_matrix_CUDA_device( + const_cast( + get_obs_device_ptr_(obsKey)), + Pennylane::Util::log2( + hermitianMatrix_cu.size()), + Pennylane::Util::log2( + hermitianMatrix_cu.size()), + tensor_network_.getDevTag().getDeviceID(), + tensor_network_.getDevTag().getStreamID(), + *cublascaller_); + } } } tensorDataPtrPerTerm_.emplace_back(get_obs_device_ptr_(obsKey)); @@ -253,109 +279,6 @@ template class ObservableTNCudaOperator { } } - // ObservableTNCudaOperator ctor specifically for variance calculation. - ObservableTNCudaOperator(const TensorNetT &tensor_network, - ObservableTNCuda &obs, - const bool var_cal) - : cublascaller_(make_shared_cublas_caller()), - tensor_network_{tensor_network}, - numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { - PL_ABORT_IF(var_cal == false, - "var_cal should be true for this constructor"); - PL_ABORT_IF_NOT( - numObsTerms_ == 1, - "Only one observable term is allowed for variance calculation"); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateNetworkOperator( - /* const cutensornetHandle_t */ tensor_network.getTNCudaHandle(), - /* int32_t */ static_cast(tensor_network.getNumQubits()), - /* const int64_t stateModeExtents */ - reinterpret_cast(const_cast( - tensor_network.getQubitDims().data())), - /* cudaDataType_t */ tensor_network.getCudaDataType(), - /* cutensornetNetworkOperator_t */ &obsOperator_)); - - numTensors_ = obs.getNumTensors(); // number of tensors in each term - - for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { - auto coeff = - cuDoubleComplex{static_cast(obs.getCoeffs()[term_idx] * - obs.getCoeffs()[term_idx]), - 0.0}; - auto numTensors = numTensors_[term_idx]; - - coeffs_.emplace_back(coeff); - - // number of state modes of each tensor in each term - numModes_.emplace_back(cast_vector( - obs.getNumStateModes()[term_idx])); - - // modes initialization - vector2D modes_per_term; - for (std::size_t tensor_idx = 0; tensor_idx < numTensors; - tensor_idx++) { - modes_per_term.emplace_back( - cuUtil::NormalizeCastIndices( - obs.getStateModes()[term_idx][tensor_idx], - tensor_network.getNumQubits())); - } - modes_.emplace_back(modes_per_term); - - // modes pointer initialization - vector1D modesPtrPerTerm; - for (std::size_t tensor_idx = 0; tensor_idx < modes_.back().size(); - tensor_idx++) { - modesPtrPerTerm.emplace_back(modes_.back()[tensor_idx].data()); - } - modesPtr_.emplace_back(modesPtrPerTerm); - - // tensor data initialization - vector1D tensorDataPtrPerTerm_; - for (std::size_t tensor_idx = 0; tensor_idx < numTensors; - tensor_idx++) { - auto metaData = obs.getMetaData()[term_idx][tensor_idx]; - - auto obsName = std::get<0>(metaData); - auto param = std::get<1>(metaData); - auto hermitianMatrix = std::get<2>(metaData); - std::size_t hash_val = 0; - - if (!hermitianMatrix.empty()) { - hash_val = MatrixHasher()(hermitianMatrix); - } - auto obs2Name = obsName + "_squared"; - auto obs2Key = std::make_tuple(obs2Name, param, hash_val); - if (device_obs_cache_.find(obs2Key) == - device_obs_cache_.end()) { - if (hermitianMatrix.empty()) { - add_obs_(obs2Name, param); - } else { - auto hermitianMatrix_cu = - cuUtil::complexToCu(hermitianMatrix); - - add_obs_(obs2Key, hermitianMatrix_cu); - - square_matrix_CUDA_device( - const_cast(get_obs_device_ptr_(obs2Key)), - Pennylane::Util::log2(hermitianMatrix_cu.size()), - Pennylane::Util::log2(hermitianMatrix_cu.size()), - tensor_network_.getDevTag().getDeviceID(), - tensor_network_.getDevTag().getStreamID(), - *cublascaller_); - } - } - tensorDataPtrPerTerm_.emplace_back( - get_obs_device_ptr_(obs2Key)); - } - - tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); - - appendTNOperator_(obsOperator_, coeff, numTensors, - numModes_.back().data(), modesPtr_.back().data(), - tensorDataPtr_.back().data()); - } - } - ~ObservableTNCudaOperator() { PL_CUTENSORNET_IS_SUCCESS( cutensornetDestroyNetworkOperator(obsOperator_)); From 0cdc3d0844b8e2faf6d54715d7a96e22d9782b39 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 20:12:08 +0000 Subject: [PATCH 017/227] further clean C++ layer --- .../tncuda/measurements/MeasurementsTNCuda.hpp | 2 +- .../tncuda/observables/ObservablesTNCudaOperator.hpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 912d92a297..c1cc7143f3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -106,7 +106,7 @@ template class MeasurementsTNCuda { * @brief Calculate expectation value for a general ObservableTNCudaOperator * object. * - * @param obs An ObservableTNCudaOperator object. + * @param tnoperator An ObservableTNCudaOperator object. * @param numHyperSamples Number of hyper samples to use in the calculation * and is default as 1. * diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 9a4a179256..dfc7027442 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -273,8 +273,8 @@ template class ObservableTNCudaOperator { tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); - appendTNOperator_(obsOperator_, coeff, numTensors, - numModes_.back().data(), modesPtr_.back().data(), + appendTNOperator_(coeff, numTensors, numModes_.back().data(), + modesPtr_.back().data(), tensorDataPtr_.back().data()); } } @@ -303,8 +303,7 @@ template class ObservableTNCudaOperator { * @param stateModes State modes of each tensor in the product. * @param tensorDataPtr Pointer to the data of each tensor in the product. */ - void appendTNOperator_(cutensornetNetworkOperator_t &tnOperator, - const cuDoubleComplex &coeff, + void appendTNOperator_(const cuDoubleComplex &coeff, const std::size_t numTensors, const int32_t *numStateModes, const int32_t **stateModes, @@ -312,7 +311,7 @@ template class ObservableTNCudaOperator { int64_t id; PL_CUTENSORNET_IS_SUCCESS(cutensornetNetworkOperatorAppendProduct( /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), - /* cutensornetNetworkOperator_t */ tnOperator, + /* cutensornetNetworkOperator_t */ getTNOperator(), /* cuDoubleComplex coefficient*/ coeff, /* int32_t numTensors */ static_cast(numTensors), /* const int32_t numStateModes[] */ numStateModes, From fca24d3b926b2b73479e20d01f50bf02fb483575 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 20:13:17 +0000 Subject: [PATCH 018/227] switch on more python unit tests --- pennylane_lightning/lightning_tensor/lightning_tensor.py | 7 +++++++ tests/test_measurements.py | 4 ---- tests/test_var.py | 6 ++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index a7212e58d5..bcbda55334 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -240,6 +240,13 @@ def circuit(num_qubits): _CPP_BINARY_AVAILABLE = LT_CPP_BINARY_AVAILABLE _new_API = True + # TODO: Move supported ops/obs to TOML file + operations = _operations + # The names of the supported operations. + + observables = _observables + # The names of the supported observables. + # pylint: disable=too-many-arguments def __init__( self, diff --git a/tests/test_measurements.py b/tests/test_measurements.py index 0e00a90d5d..d2269670cd 100644 --- a/tests/test_measurements.py +++ b/tests/test_measurements.py @@ -662,10 +662,6 @@ def test_sample_values(self, qubit_device, tol): assert np.allclose(s1**2, 1, atol=tol, rtol=0) -@pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.var()", -) class TestWiresInVar: """Test different Wires settings in Lightning's var.""" diff --git a/tests/test_var.py b/tests/test_var.py index 560151ecad..efc6fa8363 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -24,8 +24,6 @@ if not ld._CPP_BINARY_AVAILABLE: pytest.skip("No binary module found. Skipping.", allow_module_level=True) -if device_name == "lightning.tensor": - pytest.skip("lightning.tensor doesn't support var.", allow_module_level=True) np.random.seed(42) @@ -57,6 +55,10 @@ def test_var(self, theta, phi, qubit_device, tol): assert np.allclose(var, expected, tol) + pytest.mark.skipif( + device_name == "lightning.tensor", reason="lightning.tensor doesn't support projector." + ) + def test_projector_var(self, theta, phi, qubit_device, tol): """Test that Projector variance value is correct""" n_qubits = 2 From 19dbedc088882f12e24a007ab72a0d9d0b43cfeb Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 20:16:02 +0000 Subject: [PATCH 019/227] tidy up python layer --- pennylane_lightning/lightning_tensor/_measurements.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 68ee750a52..14855e4897 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -121,8 +121,6 @@ def get_measurement_function( return self.expval if isinstance(measurementprocess, VarianceMP): - # if isinstance(measurementprocess.obs, (qml.Identity, qml.Projector)): - # return self.state_diagonalizing_gates return self.var raise NotImplementedError( From 2737df15ae18a7122583630c6464f90c56b07e1d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 18 Jul 2024 21:21:17 +0000 Subject: [PATCH 020/227] tidy up linaralg and add more unit tests --- .../core/src/utils/cuda_utils/LinearAlg.hpp | 14 ++--- .../cuda_utils/tests/Test_LinearAlgebra.cpp | 54 +++++++++++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp index b32c9a7c0c..355232fc52 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp @@ -96,16 +96,18 @@ inline void square_matrix_CUDA_device(T *mat, const int row_size, const int col_size, DevTypeID dev_id, cudaStream_t stream_id, const CublasCaller &cublas) { + PL_ABORT_IF(row_size != col_size, "Matrix must be square."); const T alpha{1.0, 0.0}; const T beta{0.0, 0.0}; + int m = row_size; + int n = row_size; + int k = col_size; if constexpr (std::is_same_v) { - cublas.call(cublasCgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, - row_size, row_size, col_size, &alpha, mat, row_size, mat, - col_size, &beta, mat, row_size); + cublas.call(cublasCgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, m, + n, k, &alpha, mat, m, mat, n, &beta, mat, m); } else if constexpr (std::is_same_v) { - cublas.call(cublasZgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, - row_size, row_size, col_size, &alpha, mat, row_size, mat, - col_size, &beta, mat, row_size); + cublas.call(cublasZgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, m, + n, k, &alpha, mat, m, mat, n, &beta, mat, m); } } diff --git a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp index b5b837f1e2..f75a0077c2 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp @@ -97,3 +97,57 @@ TEMPLATE_TEST_CASE("Linear Algebra::SparseMV", "[Linear Algebra]", float, } } } + +TEMPLATE_TEST_CASE("Linear Algebra::square_matrix_CUDA_device", + "[Linear Algebra]", float, double) { + using ComplexT = std::complex; + + using CFP_t = + typename std::conditional::value, + cuFloatComplex, cuDoubleComplex>::type; + + std::size_t row_size = 2; + + std::vector matrix = {{0.2, 0.2}, + {0.3, 0.3}, + {0.3, 0.4}, + {0.4, 0.5}}; // from numpy calculation + + std::vector matrix_cu; + + std::transform(matrix.begin(), matrix.end(), std::back_inserter(matrix_cu), + [](ComplexT x) { return complexToCu(x); }); + + const std::vector result_refs = { + {-0.03, 0.29}, {-0.03, 0.39}, {-0.1, 0.45}, {-0.12, 0.61}}; + + DataBuffer mat(matrix_cu.size()); + + mat.CopyHostDataToGpu(matrix_cu.data(), matrix_cu.size()); + + SECTION("Testing square matrix multiplication:") { + std::vector result(matrix_cu.size()); + auto cublas_caller = make_shared_cublas_caller(); + + square_matrix_CUDA_device(mat.getData(), row_size, row_size, + mat.getDevice(), mat.getStream(), + *cublas_caller); + + mat.CopyGpuDataToHost(result.data(), result.size()); + + for (std::size_t j = 0; j < matrix_cu.size(); j++) { + CHECK(result[j].x == Approx(real(result_refs[j]))); + CHECK(result[j].y == Approx(imag(result_refs[j]))); + } + } + + SECTION("Throwing exception for non-square matrix multiplication:") { + std::vector result(matrix_cu.size()); + auto cublas_caller = make_shared_cublas_caller(); + + CHECK_THROWS_WITH(square_matrix_CUDA_device( + mat.getData(), row_size, row_size + 1, + mat.getDevice(), mat.getStream(), *cublas_caller), + Catch::Contains("Matrix must be square.")); + } +} \ No newline at end of file From 976da4d04791ad1a935c763c0e8e63e322b2a3de Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Sat, 20 Jul 2024 00:15:47 +0000 Subject: [PATCH 021/227] Add var support to multi-terms Hamiltionian --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 6 +- .../observables/ObservablesTNCudaOperator.hpp | 347 ++++++++++++++++-- .../core/src/utils/cuda_utils/LinearAlg.hpp | 25 ++ .../src/utils/cuda_utils/cuGates_host.hpp | 108 +++++- .../src/utils/cuda_utils/cuda_helpers.hpp | 15 + .../cuda_utils/tests/Test_LinearAlgebra.cpp | 2 +- 6 files changed, 469 insertions(+), 34 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 4a31afca2b..d73d01bc1c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -194,8 +194,10 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto ob_term = TensorProdObsT::create({X0, Z1}); - auto ob = HamiltonianObsT::create({TestType{0.5}}, {ob_term}); + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Z1}); + auto res = m.var(*ob); - CHECK(res == Approx(0.836679 * 0.25)); + CHECK(res == Approx(0.093413)); } } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index dfc7027442..342c443459 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -15,7 +15,9 @@ #pragma once #include +#include #include +#include #include #include "LinearAlg.hpp" @@ -62,9 +64,19 @@ template class ObservableTNCudaOperator { using PrecisionT = typename TensorNetT::PrecisionT; using CFP_t = typename TensorNetT::CFP_t; using ComplexT = typename TensorNetT::ComplexT; + + using MetaDataT = std::tuple, + std::vector>; // name, params, matrix using obs_key = std::tuple, std::size_t>; + private: + std::unordered_map pauli_map_{{"Identity", "I"}, + {"PauliX", "X"}, + {"PauliY", "Y"}, + {"PauliZ", "Z"}, + {"Hadamard", "H"}}; + private: SharedCublasCaller cublascaller_; cutensornetNetworkOperator_t obsOperator_{ @@ -89,6 +101,22 @@ template class ObservableTNCudaOperator { std::vector ids_; // ids for each term in the graph + /*--------------------Var Support Below------------------------*/ + std::size_t numObsTerms2_; // number of observable terms + vector1D coeffs2_; // coefficients for each term + vector1D numTensors2_; // number of tensors in each term + + vector2D + numModes2_; // number of state modes of each tensor in each term + + vector3D modes2_; // modes for each tensor in each term + + vector2D + modesPtr2_; // pointers for modes of each tensor in each term + + vector2D + tensorDataPtr2_; // pointers for each tensor data in each term + /*--------------------Var Support Above------------------------*/ const bool var_cal_ = false; private: @@ -177,28 +205,20 @@ template class ObservableTNCudaOperator { : tensor_network_{tensor_network}, numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { if (var_cal) { - PL_ABORT_IF_NOT( - numObsTerms_ == 1, - "Only one observable term is allowed for variance calculation"); + // PL_ABORT_IF_NOT( + // numObsTerms_ == 1, + // "Only one observable term is allowed for variance + // calculation"); cublascaller_ = make_shared_cublas_caller(); } - PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateNetworkOperator( - /* const cutensornetHandle_t */ tensor_network.getTNCudaHandle(), - /* int32_t */ static_cast(tensor_network.getNumQubits()), - /* const int64_t stateModeExtents */ - reinterpret_cast(const_cast( - tensor_network.getQubitDims().data())), - /* cudaDataType_t */ tensor_network.getCudaDataType(), - /* cutensornetNetworkOperator_t */ &obsOperator_)); - numTensors_ = obs.getNumTensors(); // number of tensors in each term for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { PrecisionT coeff_real = obs.getCoeffs()[term_idx]; - if (var_cal) { - coeff_real = coeff_real * coeff_real; - } + // if (var_cal) { + // coeff_real = coeff_real * coeff_real; + // } auto coeff = cuDoubleComplex{static_cast(coeff_real), 0.0}; auto numTensors = numTensors_[term_idx]; @@ -218,8 +238,8 @@ template class ObservableTNCudaOperator { tensor_network.getNumQubits())); } modes_.emplace_back(modes_per_term); - - // modes pointer initialization + // Not required for var calculation below + // modes pointer initialization vector1D modesPtrPerTerm; for (std::size_t tensor_idx = 0; tensor_idx < modes_.back().size(); tensor_idx++) { @@ -234,9 +254,9 @@ template class ObservableTNCudaOperator { auto metaData = obs.getMetaData()[term_idx][tensor_idx]; auto obsName = std::get<0>(metaData); - if (var_cal) { - obsName = obsName + "_squared"; - } + // if (var_cal) { + // obsName = obsName + "_squared"; + // } auto param = std::get<1>(metaData); auto hermitianMatrix = std::get<2>(metaData); std::size_t hash_val = 0; @@ -254,6 +274,7 @@ template class ObservableTNCudaOperator { auto hermitianMatrix_cu = cuUtil::complexToCu(hermitianMatrix); add_obs_(obsKey, hermitianMatrix_cu); + /* if (var_cal) { square_matrix_CUDA_device( const_cast( @@ -266,16 +287,287 @@ template class ObservableTNCudaOperator { tensor_network_.getDevTag().getStreamID(), *cublascaller_); } + */ } } tensorDataPtrPerTerm_.emplace_back(get_obs_device_ptr_(obsKey)); } tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); + // Not required for var calculation above + } - appendTNOperator_(coeff, numTensors, numModes_.back().data(), - modesPtr_.back().data(), - tensorDataPtr_.back().data()); + if (var_cal) { + numObsTerms2_ = numObsTerms_ * numObsTerms_; + + for (std::size_t term_idx = 0; term_idx < numObsTerms_; + term_idx++) { + for (std::size_t term_idy = 0; term_idy < numObsTerms_; + term_idy++) { + auto coeff = cuDoubleComplex{ + static_cast(obs.getCoeffs()[term_idx] * + obs.getCoeffs()[term_idy]), + 0.0}; + coeffs2_.emplace_back(coeff); + + auto modes_termx = modes_[term_idx]; + auto modes_termy = modes_[term_idy]; + + std::unordered_map> + modes_obsname_map; // Note that one-wire observables are + // supported as cutensornet v24.03 + + for (std::size_t tensor_idx = 0; + tensor_idx < modes_termx.size(); tensor_idx++) { + PL_ABORT_IF_NOT(modes_termx[tensor_idx].size() == 1, + "Only one-wire observables are " + "supported for cutensornet v24.03"); + + modes_obsname_map[modes_termx[tensor_idx][0]] = { + obs.getMetaData()[term_idx][tensor_idx]}; + } + + for (std::size_t tensor_idy = 0; + tensor_idy < modes_termy.size(); tensor_idy++) { + auto it = modes_obsname_map.find( + modes_termy[tensor_idy].front()); + if (it != modes_obsname_map.end()) { + modes_obsname_map[modes_termy[tensor_idy].front()] + .push_back( + obs.getMetaData()[term_idy][tensor_idy]); + } else { + modes_obsname_map[modes_termy[tensor_idy].front()] = + {obs.getMetaData()[term_idy][tensor_idy]}; + } + } + + auto numTensorsPerTerm = modes_obsname_map.size(); + + numTensors2_.emplace_back(numTensorsPerTerm); + + vector2D modes_per_term; + vector1D tensorDataPtrPerTerm_; + vector1D num_modes_per_term; + + for (const auto &tensors_info : modes_obsname_map) { + modes_per_term.emplace_back( + std::vector{tensors_info.first}); + + num_modes_per_term.emplace_back( + modes_per_term.back().size()); + auto metaDataArr = tensors_info.second; + if (metaDataArr.size() == 1) { + auto metaData = metaDataArr[0]; + auto obsName = std::get<0>(metaData); + auto param = std::get<1>(metaData); + auto hermitianMatrix = std::get<2>(metaData); + std::size_t hash_val = 0; + + if (!hermitianMatrix.empty()) { + hash_val = MatrixHasher()(hermitianMatrix); + } + + auto obsKey = + std::make_tuple(obsName, param, hash_val); + + if (device_obs_cache_.find(obsKey) == + device_obs_cache_.end()) { + if (hermitianMatrix.empty()) { + add_obs_(obsName, param); + } else { + auto hermitianMatrix_cu = + cuUtil::complexToCu( + hermitianMatrix); + add_obs_(obsKey, hermitianMatrix_cu); + } + } + + tensorDataPtrPerTerm_.emplace_back( + get_obs_device_ptr_(obsKey)); + + } else { + PL_ABORT_IF(metaDataArr.size() > 2, + "DEBUG PURPOSE ONLY"); + auto metaData0 = metaDataArr[0]; + auto metaData1 = metaDataArr[1]; + + auto param0 = std::get<1>(metaData0); + auto param1 = std::get<1>(metaData1); + + auto obsName0 = std::get<0>(metaData0); + auto obsName1 = std::get<0>(metaData1); + + std::string obsName = obsName0 + "@" + obsName1; + + // Branch for Pauli strings + if (pauli_map_.find(obsName0) != pauli_map_.end() && + pauli_map_.find(obsName1) != pauli_map_.end()) { + obsName0 = pauli_map_[obsName0]; + obsName1 = pauli_map_[obsName1]; + obsName = obsName0 + "@" + obsName1; + + auto obsKey = std::make_tuple( + obsName, std::vector{}, + std::size_t{0}); + if (device_obs_cache_.find(obsKey) == + device_obs_cache_.end()) { + add_obs_(obsName, param0); + } + tensorDataPtrPerTerm_.emplace_back( + static_cast( + get_obs_device_ptr_(obsKey))); + } + // Hermitian below to be tidy up + else { + // Branch for Hermtian involving Pauli strings + // add both observables matrix to GPU cache + auto hermitianMatrix0 = + std::get<2>(metaDataArr[0]); + auto hermitianMatrix1 = + std::get<2>(metaDataArr[1]); + std::size_t hash_val0 = 0; + std::size_t hash_val1 = 0; + if (!hermitianMatrix0.empty()) { + hash_val0 = + MatrixHasher()(hermitianMatrix0); + } + if (!hermitianMatrix1.empty()) { + hash_val1 = + MatrixHasher()(hermitianMatrix1); + } + auto obsKey0 = std::make_tuple( + obsName0, std::vector{}, + hash_val0); + auto obsKey1 = std::make_tuple( + obsName1, std::vector{}, + hash_val1); + + if (device_obs_cache_.find(obsKey0) == + device_obs_cache_.end()) { + if (hermitianMatrix0.empty()) { + add_obs_(obsName0, param0); + } else { + auto hermitianMatrix_cu = + cuUtil::complexToCu( + hermitianMatrix0); + add_obs_(obsKey0, hermitianMatrix_cu); + } + } + + if (device_obs_cache_.find(obsKey1) == + device_obs_cache_.end()) { + if (hermitianMatrix1.empty()) { + add_obs_(obsName1, param1); + } else { + auto hermitianMatrix_cu = + cuUtil::complexToCu( + hermitianMatrix1); + add_obs_(obsKey1, hermitianMatrix_cu); + } + } + + // add the combined observable matrix together + auto obsName = obsName0 + "@" + obsName1; + + PL_ABORT_IF(hermitianMatrix0.size() != + hermitianMatrix1.size(), + "DEBUG PURPOSE ONLY"); + + std::size_t hash_val = 0; + + auto hermitianMatrix = hermitianMatrix0; + if (!hermitianMatrix1.empty()) { + hermitianMatrix.insert( + hermitianMatrix.end(), + hermitianMatrix1.begin(), + hermitianMatrix1.end()); + } + + if (!hermitianMatrix.empty()) { + hash_val = MatrixHasher()(hermitianMatrix); + } + + auto obsKey = std::make_tuple( + obsName, std::vector{}, + hash_val); + + if (device_obs_cache_.find(obsKey) == + device_obs_cache_.end()) { + + auto hermitianMatrix_cu = + cuUtil::complexToCu( + hermitianMatrix0); + add_obs_(obsKey, hermitianMatrix_cu); + // update the matrix data with MM operation + MM_CUDA_device( + const_cast( + get_obs_device_ptr_(obsKey0)), + const_cast( + get_obs_device_ptr_(obsKey1)), + const_cast( + get_obs_device_ptr_(obsKey)), + Pennylane::Util::log2( + hermitianMatrix_cu.size()), + Pennylane::Util::log2( + hermitianMatrix_cu.size()), + Pennylane::Util::log2( + hermitianMatrix_cu.size()), + tensor_network_.getDevTag() + .getDeviceID(), + tensor_network_.getDevTag() + .getStreamID(), + *cublascaller_); + } + tensorDataPtrPerTerm_.emplace_back( + get_obs_device_ptr_(obsKey)); + } + } + // Hermitian above + } + modes2_.emplace_back(modes_per_term); + numModes2_.emplace_back(num_modes_per_term); + + // modes pointer initialization + vector1D modesPtrPerTerm; + for (std::size_t tensor_idx = 0; + tensor_idx < modes2_.back().size(); tensor_idx++) { + modesPtrPerTerm.emplace_back( + modes2_.back()[tensor_idx].data()); + } + modesPtr2_.emplace_back(modesPtrPerTerm); + tensorDataPtr2_.emplace_back(tensorDataPtrPerTerm_); + } + } + } + + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateNetworkOperator( + /* const cutensornetHandle_t */ tensor_network.getTNCudaHandle(), + /* int32_t */ + static_cast(tensor_network.getNumQubits()), + /* const int64_t stateModeExtents */ + reinterpret_cast(const_cast( + tensor_network.getQubitDims().data())), + /* cudaDataType_t */ tensor_network.getCudaDataType(), + /* cutensornetNetworkOperator_t */ &obsOperator_)); + + if (var_cal) { + for (std::size_t term_idx = 0; term_idx < numObsTerms2_; + term_idx++) { + appendTNOperator_(coeffs2_[term_idx], numTensors2_[term_idx], + numModes2_[term_idx].data(), + modesPtr2_[term_idx].data(), + tensorDataPtr2_[term_idx].data()); + } + + } else { + for (std::size_t term_idx = 0; term_idx < numObsTerms_; + term_idx++) { + appendTNOperator_(coeffs_[term_idx], numTensors_[term_idx], + numModes_[term_idx].data(), + modesPtr_[term_idx].data(), + tensorDataPtr_[term_idx].data()); + } } } @@ -295,13 +587,16 @@ template class ObservableTNCudaOperator { private: /** - * @brief Append a product of tensors to the `cutensornetNetworkOperator_t` + * @brief Append a product of tensors to the + * `cutensornetNetworkOperator_t` * * @param coeff Coefficient of the product. * @param numTensors Number of tensors in the product. - * @param numStateModes Number of state modes of each tensor in the product. + * @param numStateModes Number of state modes of each tensor in the + * product. * @param stateModes State modes of each tensor in the product. - * @param tensorDataPtr Pointer to the data of each tensor in the product. + * @param tensorDataPtr Pointer to the data of each tensor in the + * product. */ void appendTNOperator_(const cuDoubleComplex &coeff, const std::size_t numTensors, diff --git a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp index 355232fc52..5a252568c4 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp @@ -111,6 +111,31 @@ inline void square_matrix_CUDA_device(T *mat, const int row_size, } } +/** + * @brief cuBLAS backed square the matrix for GPU data. + * + * @tparam T Complex data-type. Accepts cuFloatComplex and cuDoubleComplex + * @param mat Device data pointer. + * @param row_size Size of the matrix row. + * @param col_size Size of the matrix column. + * @param dev_id the device on which the function should be executed. + * @param stream_id the CUDA stream on which the operation should be executed. + * @param cublas the CublasCaller object that manages the cuBLAS handle. + */ +template +inline void MM_CUDA_device(T *A, T *B, T *C, const int m, const int k, + const int n, DevTypeID dev_id, + cudaStream_t stream_id, const CublasCaller &cublas) { + const T alpha{1.0, 0.0}; + const T beta{0.0, 0.0}; + if constexpr (std::is_same_v) { + cublas.call(cublasCgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, m, + n, k, &alpha, A, m, B, n, &beta, C, m); + } else if constexpr (std::is_same_v) { + cublas.call(cublasZgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, m, + n, k, &alpha, A, m, B, n, &beta, C, m); + } +} /** * @brief cuBLAS backed inner product for GPU data. * diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp index e8ad56c1fd..b1bef2b2e2 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include "cuda_helpers.hpp" /// @cond DEV @@ -1472,6 +1474,74 @@ static constexpr auto getP1111_CU() -> std::vector { cuUtil::ONE()}; } +/** + * @brief Create a matrix representation of the PauliX gate data in row-major + * format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliX data. + */ +template static constexpr auto getXY() -> std::vector { + return {cuUtil::IMAG(), cuUtil::ZERO(), cuUtil::ZERO(), + -cuUtil::IMAG()}; +} + +template static constexpr auto getXZ() -> std::vector { + return {cuUtil::ZERO(), -cuUtil::ONE(), cuUtil::ONE(), + cuUtil::ZERO()}; +} + +template static constexpr auto getXH() -> std::vector { + return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), + cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +} + +template static constexpr auto getYX() -> std::vector { + return {-cuUtil::IMAG(), cuUtil::ZERO(), + cuUtil::ZERO(), cuUtil::IMAG()}; +} + +template static constexpr auto getYZ() -> std::vector { + return {cuUtil::ZERO(), cuUtil::IMAG(), cuUtil::IMAG(), + cuUtil::ZERO()}; +} + +template static constexpr auto getYH() -> std::vector { + return {-cuUtil::INVSQRT2I(), cuUtil::INVSQRT2I(), + cuUtil::INVSQRT2I(), cuUtil::INVSQRT2I()}; +} + +template static constexpr auto getZX() -> std::vector { + return {cuUtil::ZERO(), cuUtil::ONE(), -cuUtil::ONE(), + cuUtil::ZERO()}; +} + +template static constexpr auto getZY() -> std::vector { + return {cuUtil::ZERO(), -cuUtil::IMAG(), + -cuUtil::IMAG(), cuUtil::ZERO()}; +} + +template static constexpr auto getZH() -> std::vector { + return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), + -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +} + +template static constexpr auto getHX() -> std::vector { + return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), + -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +} + +template static constexpr auto getHY() -> std::vector { + return {cuUtil::INVSQRT2I(), -cuUtil::INVSQRT2I(), + -cuUtil::INVSQRT2I(), -cuUtil::INVSQRT2I()}; +} + +template static constexpr auto getHZ() -> std::vector { + return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), + cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +} + /* * @brief Dyanmical access the gate data based on the gate name and parameters. * @@ -1541,15 +1611,43 @@ template class DynamicGateDataAccess { []() -> std::vector { return cuGates::getToffoli(); }}, {"CY", []() -> std::vector { return cuGates::getCY(); }}, {"CZ", []() -> std::vector { return cuGates::getCZ(); }}, - {"Identity_squared", + {"I@I", []() -> std::vector { return cuGates::getIdentity(); }}, - {"PauliX_squared", + {"I@X", + []() -> std::vector { return cuGates::getPauliX(); }}, + {"I@Y", + []() -> std::vector { return cuGates::getPauliY(); }}, + {"I@Z", + []() -> std::vector { return cuGates::getPauliZ(); }}, + {"I@H", + []() -> std::vector { return cuGates::getHadamard(); }}, + {"X@I", + []() -> std::vector { return cuGates::getPauliX(); }}, + {"X@X", []() -> std::vector { return cuGates::getIdentity(); }}, - {"PauliY_squared", + {"X@Y", []() -> std::vector { return cuGates::getXY(); }}, + {"X@Z", []() -> std::vector { return cuGates::getXZ(); }}, + {"X@H", []() -> std::vector { return cuGates::getXH(); }}, + {"Y@I", + []() -> std::vector { return cuGates::getPauliY(); }}, + {"Y@X", []() -> std::vector { return cuGates::getYX(); }}, + {"Y@Y", []() -> std::vector { return cuGates::getIdentity(); }}, - {"PauliZ_squared", + {"Y@Z", []() -> std::vector { return cuGates::getYZ(); }}, + {"Y@H", []() -> std::vector { return cuGates::getYH(); }}, + {"Z@I", + []() -> std::vector { return cuGates::getPauliZ(); }}, + {"Z@X", []() -> std::vector { return cuGates::getZX(); }}, + {"Z@Y", []() -> std::vector { return cuGates::getZY(); }}, + {"Z@Z", []() -> std::vector { return cuGates::getIdentity(); }}, - {"Hadamard_squared", + {"Z@H", []() -> std::vector { return cuGates::getZH(); }}, + {"H@I", + []() -> std::vector { return cuGates::getHadamard(); }}, + {"H@X", []() -> std::vector { return cuGates::getHX(); }}, + {"H@Y", []() -> std::vector { return cuGates::getHY(); }}, + {"H@Z", []() -> std::vector { return cuGates::getHZ(); }}, + {"H@H", []() -> std::vector { return cuGates::getIdentity(); }}, {"CSWAP", []() -> std::vector { return cuGates::getCSWAP(); }}}; diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp index 4b6da353da..c4148564b0 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp @@ -271,6 +271,21 @@ template inline static constexpr auto INVSQRT2() -> CFP_t { } } +/** + * @brief Returns inverse sqrt(2)i as a compile-time constant. + * + * @tparam T Precision of result. `double`, `float` are accepted values. + * @return constexpr T 1/sqrt(2)i + */ +template inline static constexpr auto INVSQRT2I() -> CFP_t { + if constexpr (std::is_same_v> || + std::is_same_v>) { + return CFP_t(0, 1 / M_SQRT2); + } else { + return Div(CFP_t{0, 1}, SQRT2()); + } +} + /** * If T is a supported data type for gates, this expression will * evaluate to `true`. Otherwise, it will evaluate to `false`. diff --git a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp index f75a0077c2..b3ce7f0cc8 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp @@ -150,4 +150,4 @@ TEMPLATE_TEST_CASE("Linear Algebra::square_matrix_CUDA_device", mat.getDevice(), mat.getStream(), *cublas_caller), Catch::Contains("Matrix must be square.")); } -} \ No newline at end of file +} From ad8d9bdf8a1ffe6836193fe7fab66658e1ffe6b7 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 22 Jul 2024 19:24:17 +0000 Subject: [PATCH 022/227] tidy up code --- .github/CHANGELOG.md | 2 +- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 262 +++++++++++++++ .../observables/ObservablesTNCudaOperator.hpp | 300 +++++++----------- .../lightning_tensor/test_gates_and_expval.py | 2 +- tests/test_measurements.py | 6 +- 5 files changed, 376 insertions(+), 196 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 00e975541e..d5f16f142b 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `var` support to `lightning.tensor`. +* Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs^2`. [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) ### Breaking changes diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index d73d01bc1c..697c73f04f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -171,7 +171,9 @@ TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, double) { using TensorNetT = MPSTNCuda; + using ComplexT = typename TensorNetT::ComplexT; using NamedObsT = NamedObsTNCuda; + using HermitianObsT = HermitianObsTNCuda; using TensorProdObsT = TensorProdObsTNCuda; using HamiltonianObsT = HamiltonianTNCuda; SECTION("Using XZ") { @@ -192,6 +194,266 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto Z1 = std::make_shared("PauliZ", std::vector{1}); + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Z1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.093413)); + } + + SECTION("Using XI") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto I1 = std::make_shared("Identity", + std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, I1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.07406834808884483)); + } + + SECTION("Using YI") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto Y0 = + std::make_shared("PauliY", std::vector{0}); + auto I1 = std::make_shared("Identity", + std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, I1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.06931360376406634)); + } + SECTION("Using HI") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto H0 = std::make_shared("Hadamard", + std::vector{0}); + auto I1 = std::make_shared("Identity", + std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, I1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.02618050490800028)); + } + + SECTION("Using ZI") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto Z0 = + std::make_shared("PauliZ", std::vector{0}); + auto I1 = std::make_shared("Identity", + std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Z0, I1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.03661804814708902)); + } + + SECTION("Using XY") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto Y1 = + std::make_shared("PauliY", std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Y1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.314201)); + } + + SECTION("Using XH") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto H1 = std::make_shared("Hadamard", + std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, H1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.15724601172876368)); + } + + SECTION("Using YH") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto H0 = std::make_shared("Hadamard", + std::vector{0}); + auto Y1 = + std::make_shared("PauliY", std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, Y1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.26631312915836103)); + } + + SECTION("Using ZY") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto Z0 = + std::make_shared("PauliZ", std::vector{0}); + auto Y1 = + std::make_shared("PauliY", std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Z0, Y1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.27675067239744966)); + } + + SECTION("Using 1 Hermitian") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + std::vector matrix = { + {0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}}; + + auto X0 = std::make_shared(matrix, + std::vector{0}); + auto Z1 = + std::make_shared("PauliZ", std::vector{1}); + + auto ob_term = TensorProdObsT::create({X0, Z1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Z1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.093413)); + } + + SECTION("Using 2 Hermitians") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + std::vector matrix = { + {0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}}; + + std::vector matrix_z = { + {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}}; + + auto X0 = std::make_shared(matrix, + std::vector{0}); + auto Z1 = std::make_shared(matrix_z, + std::vector{1}); + auto ob_term = TensorProdObsT::create({X0, Z1}); auto ob = diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 342c443459..38ff91bf7a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -101,7 +101,6 @@ template class ObservableTNCudaOperator { std::vector ids_; // ids for each term in the graph - /*--------------------Var Support Below------------------------*/ std::size_t numObsTerms2_; // number of observable terms vector1D coeffs2_; // coefficients for each term vector1D numTensors2_; // number of tensors in each term @@ -116,7 +115,7 @@ template class ObservableTNCudaOperator { vector2D tensorDataPtr2_; // pointers for each tensor data in each term - /*--------------------Var Support Above------------------------*/ + const bool var_cal_ = false; private: @@ -187,6 +186,37 @@ template class ObservableTNCudaOperator { obs_data_host.data(), obs_data_host.size()); } + /** + * @brief Add metadata of observable. + * + * @param metaData Metadata of the observable. + * @return obs_key The key of observable tensor operator. + */ + auto add_meta_data_(const MetaDataT &metaData) -> obs_key { + auto obsName = std::get<0>(metaData); + auto param = std::get<1>(metaData); + auto hermitianMatrix = std::get<2>(metaData); + std::size_t hash_val = 0; + + if (!hermitianMatrix.empty()) { + hash_val = MatrixHasher()(hermitianMatrix); + } + + auto obsKey = std::make_tuple(obsName, param, hash_val); + + if (device_obs_cache_.find(obsKey) == device_obs_cache_.end()) { + if (hermitianMatrix.empty()) { + add_obs_(obsName, param); + } else { + auto hermitianMatrix_cu = + cuUtil::complexToCu(hermitianMatrix); + add_obs_(obsKey, hermitianMatrix_cu); + } + } + + return obsKey; + } + /** * @brief Returns a pointer to the GPU device memory where the observable is * stored. @@ -204,21 +234,11 @@ template class ObservableTNCudaOperator { const bool var_cal = false) : tensor_network_{tensor_network}, numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { - if (var_cal) { - // PL_ABORT_IF_NOT( - // numObsTerms_ == 1, - // "Only one observable term is allowed for variance - // calculation"); - cublascaller_ = make_shared_cublas_caller(); - } numTensors_ = obs.getNumTensors(); // number of tensors in each term for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { PrecisionT coeff_real = obs.getCoeffs()[term_idx]; - // if (var_cal) { - // coeff_real = coeff_real * coeff_real; - // } auto coeff = cuDoubleComplex{static_cast(coeff_real), 0.0}; auto numTensors = numTensors_[term_idx]; @@ -238,66 +258,39 @@ template class ObservableTNCudaOperator { tensor_network.getNumQubits())); } modes_.emplace_back(modes_per_term); - // Not required for var calculation below - // modes pointer initialization - vector1D modesPtrPerTerm; - for (std::size_t tensor_idx = 0; tensor_idx < modes_.back().size(); - tensor_idx++) { - modesPtrPerTerm.emplace_back(modes_.back()[tensor_idx].data()); - } - modesPtr_.emplace_back(modesPtrPerTerm); + } - // tensor data initialization - vector1D tensorDataPtrPerTerm_; - for (std::size_t tensor_idx = 0; tensor_idx < numTensors; - tensor_idx++) { - auto metaData = obs.getMetaData()[term_idx][tensor_idx]; - - auto obsName = std::get<0>(metaData); - // if (var_cal) { - // obsName = obsName + "_squared"; - // } - auto param = std::get<1>(metaData); - auto hermitianMatrix = std::get<2>(metaData); - std::size_t hash_val = 0; - - if (!hermitianMatrix.empty()) { - hash_val = MatrixHasher()(hermitianMatrix); + if (!var_cal) { + for (std::size_t term_idx = 0; term_idx < numObsTerms_; + term_idx++) { + auto numTensors = numTensors_[term_idx]; + + // Not required for var calculation below + // modes pointer initialization + vector1D modesPtrPerTerm; + for (std::size_t tensor_idx = 0; + tensor_idx < modes_[term_idx].size(); tensor_idx++) { + modesPtrPerTerm.emplace_back( + modes_[term_idx][tensor_idx].data()); } + modesPtr_.emplace_back(modesPtrPerTerm); - auto obsKey = std::make_tuple(obsName, param, hash_val); - - if (device_obs_cache_.find(obsKey) == device_obs_cache_.end()) { - if (hermitianMatrix.empty()) { - add_obs_(obsName, param); - } else { - auto hermitianMatrix_cu = - cuUtil::complexToCu(hermitianMatrix); - add_obs_(obsKey, hermitianMatrix_cu); - /* - if (var_cal) { - square_matrix_CUDA_device( - const_cast( - get_obs_device_ptr_(obsKey)), - Pennylane::Util::log2( - hermitianMatrix_cu.size()), - Pennylane::Util::log2( - hermitianMatrix_cu.size()), - tensor_network_.getDevTag().getDeviceID(), - tensor_network_.getDevTag().getStreamID(), - *cublascaller_); - } - */ - } + // tensor data initialization + vector1D tensorDataPtrPerTerm_; + for (std::size_t tensor_idx = 0; tensor_idx < numTensors; + tensor_idx++) { + auto obsKey = + add_meta_data_(obs.getMetaData()[term_idx][tensor_idx]); + + tensorDataPtrPerTerm_.emplace_back( + get_obs_device_ptr_(obsKey)); } - tensorDataPtrPerTerm_.emplace_back(get_obs_device_ptr_(obsKey)); - } - tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); - // Not required for var calculation above - } + tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); + } + } else { + cublascaller_ = make_shared_cublas_caller(); - if (var_cal) { numObsTerms2_ = numObsTerms_ * numObsTerms_; for (std::size_t term_idx = 0; term_idx < numObsTerms_; @@ -358,135 +351,55 @@ template class ObservableTNCudaOperator { modes_per_term.back().size()); auto metaDataArr = tensors_info.second; if (metaDataArr.size() == 1) { - auto metaData = metaDataArr[0]; - auto obsName = std::get<0>(metaData); - auto param = std::get<1>(metaData); - auto hermitianMatrix = std::get<2>(metaData); - std::size_t hash_val = 0; - - if (!hermitianMatrix.empty()) { - hash_val = MatrixHasher()(hermitianMatrix); - } - - auto obsKey = - std::make_tuple(obsName, param, hash_val); - - if (device_obs_cache_.find(obsKey) == - device_obs_cache_.end()) { - if (hermitianMatrix.empty()) { - add_obs_(obsName, param); - } else { - auto hermitianMatrix_cu = - cuUtil::complexToCu( - hermitianMatrix); - add_obs_(obsKey, hermitianMatrix_cu); - } - } - + auto obsKey = add_meta_data_(metaDataArr[0]); tensorDataPtrPerTerm_.emplace_back( get_obs_device_ptr_(obsKey)); + } else if (metaDataArr.size() == 2) { + auto obsName0 = std::get<0>(metaDataArr[0]); + auto obsName1 = std::get<0>(metaDataArr[1]); - } else { - PL_ABORT_IF(metaDataArr.size() > 2, - "DEBUG PURPOSE ONLY"); - auto metaData0 = metaDataArr[0]; - auto metaData1 = metaDataArr[1]; - - auto param0 = std::get<1>(metaData0); - auto param1 = std::get<1>(metaData1); + auto param0 = std::get<1>(metaDataArr[0]); + auto param1 = std::get<1>(metaDataArr[1]); - auto obsName0 = std::get<0>(metaData0); - auto obsName1 = std::get<0>(metaData1); + std::string obsName; - std::string obsName = obsName0 + "@" + obsName1; - - // Branch for Pauli strings if (pauli_map_.find(obsName0) != pauli_map_.end() && pauli_map_.find(obsName1) != pauli_map_.end()) { + // Branch for Pauli strings obsName0 = pauli_map_[obsName0]; obsName1 = pauli_map_[obsName1]; obsName = obsName0 + "@" + obsName1; - auto obsKey = std::make_tuple( - obsName, std::vector{}, - std::size_t{0}); - if (device_obs_cache_.find(obsKey) == - device_obs_cache_.end()) { - add_obs_(obsName, param0); - } + MetaDataT metaData = {obsName, {}, {}}; + + auto obsKey = add_meta_data_(metaData); + tensorDataPtrPerTerm_.emplace_back( static_cast( get_obs_device_ptr_(obsKey))); - } - // Hermitian below to be tidy up - else { + } else { // Branch for Hermtian involving Pauli strings // add both observables matrix to GPU cache - auto hermitianMatrix0 = - std::get<2>(metaDataArr[0]); - auto hermitianMatrix1 = - std::get<2>(metaDataArr[1]); - std::size_t hash_val0 = 0; - std::size_t hash_val1 = 0; - if (!hermitianMatrix0.empty()) { - hash_val0 = - MatrixHasher()(hermitianMatrix0); - } - if (!hermitianMatrix1.empty()) { - hash_val1 = - MatrixHasher()(hermitianMatrix1); - } - auto obsKey0 = std::make_tuple( - obsName0, std::vector{}, - hash_val0); - auto obsKey1 = std::make_tuple( - obsName1, std::vector{}, - hash_val1); - - if (device_obs_cache_.find(obsKey0) == - device_obs_cache_.end()) { - if (hermitianMatrix0.empty()) { - add_obs_(obsName0, param0); - } else { - auto hermitianMatrix_cu = - cuUtil::complexToCu( - hermitianMatrix0); - add_obs_(obsKey0, hermitianMatrix_cu); - } - } - - if (device_obs_cache_.find(obsKey1) == - device_obs_cache_.end()) { - if (hermitianMatrix1.empty()) { - add_obs_(obsName1, param1); - } else { - auto hermitianMatrix_cu = - cuUtil::complexToCu( - hermitianMatrix1); - add_obs_(obsKey1, hermitianMatrix_cu); - } - } + auto obsKey0 = add_meta_data_(metaDataArr[0]); + auto obsKey1 = add_meta_data_(metaDataArr[1]); - // add the combined observable matrix together auto obsName = obsName0 + "@" + obsName1; - PL_ABORT_IF(hermitianMatrix0.size() != - hermitianMatrix1.size(), - "DEBUG PURPOSE ONLY"); - std::size_t hash_val = 0; - auto hermitianMatrix = hermitianMatrix0; - if (!hermitianMatrix1.empty()) { + auto hermitianMatrix = + std::get<2>(metaDataArr[0]); + + if (!std::get<2>(metaDataArr[1]).empty()) { hermitianMatrix.insert( hermitianMatrix.end(), - hermitianMatrix1.begin(), - hermitianMatrix1.end()); + std::get<2>(metaDataArr[1]).begin(), + std::get<2>(metaDataArr[1]).end()); } - if (!hermitianMatrix.empty()) { - hash_val = MatrixHasher()(hermitianMatrix); - } + // if (!hermitianMatrix.empty()) { + hash_val = MatrixHasher()(hermitianMatrix); + //} auto obsKey = std::make_tuple( obsName, std::vector{}, @@ -494,34 +407,41 @@ template class ObservableTNCudaOperator { if (device_obs_cache_.find(obsKey) == device_obs_cache_.end()) { - auto hermitianMatrix_cu = cuUtil::complexToCu( - hermitianMatrix0); + std::get<2>(metaDataArr[0])); + + if (hermitianMatrix_cu.empty()) { + hermitianMatrix_cu = + cuUtil::complexToCu( + std::get<2>(metaDataArr[1])); + } + add_obs_(obsKey, hermitianMatrix_cu); + // update the matrix data with MM operation - MM_CUDA_device( - const_cast( - get_obs_device_ptr_(obsKey0)), - const_cast( - get_obs_device_ptr_(obsKey1)), - const_cast( - get_obs_device_ptr_(obsKey)), - Pennylane::Util::log2( - hermitianMatrix_cu.size()), - Pennylane::Util::log2( - hermitianMatrix_cu.size()), - Pennylane::Util::log2( - hermitianMatrix_cu.size()), - tensor_network_.getDevTag() - .getDeviceID(), - tensor_network_.getDevTag() - .getStreamID(), - *cublascaller_); + CFP_t *mat0 = const_cast( + get_obs_device_ptr_(obsKey0)); + CFP_t *mat1 = const_cast( + get_obs_device_ptr_(obsKey1)); + CFP_t *res = const_cast( + get_obs_device_ptr_(obsKey)); + std::size_t m = Pennylane::Util::log2( + hermitianMatrix_cu.size()); + + MM_CUDA_device(mat0, mat1, res, m, m, m, + tensor_network_.getDevTag() + .getDeviceID(), + tensor_network_.getDevTag() + .getStreamID(), + *cublascaller_); } tensorDataPtrPerTerm_.emplace_back( get_obs_device_ptr_(obsKey)); } + } else { + PL_ABORT("Only one wire observables are supported " + "for cutensornet v24.03"); } // Hermitian above } diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index a805edb272..ba4d58e0fd 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -183,7 +183,7 @@ def circuit(params): j_ltensor = qnode_ltensor(params) j_default = qnode_default(params) - assert np.allclose(j_ltensor, j_default, rtol=1e-1) + assert np.allclose(j_ltensor, j_default, rtol=1e-6) @pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) diff --git a/tests/test_measurements.py b/tests/test_measurements.py index d2269670cd..4d8b2241f4 100644 --- a/tests/test_measurements.py +++ b/tests/test_measurements.py @@ -326,7 +326,7 @@ def circuit(): ), ], [0.3, 1.0], - 0.9319728930156066, + 0.9319728930156066 if device_name != "lightning.tensor" else 1.0, ), ], ) @@ -345,9 +345,7 @@ def circuit(): qml.RY(-0.2, wires=[1]) return qml.expval(ham) - assert np.allclose( - circuit(), res, atol=tol, rtol=0 if device_name != "lightning.tensor" else 2e-1 - ) + assert np.allclose(circuit(), res, atol=tol, rtol=0) def test_value(self, dev, tol): """Test that the expval interface works""" From 3ac6211a2a0571b1e3916f75064b5ebd801da702 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 22 Jul 2024 19:24:48 +0000 Subject: [PATCH 023/227] Auto update version from '0.38.0-dev12' to '0.38.0-dev13' --- 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 52575c8282..c1ad83f4ad 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.38.0-dev12" +__version__ = "0.38.0-dev13" From 255e341b6df376853bb81e534d032ed40ae6ecae Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 22 Jul 2024 19:40:47 +0000 Subject: [PATCH 024/227] remove square_matrix_cuda_device --- .../observables/ObservablesTNCudaOperator.hpp | 15 +++--- .../core/src/utils/cuda_utils/LinearAlg.hpp | 47 ++++------------ .../src/utils/cuda_utils/cuGates_host.hpp | 2 - .../cuda_utils/tests/Test_LinearAlgebra.cpp | 54 ------------------- 4 files changed, 16 insertions(+), 102 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 38ff91bf7a..657f847827 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -234,7 +234,6 @@ template class ObservableTNCudaOperator { const bool var_cal = false) : tensor_network_{tensor_network}, numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { - numTensors_ = obs.getNumTensors(); // number of tensors in each term for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { @@ -397,9 +396,7 @@ template class ObservableTNCudaOperator { std::get<2>(metaDataArr[1]).end()); } - // if (!hermitianMatrix.empty()) { hash_val = MatrixHasher()(hermitianMatrix); - //} auto obsKey = std::make_tuple( obsName, std::vector{}, @@ -429,12 +426,12 @@ template class ObservableTNCudaOperator { std::size_t m = Pennylane::Util::log2( hermitianMatrix_cu.size()); - MM_CUDA_device(mat0, mat1, res, m, m, m, - tensor_network_.getDevTag() - .getDeviceID(), - tensor_network_.getDevTag() - .getStreamID(), - *cublascaller_); + GEMM_CUDA_device(mat0, mat1, res, m, m, m, + tensor_network_.getDevTag() + .getDeviceID(), + tensor_network_.getDevTag() + .getStreamID(), + *cublascaller_); } tensorDataPtrPerTerm_.emplace_back( get_obs_device_ptr_(obsKey)); diff --git a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp index 5a252568c4..5f59e834d9 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp @@ -84,48 +84,21 @@ class CublasCaller { * @brief cuBLAS backed square the matrix for GPU data. * * @tparam T Complex data-type. Accepts cuFloatComplex and cuDoubleComplex - * @param mat Device data pointer. - * @param row_size Size of the matrix row. - * @param col_size Size of the matrix column. + * @param A Device data pointer of matrix A. + * @param B Device data pointer of matrix B. + * @param C Device data pointer of matrix C. + * @param m Row size of the matrix A. + * @param n Column size of the matrix B. + * @param k Column size of the matrix A and row size of the matrix B. * @param dev_id the device on which the function should be executed. * @param stream_id the CUDA stream on which the operation should be executed. * @param cublas the CublasCaller object that manages the cuBLAS handle. */ template -inline void square_matrix_CUDA_device(T *mat, const int row_size, - const int col_size, DevTypeID dev_id, - cudaStream_t stream_id, - const CublasCaller &cublas) { - PL_ABORT_IF(row_size != col_size, "Matrix must be square."); - const T alpha{1.0, 0.0}; - const T beta{0.0, 0.0}; - int m = row_size; - int n = row_size; - int k = col_size; - if constexpr (std::is_same_v) { - cublas.call(cublasCgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, m, - n, k, &alpha, mat, m, mat, n, &beta, mat, m); - } else if constexpr (std::is_same_v) { - cublas.call(cublasZgemm, dev_id, stream_id, CUBLAS_OP_N, CUBLAS_OP_N, m, - n, k, &alpha, mat, m, mat, n, &beta, mat, m); - } -} - -/** - * @brief cuBLAS backed square the matrix for GPU data. - * - * @tparam T Complex data-type. Accepts cuFloatComplex and cuDoubleComplex - * @param mat Device data pointer. - * @param row_size Size of the matrix row. - * @param col_size Size of the matrix column. - * @param dev_id the device on which the function should be executed. - * @param stream_id the CUDA stream on which the operation should be executed. - * @param cublas the CublasCaller object that manages the cuBLAS handle. - */ -template -inline void MM_CUDA_device(T *A, T *B, T *C, const int m, const int k, - const int n, DevTypeID dev_id, - cudaStream_t stream_id, const CublasCaller &cublas) { +inline void GEMM_CUDA_device(T *A, T *B, T *C, const int m, const int k, + const int n, DevTypeID dev_id, + cudaStream_t stream_id, + const CublasCaller &cublas) { const T alpha{1.0, 0.0}; const T beta{0.0, 0.0}; if constexpr (std::is_same_v) { diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp index b1bef2b2e2..f1855e94e1 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp @@ -18,8 +18,6 @@ #include #include -#include - #include "cuda_helpers.hpp" /// @cond DEV diff --git a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp index b3ce7f0cc8..b5b837f1e2 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp @@ -97,57 +97,3 @@ TEMPLATE_TEST_CASE("Linear Algebra::SparseMV", "[Linear Algebra]", float, } } } - -TEMPLATE_TEST_CASE("Linear Algebra::square_matrix_CUDA_device", - "[Linear Algebra]", float, double) { - using ComplexT = std::complex; - - using CFP_t = - typename std::conditional::value, - cuFloatComplex, cuDoubleComplex>::type; - - std::size_t row_size = 2; - - std::vector matrix = {{0.2, 0.2}, - {0.3, 0.3}, - {0.3, 0.4}, - {0.4, 0.5}}; // from numpy calculation - - std::vector matrix_cu; - - std::transform(matrix.begin(), matrix.end(), std::back_inserter(matrix_cu), - [](ComplexT x) { return complexToCu(x); }); - - const std::vector result_refs = { - {-0.03, 0.29}, {-0.03, 0.39}, {-0.1, 0.45}, {-0.12, 0.61}}; - - DataBuffer mat(matrix_cu.size()); - - mat.CopyHostDataToGpu(matrix_cu.data(), matrix_cu.size()); - - SECTION("Testing square matrix multiplication:") { - std::vector result(matrix_cu.size()); - auto cublas_caller = make_shared_cublas_caller(); - - square_matrix_CUDA_device(mat.getData(), row_size, row_size, - mat.getDevice(), mat.getStream(), - *cublas_caller); - - mat.CopyGpuDataToHost(result.data(), result.size()); - - for (std::size_t j = 0; j < matrix_cu.size(); j++) { - CHECK(result[j].x == Approx(real(result_refs[j]))); - CHECK(result[j].y == Approx(imag(result_refs[j]))); - } - } - - SECTION("Throwing exception for non-square matrix multiplication:") { - std::vector result(matrix_cu.size()); - auto cublas_caller = make_shared_cublas_caller(); - - CHECK_THROWS_WITH(square_matrix_CUDA_device( - mat.getData(), row_size, row_size + 1, - mat.getDevice(), mat.getStream(), *cublas_caller), - Catch::Contains("Matrix must be square.")); - } -} From 7b44e8a64ab0201de72b765ddefea84aa9f3127d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 22 Jul 2024 19:54:22 +0000 Subject: [PATCH 025/227] further tidy up --- .../tncuda/observables/ObservablesTNCudaOperator.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 657f847827..31fc076160 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -284,7 +284,6 @@ template class ObservableTNCudaOperator { tensorDataPtrPerTerm_.emplace_back( get_obs_device_ptr_(obsKey)); } - tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); } } else { @@ -297,9 +296,7 @@ template class ObservableTNCudaOperator { for (std::size_t term_idy = 0; term_idy < numObsTerms_; term_idy++) { auto coeff = cuDoubleComplex{ - static_cast(obs.getCoeffs()[term_idx] * - obs.getCoeffs()[term_idy]), - 0.0}; + coeffs_[term_idx].x * coeffs_[term_idy].x, 0.0}; coeffs2_.emplace_back(coeff); auto modes_termx = modes_[term_idx]; @@ -440,7 +437,6 @@ template class ObservableTNCudaOperator { PL_ABORT("Only one wire observables are supported " "for cutensornet v24.03"); } - // Hermitian above } modes2_.emplace_back(modes_per_term); numModes2_.emplace_back(num_modes_per_term); @@ -476,7 +472,6 @@ template class ObservableTNCudaOperator { modesPtr2_[term_idx].data(), tensorDataPtr2_[term_idx].data()); } - } else { for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { From 00beafa71fa1f9daa41f98d2ba014ce7a546b131 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 22 Jul 2024 20:00:26 +0000 Subject: [PATCH 026/227] fix typo --- .../tncuda/measurements/MeasurementsTNCuda.hpp | 11 ++++++----- .../tncuda/observables/ObservablesTNCudaOperator.hpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index c1cc7143f3..fed9f489b0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -59,7 +59,7 @@ template class MeasurementsTNCuda { : tensor_network_(tensor_network){}; /** - * @brief Calculate var value for a general Observable. + * @brief Calculate var value for a general ObservableTNCuda Observable. * * Current implementation ensure that only one cutensornetNetworkOperator_t * object is attached to the circuit. @@ -85,7 +85,8 @@ template class MeasurementsTNCuda { } /** - * @brief Calculate expectation value for a general Observable. + * @brief Calculate expectation value for a general ObservableTNCuda + * Observable. * * @param obs An Observable object. * @param numHyperSamples Number of hyper samples to use in the calculation @@ -103,15 +104,15 @@ template class MeasurementsTNCuda { private: /** - * @brief Calculate expectation value for a general ObservableTNCudaOperator + * @brief Calculate expectation value for a cutensornetNetworkOperator_t * object. * - * @param tnoperator An ObservableTNCudaOperator object. + * @param tnoperator A cutensornetNetworkOperator_t object. * @param numHyperSamples Number of hyper samples to use in the calculation * and is default as 1. * * @return Expectation value with respect to the given - * ObservableTNCudaOperator object. + * cutensornetNetworkOperator_t object. */ auto expval_(cutensornetNetworkOperator_t tnoperator, diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 31fc076160..3c22279d5d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -187,7 +187,7 @@ template class ObservableTNCudaOperator { } /** - * @brief Add metadata of observable. + * @brief Add metadata of an observable. * * @param metaData Metadata of the observable. * @return obs_key The key of observable tensor operator. From 48f74b5e111b71aebcb9cea20e3668aa1a34dde6 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 15 Jul 2024 21:16:53 +0000 Subject: [PATCH 027/227] initial commit --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 818ff1b25d..727222ed34 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "../../scipy.libs/"; + scipyPathStr = currentPathStr + "/../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From 6afbc37e8f5c6dc0db484cd4e3ab0dc2a2503452 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 22 Jul 2024 20:02:38 +0000 Subject: [PATCH 028/227] quick fix --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 727222ed34..818ff1b25d 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "/../../scipy.libs/"; + scipyPathStr = currentPathStr + "../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From 8a588e67a6d3b62ea6a7a084e11789bf7a930e67 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 22 Jul 2024 20:03:23 +0000 Subject: [PATCH 029/227] Auto update version from '0.38.0-dev12' to '0.38.0-dev13' --- 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 52575c8282..c1ad83f4ad 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.38.0-dev12" +__version__ = "0.38.0-dev13" From 2103fa07c2d6afebcd7222728c0ae15c92ff430c Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 22 Jul 2024 20:14:10 +0000 Subject: [PATCH 030/227] add more docstrings --- .../src/utils/cuda_utils/cuGates_host.hpp | 104 ++++++++++++++++-- .../src/utils/cuda_utils/cuda_helpers.hpp | 4 +- 2 files changed, 98 insertions(+), 10 deletions(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp index f1855e94e1..a95363fd9c 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp @@ -30,12 +30,12 @@ using namespace cuUtil; namespace Pennylane::LightningGPU::cuGates { /** - * @brief Create a matrix representation of the PauliX gate data in row-major + * @brief Create a matrix representation of the Identity gate data in row-major * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliX data. + * of Identity data. */ template static constexpr auto getIdentity() -> std::vector { @@ -1473,68 +1473,156 @@ static constexpr auto getP1111_CU() -> std::vector { } /** - * @brief Create a matrix representation of the PauliX gate data in row-major + * @brief Create a matrix representation of the PauliX@PauliY data in row-major * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliX data. + * of PauliX@PauliY data. */ template static constexpr auto getXY() -> std::vector { return {cuUtil::IMAG(), cuUtil::ZERO(), cuUtil::ZERO(), -cuUtil::IMAG()}; } +/** + * @brief Create a matrix representation of the PauliX@PauliZ data in row-major + * format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliX@PauliZ data. + */ template static constexpr auto getXZ() -> std::vector { return {cuUtil::ZERO(), -cuUtil::ONE(), cuUtil::ONE(), cuUtil::ZERO()}; } +/** + * @brief Create a matrix representation of the PauliX@Hadamard data in + * row-major format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliX@Hadamard data. + */ template static constexpr auto getXH() -> std::vector { return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; } +/** + * @brief Create a matrix representation of the PauliY@PauliX data in row-major + * format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliY@PauliX data. + */ template static constexpr auto getYX() -> std::vector { return {-cuUtil::IMAG(), cuUtil::ZERO(), cuUtil::ZERO(), cuUtil::IMAG()}; } +/** + * @brief Create a matrix representation of the PauliY@PauliZ data in row-major + * format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliY@PauliZ data. + */ template static constexpr auto getYZ() -> std::vector { return {cuUtil::ZERO(), cuUtil::IMAG(), cuUtil::IMAG(), cuUtil::ZERO()}; } +/** + * @brief Create a matrix representation of the PauliY@Hadamard data in + * row-major format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliY@Hadamard data. + */ template static constexpr auto getYH() -> std::vector { - return {-cuUtil::INVSQRT2I(), cuUtil::INVSQRT2I(), - cuUtil::INVSQRT2I(), cuUtil::INVSQRT2I()}; + return {-cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG(), + cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG()}; } +/** + * @brief Create a matrix representation of the PauliZ@PauliX data in row-major + * format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliZ@PauliX data. + */ template static constexpr auto getZX() -> std::vector { return {cuUtil::ZERO(), cuUtil::ONE(), -cuUtil::ONE(), cuUtil::ZERO()}; } +/** + * @brief Create a matrix representation of the PauliZ@PauliY data in row-major + * format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliZ@PauliY data. + */ template static constexpr auto getZY() -> std::vector { return {cuUtil::ZERO(), -cuUtil::IMAG(), -cuUtil::IMAG(), cuUtil::ZERO()}; } +/** + * @brief Create a matrix representation of the PauliZ@Hadamard data in + * row-major format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of PauliZ@Hadamard data. + */ template static constexpr auto getZH() -> std::vector { return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; } +/** + * @brief Create a matrix representation of the Hadamard@PauliX data in + * row-major format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of Hadamard@PauliX data. + */ template static constexpr auto getHX() -> std::vector { return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; } +/** + * @brief Create a matrix representation of the Hadamard@PauliY data in + * row-major format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of Hadamard@PauliY data. + */ template static constexpr auto getHY() -> std::vector { - return {cuUtil::INVSQRT2I(), -cuUtil::INVSQRT2I(), - -cuUtil::INVSQRT2I(), -cuUtil::INVSQRT2I()}; + return {cuUtil::INVSQRT2IMAG(), -cuUtil::INVSQRT2IMAG(), + -cuUtil::INVSQRT2IMAG(), -cuUtil::INVSQRT2IMAG()}; } +/** + * @brief Create a matrix representation of the Hadamard@PauliZ data in + * row-major format. + * + * @tparam CFP_t Required precision of gate (`float` or `double`). + * @return constexpr std::vector Return constant expression + * of Hadamard@PauliZ data. + */ template static constexpr auto getHZ() -> std::vector { return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp index c4148564b0..ba329affb1 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuda_helpers.hpp @@ -272,12 +272,12 @@ template inline static constexpr auto INVSQRT2() -> CFP_t { } /** - * @brief Returns inverse sqrt(2)i as a compile-time constant. + * @brief Returns inverse sqrt(2)*i as a compile-time constant. * * @tparam T Precision of result. `double`, `float` are accepted values. * @return constexpr T 1/sqrt(2)i */ -template inline static constexpr auto INVSQRT2I() -> CFP_t { +template inline static constexpr auto INVSQRT2IMAG() -> CFP_t { if constexpr (std::is_same_v> || std::is_same_v>) { return CFP_t(0, 1 / M_SQRT2); From bb85c5460dc1351bfa06892d7d2079dc6213ddb0 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 22 Jul 2024 20:16:15 +0000 Subject: [PATCH 031/227] typo fix --- pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp index 5f59e834d9..a06765849a 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp @@ -81,7 +81,7 @@ class CublasCaller { }; /** - * @brief cuBLAS backed square the matrix for GPU data. + * @brief cuBLAS backed matrix-matrix multiply for GPU data. * * @tparam T Complex data-type. Accepts cuFloatComplex and cuDoubleComplex * @param A Device data pointer of matrix A. From 20113a006c3700037888e38f8cff3adf966a0a25 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 26 Jul 2024 16:11:08 +0000 Subject: [PATCH 032/227] add more unit tests --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 194 +++++++++++++++--- 1 file changed, 160 insertions(+), 34 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 697c73f04f..d5fd35de28 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -176,6 +176,81 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, using HermitianObsT = HermitianObsTNCuda; using TensorProdObsT = TensorProdObsTNCuda; using HamiltonianObsT = HamiltonianTNCuda; + SECTION("Using XI") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto I1 = std::make_shared("Identity", + std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, I1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.07406834808884483)); + } + + SECTION("Using XX") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto X1 = + std::make_shared("PauliX", std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, X1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.3145904327559435)); + } + + SECTION("Using XY") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto Y1 = + std::make_shared("PauliY", std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Y1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.3142009723392052)); + } + SECTION("Using XZ") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; @@ -201,7 +276,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, CHECK(res == Approx(0.093413)); } - SECTION("Using XI") { + SECTION("Using XH") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -216,14 +291,14 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto X0 = std::make_shared("PauliX", std::vector{0}); - auto I1 = std::make_shared("Identity", + auto H1 = std::make_shared("Hadamard", std::vector{1}); auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, I1}); + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, H1}); auto res = m.var(*ob); - CHECK(res == Approx(0.07406834808884483)); + CHECK(res == Approx(0.15724601172876368)); } SECTION("Using YI") { @@ -250,7 +325,8 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto res = m.var(*ob); CHECK(res == Approx(0.06931360376406634)); } - SECTION("Using HI") { + + SECTION("Using YX") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -263,19 +339,19 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - auto H0 = std::make_shared("Hadamard", - std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); + auto Y0 = + std::make_shared("PauliY", std::vector{0}); + auto X1 = + std::make_shared("PauliX", std::vector{1}); auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, I1}); + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, X1}); auto res = m.var(*ob); - CHECK(res == Approx(0.02618050490800028)); + CHECK(res == Approx(0.30983568843116516)); } - SECTION("Using ZI") { + SECTION("Using YY") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -288,19 +364,19 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - auto Z0 = - std::make_shared("PauliZ", std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); + auto Y0 = + std::make_shared("PauliY", std::vector{0}); + auto Y1 = + std::make_shared("PauliY", std::vector{1}); auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Z0, I1}); + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, Y1}); auto res = m.var(*ob); - CHECK(res == Approx(0.03661804814708902)); + CHECK(res == Approx(0.3094462280144269)); } - SECTION("Using XY") { + SECTION("Using YZ") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -313,19 +389,44 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - auto X0 = - std::make_shared("PauliX", std::vector{0}); + auto Y0 = + std::make_shared("PauliY", std::vector{0}); + auto Z1 = + std::make_shared("PauliZ", std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, Z1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.08865889484660677)); + } + + SECTION("Using YH") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto H0 = std::make_shared("Hadamard", + std::vector{0}); auto Y1 = std::make_shared("PauliY", std::vector{1}); auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Y1}); + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, Y1}); auto res = m.var(*ob); - CHECK(res == Approx(0.314201)); + CHECK(res == Approx(0.26631312915836103)); } - SECTION("Using XH") { + SECTION("Using ZI") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -338,19 +439,19 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto H1 = std::make_shared("Hadamard", + auto Z0 = + std::make_shared("PauliZ", std::vector{0}); + auto I1 = std::make_shared("Identity", std::vector{1}); auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, H1}); + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Z0, I1}); auto res = m.var(*ob); - CHECK(res == Approx(0.15724601172876368)); + CHECK(res == Approx(0.03661804814708902)); } - SECTION("Using YH") { + SECTION("Using HI") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -365,14 +466,14 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto H0 = std::make_shared("Hadamard", std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); + auto I1 = std::make_shared("Identity", + std::vector{1}); auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, Y1}); + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, I1}); auto res = m.var(*ob); - CHECK(res == Approx(0.26631312915836103)); + CHECK(res == Approx(0.02618050490800028)); } SECTION("Using ZY") { @@ -400,6 +501,31 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, CHECK(res == Approx(0.27675067239744966)); } + SECTION("Using XY") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, + {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto Y1 = + std::make_shared("PauliY", std::vector{1}); + + auto ob = + HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Y1}); + + auto res = m.var(*ob); + CHECK(res == Approx(0.314201)); + } + SECTION("Using 1 Hermitian") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; From 3f24ca247690acd1f169a3ac02d5cfa68bd21cf3 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 26 Jul 2024 16:11:43 +0000 Subject: [PATCH 033/227] Auto update version from '0.38.0-dev13' to '0.38.0-dev18' --- 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 c1ad83f4ad..67dc4a35b2 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.38.0-dev13" +__version__ = "0.38.0-dev18" From 646e2e1a354139c1ed7f3ca933cef7069dbc724c Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 15 Jul 2024 21:16:53 +0000 Subject: [PATCH 034/227] initial commit --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 818ff1b25d..727222ed34 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "../../scipy.libs/"; + scipyPathStr = currentPathStr + "/../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From 208e67952ed4663f3daab3ecc4c473dbecb57021 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 26 Jul 2024 18:21:28 +0000 Subject: [PATCH 035/227] add more unit tests --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index d5fd35de28..424e702d43 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -176,6 +176,120 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, using HermitianObsT = HermitianObsTNCuda; using TensorProdObsT = TensorProdObsTNCuda; using HamiltonianObsT = HamiltonianTNCuda; + + SECTION("Using TensorProd") { + std::size_t bondDim = GENERATE(2); + std::size_t num_qubits = 5; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, + {"RY"}, + {"RX"}, + {"RY"}, + {"RX"}, + {"RY"}, + {"RX"}, + {"RY"}, + {"RX"}, + {"RY"}}, + {{0}, {0}, {1}, {1}, {2}, {2}, {3}, {3}, {4}, {4}}, + {{false}, + {false}, + {false}, + {false}, + {false}, + {false}, + {false}, + {false}, + {false}, + {false}}, + {{0.5}, + {0.5}, + {0.2}, + {0.2}, + {0.5}, + {0.5}, + {0.2}, + {0.2}, + {0.5}, + {0.5}}); + + auto m = MeasurementsTNCuda(mps_state); + + auto I0 = std::make_shared("Identity", + std::vector{0}); + auto X1 = + std::make_shared("PauliX", std::vector{1}); + auto Y2 = + std::make_shared("PauliY", std::vector{2}); + auto Z3 = + std::make_shared("PauliZ", std::vector{3}); + auto H4 = std::make_shared("Hadamard", + std::vector{4}); + + auto I1 = std::make_shared("Identity", + std::vector{1}); + auto X2 = + std::make_shared("PauliX", std::vector{2}); + auto Y3 = + std::make_shared("PauliY", std::vector{3}); + auto Z4 = + std::make_shared("PauliZ", std::vector{4}); + auto H0 = std::make_shared("Hadamard", + std::vector{0}); + + auto I2 = std::make_shared("Identity", + std::vector{2}); + auto X3 = + std::make_shared("PauliX", std::vector{3}); + auto Y4 = + std::make_shared("PauliY", std::vector{4}); + auto Z0 = + std::make_shared("PauliZ", std::vector{0}); + auto H1 = std::make_shared("Hadamard", + std::vector{1}); + + auto I3 = std::make_shared("Identity", + std::vector{3}); + auto X4 = + std::make_shared("PauliX", std::vector{4}); + auto Y0 = + std::make_shared("PauliY", std::vector{0}); + auto Z1 = + std::make_shared("PauliZ", std::vector{1}); + auto H2 = std::make_shared("Hadamard", + std::vector{2}); + + auto I4 = std::make_shared("Identity", + std::vector{4}); + auto X0 = + std::make_shared("PauliX", std::vector{0}); + auto Y1 = + std::make_shared("PauliY", std::vector{1}); + auto Z2 = + std::make_shared("PauliZ", std::vector{2}); + auto H3 = std::make_shared("Hadamard", + std::vector{3}); + + auto ob0 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); + auto ob1 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); + auto ob2 = TensorProdObsT::create({I1, X2, Y3, Z4, H0}); + auto ob3 = TensorProdObsT::create({I2, X3, Y4, Z0, H1}); + auto ob4 = TensorProdObsT::create({I3, X4, Y0, Z1, H2}); + auto ob5 = TensorProdObsT::create({I4, X0, Y1, Z2, H3}); + + auto ob = HamiltonianObsT::create({TestType{0.3}, TestType{0.5}, + TestType{0.3}, TestType{0.5}, + TestType{0.3}, TestType{0.5}}, + {ob0, ob1, ob2, ob3, ob4, ob5}); + + auto res = m.var(*ob); + CHECK(res == Approx(1.083014482574645)); + } + SECTION("Using XI") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; From 194d87f1ef460da4615bf26a1277c07536133d9d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 26 Jul 2024 18:27:47 +0000 Subject: [PATCH 036/227] tidy up --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 424e702d43..35b9d7dc3a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -221,58 +221,58 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto I0 = std::make_shared("Identity", std::vector{0}); - auto X1 = - std::make_shared("PauliX", std::vector{1}); - auto Y2 = - std::make_shared("PauliY", std::vector{2}); - auto Z3 = - std::make_shared("PauliZ", std::vector{3}); - auto H4 = std::make_shared("Hadamard", - std::vector{4}); - auto I1 = std::make_shared("Identity", std::vector{1}); - auto X2 = - std::make_shared("PauliX", std::vector{2}); - auto Y3 = - std::make_shared("PauliY", std::vector{3}); - auto Z4 = - std::make_shared("PauliZ", std::vector{4}); - auto H0 = std::make_shared("Hadamard", - std::vector{0}); - auto I2 = std::make_shared("Identity", std::vector{2}); - auto X3 = - std::make_shared("PauliX", std::vector{3}); - auto Y4 = - std::make_shared("PauliY", std::vector{4}); - auto Z0 = - std::make_shared("PauliZ", std::vector{0}); - auto H1 = std::make_shared("Hadamard", - std::vector{1}); - auto I3 = std::make_shared("Identity", std::vector{3}); - auto X4 = - std::make_shared("PauliX", std::vector{4}); - auto Y0 = - std::make_shared("PauliY", std::vector{0}); - auto Z1 = - std::make_shared("PauliZ", std::vector{1}); - auto H2 = std::make_shared("Hadamard", - std::vector{2}); - auto I4 = std::make_shared("Identity", std::vector{4}); + auto X0 = std::make_shared("PauliX", std::vector{0}); + auto X1 = + std::make_shared("PauliX", std::vector{1}); + auto X2 = + std::make_shared("PauliX", std::vector{2}); + auto X3 = + std::make_shared("PauliX", std::vector{3}); + auto X4 = + std::make_shared("PauliX", std::vector{4}); + + auto Y0 = + std::make_shared("PauliY", std::vector{0}); auto Y1 = std::make_shared("PauliY", std::vector{1}); + auto Y2 = + std::make_shared("PauliY", std::vector{2}); + auto Y3 = + std::make_shared("PauliY", std::vector{3}); + auto Y4 = + std::make_shared("PauliY", std::vector{4}); + + auto Z0 = + std::make_shared("PauliZ", std::vector{0}); + auto Z1 = + std::make_shared("PauliZ", std::vector{1}); auto Z2 = std::make_shared("PauliZ", std::vector{2}); + auto Z3 = + std::make_shared("PauliZ", std::vector{3}); + auto Z4 = + std::make_shared("PauliZ", std::vector{4}); + + auto H0 = std::make_shared("Hadamard", + std::vector{0}); + auto H1 = std::make_shared("Hadamard", + std::vector{1}); + auto H2 = std::make_shared("Hadamard", + std::vector{2}); auto H3 = std::make_shared("Hadamard", std::vector{3}); + auto H4 = std::make_shared("Hadamard", + std::vector{4}); auto ob0 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); auto ob1 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); From 6aeb802da1b73de834aa248228be98e39cdd5b68 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 15 Jul 2024 21:16:53 +0000 Subject: [PATCH 037/227] initial commit --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 818ff1b25d..727222ed34 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "../../scipy.libs/"; + scipyPathStr = currentPathStr + "/../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From 408dcb25a0c0c4649cfe329289c69736f8929161 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 26 Jul 2024 18:59:18 +0000 Subject: [PATCH 038/227] revert changes --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 727222ed34..818ff1b25d 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "/../../scipy.libs/"; + scipyPathStr = currentPathStr + "../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From 83c13167d669807fba97c7b068398aefa57dc0ff Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 26 Jul 2024 18:59:41 +0000 Subject: [PATCH 039/227] Auto update version from '0.38.0-dev18' to '0.38.0-dev19' --- 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 67dc4a35b2..e08dc521d2 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.38.0-dev18" +__version__ = "0.38.0-dev19" From c83fa7ac2923350606186f394263b54a72bcc813 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 26 Jul 2024 19:10:42 +0000 Subject: [PATCH 040/227] remove some unit tests --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 367 +----------------- 1 file changed, 12 insertions(+), 355 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 35b9d7dc3a..f088a417fb 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -290,282 +290,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, CHECK(res == Approx(1.083014482574645)); } - SECTION("Using XI") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, I1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.07406834808884483)); - } - - SECTION("Using XX") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto X1 = - std::make_shared("PauliX", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, X1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.3145904327559435)); - } - - SECTION("Using XY") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Y1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.3142009723392052)); - } - - SECTION("Using XZ") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto Z1 = - std::make_shared("PauliZ", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Z1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.093413)); - } - - SECTION("Using XH") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto H1 = std::make_shared("Hadamard", - std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, H1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.15724601172876368)); - } - - SECTION("Using YI") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto Y0 = - std::make_shared("PauliY", std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, I1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.06931360376406634)); - } - - SECTION("Using YX") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto Y0 = - std::make_shared("PauliY", std::vector{0}); - auto X1 = - std::make_shared("PauliX", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, X1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.30983568843116516)); - } - - SECTION("Using YY") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto Y0 = - std::make_shared("PauliY", std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, Y1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.3094462280144269)); - } - - SECTION("Using YZ") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto Y0 = - std::make_shared("PauliY", std::vector{0}); - auto Z1 = - std::make_shared("PauliZ", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Y0, Z1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.08865889484660677)); - } - - SECTION("Using YH") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto H0 = std::make_shared("Hadamard", - std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, Y1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.26631312915836103)); - } - - SECTION("Using ZI") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto Z0 = - std::make_shared("PauliZ", std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Z0, I1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.03661804814708902)); - } - - SECTION("Using HI") { + SECTION("Using 1 Hermitian") { std::size_t bondDim = GENERATE(2); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -578,96 +303,28 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - auto H0 = std::make_shared("Hadamard", - std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {H0, I1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.02618050490800028)); - } - - SECTION("Using ZY") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; + std::vector matrix = { + {0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}}; - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + auto Herm0 = std::make_shared( + matrix, std::vector{0}); - auto m = MeasurementsTNCuda(mps_state); + auto Herm1 = std::make_shared( + matrix, std::vector{1}); auto Z0 = std::make_shared("PauliZ", std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {Z0, Y1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.27675067239744966)); - } - - SECTION("Using XY") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); - - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Y1}); - - auto res = m.var(*ob); - CHECK(res == Approx(0.314201)); - } - - SECTION("Using 1 Hermitian") { - std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, - {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); - - auto m = MeasurementsTNCuda(mps_state); - - std::vector matrix = { - {0.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}}; - - auto X0 = std::make_shared(matrix, - std::vector{0}); auto Z1 = std::make_shared("PauliZ", std::vector{1}); - auto ob_term = TensorProdObsT::create({X0, Z1}); + auto obs0 = TensorProdObsT::create({Z0, Z1}); + auto obs1 = TensorProdObsT::create({Herm0, Herm1}); - auto ob = - HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Z1}); + auto ob = HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, + {obs0, obs1}); auto res = m.var(*ob); - CHECK(res == Approx(0.093413)); + CHECK(res == Approx(0.24231647427614533)); } SECTION("Using 2 Hermitians") { From afb283154f2e8f972107bd0c5ff508d8192beb63 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 26 Jul 2024 20:17:49 +0000 Subject: [PATCH 041/227] set ref result with 8 significant figures --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index f088a417fb..6e42fb79a3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -65,7 +65,7 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, mps_state.append_mps_final_state(); auto ob = NamedObsT("PauliX", {0}); auto res = measure.var(ob); - auto expected = TestType(0.7572222074); + auto expected = TestType(0.75722220); CHECK(res == Approx(expected)); } @@ -76,7 +76,7 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, mps_state.append_mps_final_state(); auto ob = NamedObsT("PauliY", {0}); auto res = measure.var(ob); - auto expected = TestType(0.5849835715); + auto expected = TestType(0.58498357); CHECK(res == Approx(expected)); } @@ -87,7 +87,7 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, mps_state.append_mps_final_state(); auto ob = NamedObsT("PauliZ", {1}); auto res = measure.var(ob); - auto expected = TestType(0.4068672016); + auto expected = TestType(0.40686720); CHECK(res == Approx(expected)); } @@ -98,7 +98,7 @@ TEMPLATE_TEST_CASE("Test variance of NamedObs", "[MPSTNCuda_Var]", float, mps_state.append_mps_final_state(); auto ob = NamedObsT("Hadamard", {1}); auto res = measure.var(ob); - auto expected = TestType(0.2908944989); + auto expected = TestType(0.29089449); CHECK(res == Approx(expected)); } } @@ -130,7 +130,7 @@ TEMPLATE_TEST_CASE("Test variance of HermitianObs", "[MPSTNCuda_Var]", float, auto ob = HermitianObsT(matrix, {0}); auto res = measure.var(ob); - auto expected = TestType(1.8499002205); // from default.qubit + auto expected = TestType(1.8499002); // from default.qubit CHECK(res == Approx(expected)); } } @@ -163,7 +163,7 @@ TEMPLATE_TEST_CASE("Test variance of TensorProdObs", "[MPSTNCuda_Var]", float, auto ob = TensorProdObsT::create({X0, Z1}); auto res = measure.var(*ob); - auto expected = TestType(0.836679); + auto expected = TestType(0.83667953); CHECK(expected == Approx(res)); } } @@ -216,6 +216,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, {0.2}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); auto m = MeasurementsTNCuda(mps_state); @@ -287,7 +288,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, {ob0, ob1, ob2, ob3, ob4, ob5}); auto res = m.var(*ob); - CHECK(res == Approx(1.083014482574645)); + CHECK(res == Approx(1.0830144)); } SECTION("Using 1 Hermitian") { @@ -301,6 +302,8 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + mps_state.append_mps_final_state(); + auto m = MeasurementsTNCuda(mps_state); std::vector matrix = { @@ -324,7 +327,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, {obs0, obs1}); auto res = m.var(*ob); - CHECK(res == Approx(0.24231647427614533)); + CHECK(res == Approx(0.24231647)); } SECTION("Using 2 Hermitians") { @@ -338,6 +341,8 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, {{"RX"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}}, {{false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}}); + mps_state.append_mps_final_state(); + auto m = MeasurementsTNCuda(mps_state); std::vector matrix = { @@ -351,12 +356,10 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto Z1 = std::make_shared(matrix_z, std::vector{1}); - auto ob_term = TensorProdObsT::create({X0, Z1}); - auto ob = HamiltonianObsT::create({TestType{0.3}, TestType{0.5}}, {X0, Z1}); auto res = m.var(*ob); - CHECK(res == Approx(0.093413)); + CHECK(res == Approx(0.09341363)); } } From 1cdb53842f9f6faf5bf8c75d3547c7d4e2a938e9 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 29 Jul 2024 15:13:37 +0000 Subject: [PATCH 042/227] update `ObservableTNCudaOperator` --- .../observables/ObservablesTNCudaOperator.hpp | 95 ++++++++++--------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 3c22279d5d..693da1b084 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -160,6 +160,45 @@ template class ObservableTNCudaOperator { add_obs_(obsKey, gateMap.getGateData(obs_name, obs_param)); } + /** + * @brief Create a map of modes to observable meta data. + * + * @param obs An observableTNCuda object. + * @param i Index of the first observable term. + * @param j Index of the second observable term. + * + * @return std::unordered_map> Map of modes + * to observable meta data. + */ + auto create_modes_obsname_map_(ObservableTNCuda &obs, + const std::size_t i, const std::size_t j) + -> std::unordered_map> { + std::unordered_map> modes_obsname_map; + for (std::size_t tensor_idx = 0; tensor_idx < modes_[i].size(); + tensor_idx++) { + PL_ABORT_IF_NOT(modes_[i][tensor_idx].size() == 1, + "Only one-wire observables are supported for " + "cutensornet v24.03"); + + modes_obsname_map[modes_[i][tensor_idx][0]] = { + obs.getMetaData()[i][tensor_idx]}; + } + + for (std::size_t tensor_idy = 0; tensor_idy < modes_[j].size(); + tensor_idy++) { + auto it = modes_obsname_map.find(modes_[j][tensor_idy].front()); + if (it != modes_obsname_map.end()) { + modes_obsname_map[modes_[j][tensor_idy].front()].push_back( + obs.getMetaData()[j][tensor_idy]); + } else { + modes_obsname_map[modes_[j][tensor_idy].front()] = { + obs.getMetaData()[j][tensor_idy]}; + } + } + + return modes_obsname_map; + } + /** * @brief Add observable numerical value to the cache map, the name, * parameters and hash value(default as 0 for named observables). @@ -299,37 +338,8 @@ template class ObservableTNCudaOperator { coeffs_[term_idx].x * coeffs_[term_idy].x, 0.0}; coeffs2_.emplace_back(coeff); - auto modes_termx = modes_[term_idx]; - auto modes_termy = modes_[term_idy]; - - std::unordered_map> - modes_obsname_map; // Note that one-wire observables are - // supported as cutensornet v24.03 - - for (std::size_t tensor_idx = 0; - tensor_idx < modes_termx.size(); tensor_idx++) { - PL_ABORT_IF_NOT(modes_termx[tensor_idx].size() == 1, - "Only one-wire observables are " - "supported for cutensornet v24.03"); - - modes_obsname_map[modes_termx[tensor_idx][0]] = { - obs.getMetaData()[term_idx][tensor_idx]}; - } - - for (std::size_t tensor_idy = 0; - tensor_idy < modes_termy.size(); tensor_idy++) { - auto it = modes_obsname_map.find( - modes_termy[tensor_idy].front()); - if (it != modes_obsname_map.end()) { - modes_obsname_map[modes_termy[tensor_idy].front()] - .push_back( - obs.getMetaData()[term_idy][tensor_idy]); - } else { - modes_obsname_map[modes_termy[tensor_idy].front()] = - {obs.getMetaData()[term_idy][tensor_idy]}; - } - } + auto modes_obsname_map = + create_modes_obsname_map_(obs, term_idx, term_idy); auto numTensorsPerTerm = modes_obsname_map.size(); @@ -376,24 +386,18 @@ template class ObservableTNCudaOperator { } else { // Branch for Hermtian involving Pauli strings // add both observables matrix to GPU cache - auto obsKey0 = add_meta_data_(metaDataArr[0]); - auto obsKey1 = add_meta_data_(metaDataArr[1]); - auto obsName = obsName0 + "@" + obsName1; - std::size_t hash_val = 0; - auto hermitianMatrix = std::get<2>(metaDataArr[0]); - if (!std::get<2>(metaDataArr[1]).empty()) { - hermitianMatrix.insert( - hermitianMatrix.end(), - std::get<2>(metaDataArr[1]).begin(), - std::get<2>(metaDataArr[1]).end()); - } + hermitianMatrix.insert( + hermitianMatrix.end(), + std::get<2>(metaDataArr[1]).begin(), + std::get<2>(metaDataArr[1]).end()); - hash_val = MatrixHasher()(hermitianMatrix); + std::size_t hash_val = + MatrixHasher()(hermitianMatrix); auto obsKey = std::make_tuple( obsName, std::vector{}, @@ -413,6 +417,11 @@ template class ObservableTNCudaOperator { add_obs_(obsKey, hermitianMatrix_cu); + auto obsKey0 = + add_meta_data_(metaDataArr[0]); + auto obsKey1 = + add_meta_data_(metaDataArr[1]); + // update the matrix data with MM operation CFP_t *mat0 = const_cast( get_obs_device_ptr_(obsKey0)); From c9d430e7ed7b46aa8d74e2e8647ab46e0c29f87d Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 29 Jul 2024 15:13:59 +0000 Subject: [PATCH 043/227] Auto update version from '0.38.0-dev19' to '0.38.0-dev20' --- 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 e08dc521d2..2ee21e257c 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.38.0-dev19" +__version__ = "0.38.0-dev20" From ea68235d4ab8c08f148711ec4eaf0527a2f93c14 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 29 Jul 2024 21:06:21 +0000 Subject: [PATCH 044/227] unify private data for ObservableTNCudaOperator --- .../observables/ObservablesTNCudaOperator.hpp | 170 +++++++++--------- 1 file changed, 82 insertions(+), 88 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 693da1b084..d41aba0660 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -78,7 +78,6 @@ template class ObservableTNCudaOperator { {"Hadamard", "H"}}; private: - SharedCublasCaller cublascaller_; cutensornetNetworkOperator_t obsOperator_{ nullptr}; // cutensornetNetworkOperator operator @@ -101,21 +100,6 @@ template class ObservableTNCudaOperator { std::vector ids_; // ids for each term in the graph - std::size_t numObsTerms2_; // number of observable terms - vector1D coeffs2_; // coefficients for each term - vector1D numTensors2_; // number of tensors in each term - - vector2D - numModes2_; // number of state modes of each tensor in each term - - vector3D modes2_; // modes for each tensor in each term - - vector2D - modesPtr2_; // pointers for modes of each tensor in each term - - vector2D - tensorDataPtr2_; // pointers for each tensor data in each term - const bool var_cal_ = false; private: @@ -164,35 +148,42 @@ template class ObservableTNCudaOperator { * @brief Create a map of modes to observable meta data. * * @param obs An observableTNCuda object. - * @param i Index of the first observable term. - * @param j Index of the second observable term. + * @param modes Modes of all observable terms. + * @param term_idx Index of the first observable term. + * @param term_idy Index of the second observable term. * * @return std::unordered_map> Map of modes * to observable meta data. */ auto create_modes_obsname_map_(ObservableTNCuda &obs, - const std::size_t i, const std::size_t j) + const vector3D &modes, + const std::size_t term_idx, + const std::size_t term_idy) -> std::unordered_map> { std::unordered_map> modes_obsname_map; - for (std::size_t tensor_idx = 0; tensor_idx < modes_[i].size(); + + auto modes_termx = modes[term_idx]; + auto modes_termy = modes[term_idy]; + + for (std::size_t tensor_idx = 0; tensor_idx < modes_termx.size(); tensor_idx++) { - PL_ABORT_IF_NOT(modes_[i][tensor_idx].size() == 1, - "Only one-wire observables are supported for " - "cutensornet v24.03"); + PL_ABORT_IF_NOT(modes_termx[tensor_idx].size() == 1, + "Only one-wire observables are " + "supported for cutensornet v24.03"); - modes_obsname_map[modes_[i][tensor_idx][0]] = { - obs.getMetaData()[i][tensor_idx]}; + modes_obsname_map[modes_termx[tensor_idx][0]] = { + obs.getMetaData()[term_idx][tensor_idx]}; } - for (std::size_t tensor_idy = 0; tensor_idy < modes_[j].size(); + for (std::size_t tensor_idy = 0; tensor_idy < modes_termy.size(); tensor_idy++) { - auto it = modes_obsname_map.find(modes_[j][tensor_idy].front()); + auto it = modes_obsname_map.find(modes_termy[tensor_idy].front()); if (it != modes_obsname_map.end()) { - modes_obsname_map[modes_[j][tensor_idy].front()].push_back( - obs.getMetaData()[j][tensor_idy]); + modes_obsname_map[modes_termy[tensor_idy].front()].push_back( + obs.getMetaData()[term_idy][tensor_idy]); } else { - modes_obsname_map[modes_[j][tensor_idy].front()] = { - obs.getMetaData()[j][tensor_idy]}; + modes_obsname_map[modes_termy[tensor_idy].front()] = { + obs.getMetaData()[term_idy][tensor_idy]}; } } @@ -273,35 +264,31 @@ template class ObservableTNCudaOperator { const bool var_cal = false) : tensor_network_{tensor_network}, numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { - numTensors_ = obs.getNumTensors(); // number of tensors in each term - - for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { - PrecisionT coeff_real = obs.getCoeffs()[term_idx]; - auto coeff = cuDoubleComplex{static_cast(coeff_real), 0.0}; - auto numTensors = numTensors_[term_idx]; - - coeffs_.emplace_back(coeff); - - // number of state modes of each tensor in each term - numModes_.emplace_back(cast_vector( - obs.getNumStateModes()[term_idx])); - - // modes initialization - vector2D modes_per_term; - for (std::size_t tensor_idx = 0; tensor_idx < numTensors; - tensor_idx++) { - modes_per_term.emplace_back( - cuUtil::NormalizeCastIndices( - obs.getStateModes()[term_idx][tensor_idx], - tensor_network.getNumQubits())); - } - modes_.emplace_back(modes_per_term); - } - if (!var_cal) { for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { - auto numTensors = numTensors_[term_idx]; + PrecisionT coeff_real = obs.getCoeffs()[term_idx]; + auto coeff = + cuDoubleComplex{static_cast(coeff_real), 0.0}; + auto numTensors = obs.getNumTensors()[term_idx]; + + coeffs_.emplace_back(coeff); + numTensors_.emplace_back(numTensors); + + // number of state modes of each tensor in each term + numModes_.emplace_back(cast_vector( + obs.getNumStateModes()[term_idx])); + + // modes initialization + vector2D modes_per_term; + for (std::size_t tensor_idx = 0; tensor_idx < numTensors; + tensor_idx++) { + modes_per_term.emplace_back( + cuUtil::NormalizeCastIndices( + obs.getStateModes()[term_idx][tensor_idx], + tensor_network.getNumQubits())); + } + modes_.emplace_back(modes_per_term); // Not required for var calculation below // modes pointer initialization @@ -326,24 +313,40 @@ template class ObservableTNCudaOperator { tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); } } else { - cublascaller_ = make_shared_cublas_caller(); + SharedCublasCaller cublascaller = make_shared_cublas_caller(); - numObsTerms2_ = numObsTerms_ * numObsTerms_; + // convert obs modes from std::size_t to int32_t + vector3D modes; + for (std::size_t term_idx = 0; term_idx < numObsTerms_; + term_idx++) { + vector2D modes_per_term; + for (std::size_t tensor_idx = 0; + tensor_idx < obs.getNumTensors()[term_idx]; tensor_idx++) { + modes_per_term.emplace_back( + cuUtil::NormalizeCastIndices( + obs.getStateModes()[term_idx][tensor_idx], + tensor_network.getNumQubits())); + } + modes.emplace_back(modes_per_term); + } for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { for (std::size_t term_idy = 0; term_idy < numObsTerms_; term_idy++) { - auto coeff = cuDoubleComplex{ - coeffs_[term_idx].x * coeffs_[term_idy].x, 0.0}; - coeffs2_.emplace_back(coeff); + PrecisionT coeff_real = + obs.getCoeffs()[term_idx] * obs.getCoeffs()[term_idy]; + auto coeff = + cuDoubleComplex{static_cast(coeff_real), 0.0}; - auto modes_obsname_map = - create_modes_obsname_map_(obs, term_idx, term_idy); + coeffs_.emplace_back(coeff); + + auto modes_obsname_map = create_modes_obsname_map_( + obs, modes, term_idx, term_idy); auto numTensorsPerTerm = modes_obsname_map.size(); - numTensors2_.emplace_back(numTensorsPerTerm); + numTensors_.emplace_back(numTensorsPerTerm); vector2D modes_per_term; vector1D tensorDataPtrPerTerm_; @@ -437,7 +440,7 @@ template class ObservableTNCudaOperator { .getDeviceID(), tensor_network_.getDevTag() .getStreamID(), - *cublascaller_); + *cublascaller); } tensorDataPtrPerTerm_.emplace_back( get_obs_device_ptr_(obsKey)); @@ -447,18 +450,18 @@ template class ObservableTNCudaOperator { "for cutensornet v24.03"); } } - modes2_.emplace_back(modes_per_term); - numModes2_.emplace_back(num_modes_per_term); + modes_.emplace_back(modes_per_term); + numModes_.emplace_back(num_modes_per_term); // modes pointer initialization vector1D modesPtrPerTerm; for (std::size_t tensor_idx = 0; - tensor_idx < modes2_.back().size(); tensor_idx++) { + tensor_idx < modes_.back().size(); tensor_idx++) { modesPtrPerTerm.emplace_back( - modes2_.back()[tensor_idx].data()); + modes_.back()[tensor_idx].data()); } - modesPtr2_.emplace_back(modesPtrPerTerm); - tensorDataPtr2_.emplace_back(tensorDataPtrPerTerm_); + modesPtr_.emplace_back(modesPtrPerTerm); + tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); } } } @@ -473,22 +476,13 @@ template class ObservableTNCudaOperator { /* cudaDataType_t */ tensor_network.getCudaDataType(), /* cutensornetNetworkOperator_t */ &obsOperator_)); - if (var_cal) { - for (std::size_t term_idx = 0; term_idx < numObsTerms2_; - term_idx++) { - appendTNOperator_(coeffs2_[term_idx], numTensors2_[term_idx], - numModes2_[term_idx].data(), - modesPtr2_[term_idx].data(), - tensorDataPtr2_[term_idx].data()); - } - } else { - for (std::size_t term_idx = 0; term_idx < numObsTerms_; - term_idx++) { - appendTNOperator_(coeffs_[term_idx], numTensors_[term_idx], - numModes_[term_idx].data(), - modesPtr_[term_idx].data(), - tensorDataPtr_[term_idx].data()); - } + const std::size_t numObsTerms = + var_cal ? (numObsTerms_ * numObsTerms_) : numObsTerms_; + for (std::size_t term_idx = 0; term_idx < numObsTerms; term_idx++) { + appendTNOperator_(coeffs_[term_idx], numTensors_[term_idx], + numModes_[term_idx].data(), + modesPtr_[term_idx].data(), + tensorDataPtr_[term_idx].data()); } } From 03c2628b2992e5241314268959cbc276af1aaf51 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 15 Jul 2024 21:16:53 +0000 Subject: [PATCH 045/227] initial commit --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 818ff1b25d..727222ed34 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "../../scipy.libs/"; + scipyPathStr = currentPathStr + "/../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From b1aea0163f369e42fa101dda022e18169b0a409c Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 29 Jul 2024 21:10:28 +0000 Subject: [PATCH 046/227] revert some changes --- pennylane_lightning/core/src/utils/UtilLinearAlg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 727222ed34..818ff1b25d 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -150,7 +150,7 @@ void compute_diagonalizing_gates(int n, int lda, } } else { try { - scipyPathStr = currentPathStr + "/../../scipy.libs/"; + scipyPathStr = currentPathStr + "../../scipy.libs/"; // convert the relative path to absolute path scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); From 89deb72c0077547a42733e2d942b79700dda10e6 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 29 Jul 2024 21:16:49 +0000 Subject: [PATCH 047/227] Auto update version from '0.38.0-dev20' to '0.38.0-dev21' --- 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 2ee21e257c..b0db6142fe 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.38.0-dev20" +__version__ = "0.38.0-dev21" From 7d1d66933c1f8d94a8be819c4381be53b1a5eb8d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 30 Jul 2024 20:09:17 +0000 Subject: [PATCH 048/227] initial commit --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 21 +--- .../lightning_tensor/tncuda/TNCudaBase.hpp | 118 +++++++++++++++++- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 19 +++ .../lightning_tensor/_tensornet.py | 7 ++ tests/test_apply.py | 4 +- tests/test_templates.py | 6 +- 6 files changed, 149 insertions(+), 26 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index e6754f92f2..ff5542c473 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -262,31 +262,12 @@ class MPSTNCuda final : public TNCudaBase> { /** * @brief Get the full state vector representation of a MPS quantum state. * - * NOTE: This method is for MPS unit tests purpose only, given that full - * state vector requires too much memory (`exp2(numQubits)`) in large - * systems. * * @return std::vector Full state vector representation of MPS * quantum state on host */ auto getDataVector() -> std::vector { - // 1D representation - std::vector output_modes(std::size_t{1}, std::size_t{1}); - std::vector output_extent( - std::size_t{1}, std::size_t{1} << BaseType::getNumQubits()); - TensorCuda output_tensor(output_modes.size(), output_modes, - output_extent, - BaseType::getDevTag()); - - void *output_tensorPtr[] = { - static_cast(output_tensor.getDataBuffer().getData())}; - - BaseType::computeState(nullptr, output_tensorPtr); - - std::vector results(output_extent.front()); - output_tensor.CopyGpuDataToHost(results.data(), results.size()); - - return results; + return BaseType::get_state_tensor(); } private: diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index ea21984a39..28578e9d58 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -27,6 +27,7 @@ #include #include +#include "LinearAlg.hpp" #include "TNCudaGateCache.hpp" #include "TensorBase.hpp" #include "TensorCuda.hpp" @@ -293,6 +294,121 @@ class TNCudaBase : public TensornetBase { /* int32_t unitary*/ 1)); } + auto get_state_tensor(const int32_t numHyperSamples = 1) { + std::vector wires(BaseType::getNumQubits()); + std::iota(wires.begin(), wires.end(), 0); + return get_state_tensor(wires, numHyperSamples); + } + + auto get_state_tensor(const std::vector &wires, + const int32_t numHyperSamples = 1) + -> std::vector { + std::vector sorted_wires(wires); + + std::sort(sorted_wires.begin(), sorted_wires.end(), + std::less()); + + const std::size_t length = std::size_t{1} << wires.size(); + + std::vector h_res(length); + + DataBuffer d_output_tensor(length, getDevTag(), true); + + auto stateModes = cuUtil::NormalizeCastIndices( + wires, BaseType::getNumQubits()); + + std::vector projected_modes; + + for (std::size_t idx = 0; idx < BaseType::getNumQubits(); idx++) { + auto it = std::find(stateModes.begin(), stateModes.end(), + static_cast(idx)); + if (it == stateModes.end()) { + projected_modes.emplace_back(static_cast(idx)); + } + } + + std::vector projectedModeValues(projected_modes.size(), 1); + + cutensornetStateAccessor_t accessor; + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateAccessor( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* int32_t numProjectedModes */ + static_cast(projected_modes.size()), + /* const int32_t *projectedModes */ projected_modes.data(), + /* const int64_t *amplitudesTensorStrides */ nullptr, + /* cutensornetStateAccessor_t *tensorNetworkAccessor*/ &accessor)); + + // Configure the computation + cutensornetAccessorAttributes_t accessor_attribute = + CUTENSORNET_ACCESSOR_CONFIG_NUM_HYPER_SAMPLES; + PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorConfigure( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetStateAccessor_t */ accessor, + /* cutensornetAccessorAttributes_t */ accessor_attribute, + /* const void * */ &numHyperSamples, + /* size_t */ sizeof(numHyperSamples))); + + // prepare the computation + cutensornetWorkspaceDescriptor_t workDesc; + PL_CUTENSORNET_IS_SUCCESS( + cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); + + // TODO we assign half (magic number is) of free memory size to the + // maximum memory usage. + const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; + + PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorPrepare( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetStateAccessor_t*/ accessor, + /* size_t */ scratchSize, + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* cudaStream_t unused as of v24.03 */ 0x0)); + + // Allocate workspace buffer + std::size_t worksize = + getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); + + PL_ABORT_IF(worksize > scratchSize, + "Insufficient workspace size on Device!"); + + const std::size_t d_scratch_length = worksize / sizeof(std::size_t); + DataBuffer d_scratch(d_scratch_length, getDevTag(), + true); + + setWorkSpaceMemory(getTNCudaHandle(), workDesc, + reinterpret_cast(d_scratch.getData()), + worksize); + + // compute the specified slice of the quantum circuit amplitudes tensor + ComplexT stateNorm2{0.0, 0.0}; + PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorCompute( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetStateAccessor_t */ accessor, + /* const int64_t * projectedModeValues */ + projectedModeValues.data(), + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* void *amplitudesTensor*/ + static_cast(d_output_tensor.getData()), + /* void *stateNorm */ static_cast(&stateNorm2), + /* cudaStream_t cudaStream */ 0x0)); + + ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; + + CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; + + SharedCublasCaller cublascaller = make_shared_cublas_caller(); + + scaleC_CUDA(scale_scalar_cu, d_output_tensor.getData(), + d_output_tensor.getLength(), + getDevTag().getDeviceID(), + getDevTag().getStreamID(), *cublascaller); + + d_output_tensor.CopyGpuDataToHost(h_res.data(), h_res.size()); + + return h_res; + } + protected: /** * @brief Save quantumState information to data provided by a user @@ -313,7 +429,7 @@ class TNCudaBase : public TensornetBase { /* cutensornetState_t */ getQuantumState(), /* size_t maxWorkspaceSizeDevice */ scratchSize, /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* cudaStream_t unused in v24.03*/ 0x0)); + /* cudaStream_t unused as of v24.03*/ 0x0)); std::size_t worksize = getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index 39bb9fa61c..c205ac2021 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -53,12 +53,31 @@ using TensorNetBackends = template void registerBackendClassSpecificBindings(PyClass &pyclass) { registerGatesForTensorNet(pyclass); + using PrecisionT = typename TensorNet::PrecisionT; // TensorNet's precision + using ParamT = PrecisionT; // Parameter's data precision + + using np_arr_c = py::array_t, + py::array::c_style | py::array::forcecast>; pyclass .def(py::init()) // num_qubits, max_bond_dim .def(py::init>()) // num_qubits, max_bond_dim, dev-tag + .def( + "getState", + [](const TensorNet &tensor_network, np_arr_c &state) { + py::buffer_info numpyArrayInfo = state.request(); + auto *data_ptr = + static_cast *>(numpyArrayInfo.ptr); + if (state.size()) { + std::copy(tensor_network.getDataVector(), + tensor_network.getDataVector() + + tensor_network.getDataVector().size(), + data_ptr); + } + }, + "Copy StateVector data into a Numpy array.") .def( "setBasisState", [](TensorNet &tensor_network, diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index cf9eceb150..eab81f6be0 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -90,6 +90,13 @@ def tensornet(self): """Returns a handle to the tensor network.""" return self._tensornet + @property + def state(self): + """Copy the state vector data to a numpy array.""" + state = np.zeros(2**self._num_wires, dtype=self.dtype) + self._tensornet.getState(state) + return state + def _tensornet_dtype(self): """Binding to Lightning Managed tensor network C++ class. diff --git a/tests/test_apply.py b/tests/test_apply.py index 9b89c60f48..cb441753d2 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -31,8 +31,8 @@ @pytest.mark.skipif( - ld._new_API or device_name == "lightning.tensor", - reason="Old API required, lightning.tensor does not support qml.state().", + ld._new_API, + reason="Old API required.", ) class TestApply: """Tests that operations of certain operations are applied correctly or diff --git a/tests/test_templates.py b/tests/test_templates.py index 69dc85f6f3..142e397ac7 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -131,7 +131,7 @@ def circuit(f=None): if not first_op: qml.Hadamard(0) qml.AmplitudeEmbedding(features=f, wires=range(n_qubits)) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() X = np.random.rand(2**n_qubits) X /= np.linalg.norm(X) @@ -172,7 +172,7 @@ def test_displacementembedding(self, n_qubits, template): def circuit(feature_vector): template(features=feature_vector, wires=range(n_qubits)) qml.QuadraticPhase(0.1, wires=1) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() X = np.arange(1, n_qubits + 1) @@ -237,7 +237,7 @@ def test_cvneuralnetlayers(self): def circuit(weights): qml.CVNeuralNetLayers(*weights, wires=[0, 1]) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() shapes = qml.CVNeuralNetLayers.shape(n_layers=2, n_wires=n_qubits) weights = [np.random.random(shape) for shape in shapes] From b893ac8fc75fa3e7bd9e3313e9b98e39a5ea89b3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 30 Jul 2024 21:14:10 +0000 Subject: [PATCH 049/227] free resource --- .../core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 28578e9d58..ba41f96b20 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -406,6 +406,9 @@ class TNCudaBase : public TensornetBase { d_output_tensor.CopyGpuDataToHost(h_res.data(), h_res.size()); + PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyWorkspaceDescriptor(workDesc)); + PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); + return h_res; } From f770bdce8597f9d656272b9dbcd59a8de60b5c8b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 13:07:53 +0000 Subject: [PATCH 050/227] add prob support --- .../lightning_tensor/tncuda/CMakeLists.txt | 4 +- .../lightning_tensor/tncuda/TNCudaBase.hpp | 42 ++++++--- .../tncuda/cuda_kernels_ltensor.cu | 94 +++++++++++++++++++ .../measurements/MeasurementsTNCuda.hpp | 45 +++++++++ 4 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt index 49630b536f..39250497d8 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt @@ -9,7 +9,7 @@ message(${LOGO}) project(${PL_BACKEND} DESCRIPTION "Lightning-Tensor MPS bindings for PennyLane. Backed by NVIDIA cuQuantum SDK." - LANGUAGES CXX C + LANGUAGES CXX C CUDA ) include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pllgpu.cmake") @@ -17,7 +17,7 @@ include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pltensortncuda.cmake") findCUDATK(lightning_external_libs) findCutensornet(lightning_external_libs) -set(LTENSOR_MPS_FILES MPSTNCuda.cpp CACHE INTERNAL "" FORCE) +set(LTENSOR_MPS_FILES MPSTNCuda.cpp cuda_kernels_ltensor.cu CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND} STATIC ${LTENSOR_MPS_FILES}) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index ba41f96b20..e607145822 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -294,7 +294,16 @@ class TNCudaBase : public TensornetBase { /* int32_t unitary*/ 1)); } - auto get_state_tensor(const int32_t numHyperSamples = 1) { + /** + * @brief Get full state tensor + * + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Full state tensor on the host memory + */ + auto get_state_tensor(const int32_t numHyperSamples = 1) + -> std::vector { std::vector wires(BaseType::getNumQubits()); std::iota(wires.begin(), wires.end(), 0); return get_state_tensor(wires, numHyperSamples); @@ -303,17 +312,24 @@ class TNCudaBase : public TensornetBase { auto get_state_tensor(const std::vector &wires, const int32_t numHyperSamples = 1) -> std::vector { - std::vector sorted_wires(wires); - - std::sort(sorted_wires.begin(), sorted_wires.end(), - std::less()); - const std::size_t length = std::size_t{1} << wires.size(); std::vector h_res(length); DataBuffer d_output_tensor(length, getDevTag(), true); + get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), + wires, numHyperSamples); + + d_output_tensor.CopyGpuDataToHost(h_res.data(), h_res.size()); + + return h_res; + } + + void get_state_tensor(CFP_t *tensor_data, + const std::size_t tensor_data_size, + const std::vector &wires, + const int32_t numHyperSamples = 1) { auto stateModes = cuUtil::NormalizeCastIndices( wires, BaseType::getNumQubits()); @@ -389,7 +405,7 @@ class TNCudaBase : public TensornetBase { projectedModeValues.data(), /* cutensornetWorkspaceDescriptor_t */ workDesc, /* void *amplitudesTensor*/ - static_cast(d_output_tensor.getData()), + static_cast(tensor_data), /* void *stateNorm */ static_cast(&stateNorm2), /* cudaStream_t cudaStream */ 0x0)); @@ -399,17 +415,13 @@ class TNCudaBase : public TensornetBase { SharedCublasCaller cublascaller = make_shared_cublas_caller(); - scaleC_CUDA(scale_scalar_cu, d_output_tensor.getData(), - d_output_tensor.getLength(), - getDevTag().getDeviceID(), + scaleC_CUDA(scale_scalar_cu, tensor_data, + tensor_data_size, getDevTag().getDeviceID(), getDevTag().getStreamID(), *cublascaller); - d_output_tensor.CopyGpuDataToHost(h_res.data(), h_res.size()); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyWorkspaceDescriptor(workDesc)); + PL_CUTENSORNET_IS_SUCCESS( + cutensornetDestroyWorkspaceDescriptor(workDesc)); PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); - - return h_res; } protected: diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu new file mode 100644 index 0000000000..f31c2fb02e --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu @@ -0,0 +1,94 @@ +// Copyright 2024 Xanadu Quantum Technologies Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** + * @file cuda_kernels_ltensor.cu + */ +#include + +#include "cuError.hpp" +#include "cuda_helpers.hpp" + +namespace Pennylane::LightningTensor::TNCuda { +/** + * @brief Explicitly get the probability of given state tensor data on GPU device. + * + * @param state Complex data pointer of state tensor on device. + * @param probs The probability result on device. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ +void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id); +void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id); + +/** + * @brief The CUDA kernel that calculate the probability from a given state tensor data on GPU device. + * + * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). + * @tparam PrecisionT Floating data type. + * + * @param state Complex data pointer of state tensor on device. + * @param probs The probability result on device. + * @param data_size The length of state tensor on device. + */ +template +__global__ void getProbsKernel(GPUDataT *state, PrecisionT *probs, + const int data_size) { + const unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; + + if (i < data_size) { + PrecisionT real = state[i].x; + PrecisionT imag = state[i].y; + probs[i] = real * real + imag * imag; + } +} + +/** + * @brief The CUDA kernel call wrapper. + * + * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). + * @tparam PrecisionT Floating data type. + * + * @param state Complex data pointer of state tensor on device. + * @param probs The probability result on device. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ +template +void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, + std::size_t thread_per_block, cudaStream_t stream_id) { + auto dv = std::div(data_size, thread_per_block); + std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); + const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); + dim3 blockSize(thread_per_block, 1, 1); + dim3 gridSize(block_per_grid, 1); + + getProbsKernel + <<>>(state, probs, data_size); + PL_CUDA_IS_SUCCESS(cudaGetLastError()); +} + +//Definitions +void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id) { + getProbs_CUDA_call(state, probs, data_size, + thread_per_block, stream_id); +} + +void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id) { + getProbs_CUDA_call(state, probs, data_size, + thread_per_block, stream_id); +} +} // namespace Pennylane::LightningTensor::TNCuda \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index fed9f489b0..4700ac7104 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -21,6 +21,7 @@ #pragma once #include +#include #include #include @@ -39,6 +40,13 @@ using namespace Pennylane::LightningTensor::TNCuda::Util; /// @endcond namespace Pennylane::LightningTensor::TNCuda::Measures { +extern void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, + const std::size_t thread_per_block, + cudaStream_t stream_id); +extern void getProbs_CUDA(cuDoubleComplex *state, double *probs, + const int data_size, + const std::size_t thread_per_block, + cudaStream_t stream_id); /** * @brief ObservablesTNCuda's Measurement Class. * @@ -51,6 +59,7 @@ template class MeasurementsTNCuda { private: using PrecisionT = typename TensorNetT::PrecisionT; using ComplexT = typename TensorNetT::ComplexT; + using CFP_t = typename TensorNetT::CFP_t; const TensorNetT &tensor_network_; @@ -58,6 +67,42 @@ template class MeasurementsTNCuda { explicit MeasurementsTNCuda(const TensorNetT &tensor_network) : tensor_network_(tensor_network){}; + /** + * @brief Probabilities for a subset of the full system. + * + * @param wires Wires will restrict probabilities to a subset + * of the full system. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Floating point std::vector with probabilities. + */ + template + auto probs(const std::vector &wires, + const int32_t numHyperSamples = 1) -> std::vector { + const std::size_t length = std::size_t{1} << wires.size(); + + std::vector h_res(length); + + DataBuffer d_output_tensor( + length, tensor_network_.getDevTag(), true); + + DataBuffer d_output_probs( + length, tensor_network_.getDevTag(), true); + + tensor_network_.get_state_tensor(d_output_tensor.getData(), + d_output_tensor.getLength(), wires, + numHyperSamples); + + getProbs_CUDA(d_output_tensor.getData(), d_output_probs.getData(), + length, static_cast(thread_per_block), + tensor_network_.getDevTag().getStreamID()); + + d_output_probs.CopyGpuDataToHost(h_res.data(), h_res.size()); + + return h_res; + } + /** * @brief Calculate var value for a general ObservableTNCuda Observable. * From e260a57332611f65043c0a97efec80f63d7a7d8e Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 31 Jul 2024 13:09:54 +0000 Subject: [PATCH 051/227] Auto update version from '0.38.0-dev21' to '0.38.0-dev22' --- 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 b0db6142fe..69ef0e05e7 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.38.0-dev21" +__version__ = "0.38.0-dev22" From e30ff896308e5ed2990b79ab4a91772e738bd957 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 14:19:10 +0000 Subject: [PATCH 052/227] update C++ unit tests and changelog --- .github/CHANGELOG.md | 2 +- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 89 ++++++------------- 2 files changed, 30 insertions(+), 61 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 420790540d..404cd6d271 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs^2`. +* Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs^2` and this implementation scales `O(num_obs^2)`. [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) ### Breaking changes diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 6e42fb79a3..502c995685 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include #include @@ -179,7 +180,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, SECTION("Using TensorProd") { std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 5; + constexpr std::size_t num_qubits = 5; std::size_t maxBondDim = bondDim; TensorNetT mps_state{num_qubits, maxBondDim}; @@ -220,67 +221,35 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - auto I0 = std::make_shared("Identity", - std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); - auto I2 = std::make_shared("Identity", - std::vector{2}); - auto I3 = std::make_shared("Identity", - std::vector{3}); - auto I4 = std::make_shared("Identity", - std::vector{4}); + std::array, num_qubits> I; + std::array, num_qubits> X; + std::array, num_qubits> Y; + std::array, num_qubits> Z; + std::array, num_qubits> H; - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto X1 = - std::make_shared("PauliX", std::vector{1}); - auto X2 = - std::make_shared("PauliX", std::vector{2}); - auto X3 = - std::make_shared("PauliX", std::vector{3}); - auto X4 = - std::make_shared("PauliX", std::vector{4}); - - auto Y0 = - std::make_shared("PauliY", std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); - auto Y2 = - std::make_shared("PauliY", std::vector{2}); - auto Y3 = - std::make_shared("PauliY", std::vector{3}); - auto Y4 = - std::make_shared("PauliY", std::vector{4}); + for (std::size_t i = 0; i < num_qubits; i++) { + I[i] = std::make_shared("Identity", + std::vector{i}); - auto Z0 = - std::make_shared("PauliZ", std::vector{0}); - auto Z1 = - std::make_shared("PauliZ", std::vector{1}); - auto Z2 = - std::make_shared("PauliZ", std::vector{2}); - auto Z3 = - std::make_shared("PauliZ", std::vector{3}); - auto Z4 = - std::make_shared("PauliZ", std::vector{4}); - - auto H0 = std::make_shared("Hadamard", - std::vector{0}); - auto H1 = std::make_shared("Hadamard", - std::vector{1}); - auto H2 = std::make_shared("Hadamard", - std::vector{2}); - auto H3 = std::make_shared("Hadamard", - std::vector{3}); - auto H4 = std::make_shared("Hadamard", - std::vector{4}); - - auto ob0 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); - auto ob1 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); - auto ob2 = TensorProdObsT::create({I1, X2, Y3, Z4, H0}); - auto ob3 = TensorProdObsT::create({I2, X3, Y4, Z0, H1}); - auto ob4 = TensorProdObsT::create({I3, X4, Y0, Z1, H2}); - auto ob5 = TensorProdObsT::create({I4, X0, Y1, Z2, H3}); + X[i] = std::make_shared("PauliX", + std::vector{i}); + + Y[i] = std::make_shared("PauliY", + std::vector{i}); + + Z[i] = std::make_shared("PauliZ", + std::vector{i}); + + H[i] = std::make_shared("Hadamard", + std::vector{i}); + } + + auto ob0 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); + auto ob1 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); + auto ob2 = TensorProdObsT::create({I[1], X[2], Y[3], Z[4], H[0]}); + auto ob3 = TensorProdObsT::create({I[2], X[3], Y[4], Z[0], H[1]}); + auto ob4 = TensorProdObsT::create({I[3], X[4], Y[0], Z[1], H[2]}); + auto ob5 = TensorProdObsT::create({I[4], X[0], Y[1], Z[2], H[3]}); auto ob = HamiltonianObsT::create({TestType{0.3}, TestType{0.5}, TestType{0.3}, TestType{0.5}, From 28f0b474eec9e153034bf060dd6e1113d5b95fc9 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 31 Jul 2024 14:19:36 +0000 Subject: [PATCH 053/227] Auto update version from '0.38.0-dev21' to '0.38.0-dev22' --- 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 b0db6142fe..69ef0e05e7 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.38.0-dev21" +__version__ = "0.38.0-dev22" From fea0770e0d672545ca65f253f839af19ca52e7c3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 15:34:10 +0000 Subject: [PATCH 054/227] further tidy up the code --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 502c995685..7360c52e42 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -181,6 +181,8 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, SECTION("Using TensorProd") { std::size_t bondDim = GENERATE(2); constexpr std::size_t num_qubits = 5; + constexpr std::size_t num_paulis = 5; + constexpr std::size_t num_obs_terms = 6; std::size_t maxBondDim = bondDim; TensorNetT mps_state{num_qubits, maxBondDim}; @@ -221,43 +223,46 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - std::array, num_qubits> I; - std::array, num_qubits> X; - std::array, num_qubits> Y; - std::array, num_qubits> Z; - std::array, num_qubits> H; - - for (std::size_t i = 0; i < num_qubits; i++) { - I[i] = std::make_shared("Identity", - std::vector{i}); - - X[i] = std::make_shared("PauliX", - std::vector{i}); - - Y[i] = std::make_shared("PauliY", - std::vector{i}); - - Z[i] = std::make_shared("PauliZ", - std::vector{i}); + std::array paulis = { + "Identity", "PauliX", "PauliY", "PauliZ", "Hadamard"}; + + std::array, num_qubits>, + num_paulis> + named_obs; + // create Paulis(0)-Paulis(num_qubits-1) for each Pauli + for (std::size_t i = 0; i < num_paulis; i++) { + for (std::size_t j = 0; j < num_qubits; j++) { + named_obs[i][j] = std::make_shared( + paulis[i], std::vector{j}); + } + } - H[i] = std::make_shared("Hadamard", - std::vector{i}); + std::array, num_obs_terms> + obs_tensor_prod; + + // Create the tensor product of the observables + // I(i % num_qubits)@X((i + 1) % num_qubits)@Y((i + 2) % + // num_qubits)@Z((i + 3) % num_qubits)@H((i + 4) % num_qubits) + for (std::size_t i = 0; i < num_obs_terms - 1; i++) { + obs_tensor_prod[i + 1] = + TensorProdObsT::create({named_obs[0][i % num_qubits], + named_obs[1][(i + 1) % num_qubits], + named_obs[2][(i + 2) % num_qubits], + named_obs[3][(i + 3) % num_qubits], + named_obs[4][(i + 4) % num_qubits]}); } - auto ob0 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); - auto ob1 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); - auto ob2 = TensorProdObsT::create({I[1], X[2], Y[3], Z[4], H[0]}); - auto ob3 = TensorProdObsT::create({I[2], X[3], Y[4], Z[0], H[1]}); - auto ob4 = TensorProdObsT::create({I[3], X[4], Y[0], Z[1], H[2]}); - auto ob5 = TensorProdObsT::create({I[4], X[0], Y[1], Z[2], H[3]}); + obs_tensor_prod[0] = obs_tensor_prod[1]; + + std::initializer_list coeffs{0.3, 0.5, 0.3, 0.5, 0.3, 0.5}; + std::initializer_list>> + obs{obs_tensor_prod[0], obs_tensor_prod[1], obs_tensor_prod[2], + obs_tensor_prod[3], obs_tensor_prod[4], obs_tensor_prod[5]}; - auto ob = HamiltonianObsT::create({TestType{0.3}, TestType{0.5}, - TestType{0.3}, TestType{0.5}, - TestType{0.3}, TestType{0.5}}, - {ob0, ob1, ob2, ob3, ob4, ob5}); + auto ob = HamiltonianObsT::create(coeffs, obs); auto res = m.var(*ob); - CHECK(res == Approx(1.0830144)); + CHECK(res == Approx(1.0830144)); // results from default.qubit } SECTION("Using 1 Hermitian") { From c69f0ba372fda4caa5c2b2123b09491f9a935bc6 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 16:07:56 +0000 Subject: [PATCH 055/227] update getPauliPauli with rotation of one Pauli --- .../src/utils/cuda_utils/cuGates_host.hpp | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp index a95363fd9c..53b712ed53 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp @@ -1481,8 +1481,8 @@ static constexpr auto getP1111_CU() -> std::vector { * of PauliX@PauliY data. */ template static constexpr auto getXY() -> std::vector { - return {cuUtil::IMAG(), cuUtil::ZERO(), cuUtil::ZERO(), - -cuUtil::IMAG()}; + auto &&PauliY = getPauliY(); + return {PauliY[2], PauliY[3], PauliY[0], PauliY[1]}; } /** @@ -1494,8 +1494,8 @@ template static constexpr auto getXY() -> std::vector { * of PauliX@PauliZ data. */ template static constexpr auto getXZ() -> std::vector { - return {cuUtil::ZERO(), -cuUtil::ONE(), cuUtil::ONE(), - cuUtil::ZERO()}; + auto &&PauliZ = getPauliZ(); + return {PauliZ[2], PauliZ[3], PauliZ[0], PauliZ[1]}; } /** @@ -1507,8 +1507,8 @@ template static constexpr auto getXZ() -> std::vector { * of PauliX@Hadamard data. */ template static constexpr auto getXH() -> std::vector { - return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), - cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; + auto &&Hadamard = getHadamard(); + return {Hadamard[2], Hadamard[3], Hadamard[0], Hadamard[1]}; } /** @@ -1520,86 +1520,86 @@ template static constexpr auto getXH() -> std::vector { * of PauliY@PauliX data. */ template static constexpr auto getYX() -> std::vector { - return {-cuUtil::IMAG(), cuUtil::ZERO(), - cuUtil::ZERO(), cuUtil::IMAG()}; + auto &&PauliY = getPauliY(); + return {PauliY[1], PauliY[0], PauliY[3], PauliY[2]}; } /** - * @brief Create a matrix representation of the PauliY@PauliZ data in row-major + * @brief Create a matrix representation of the PauliZ@PauliX data in row-major * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliY@PauliZ data. + * of PauliZ@PauliX data. */ -template static constexpr auto getYZ() -> std::vector { - return {cuUtil::ZERO(), cuUtil::IMAG(), cuUtil::IMAG(), - cuUtil::ZERO()}; +template static constexpr auto getZX() -> std::vector { + auto &&PauliZ = getPauliZ(); + return {PauliZ[1], PauliZ[0], PauliZ[3], PauliZ[2]}; } /** - * @brief Create a matrix representation of the PauliY@Hadamard data in + * @brief Create a matrix representation of the Hadamard@PauliX data in * row-major format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliY@Hadamard data. + * of Hadamard@PauliX data. */ -template static constexpr auto getYH() -> std::vector { - return {-cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG(), - cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG()}; +template static constexpr auto getHX() -> std::vector { + auto &&Hadamard = getHadamard(); + return {Hadamard[1], Hadamard[0], Hadamard[3], Hadamard[2]}; } /** - * @brief Create a matrix representation of the PauliZ@PauliX data in row-major + * @brief Create a matrix representation of the PauliY@PauliZ data in row-major * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliZ@PauliX data. + * of PauliY@PauliZ data. */ -template static constexpr auto getZX() -> std::vector { - return {cuUtil::ZERO(), cuUtil::ONE(), -cuUtil::ONE(), - cuUtil::ZERO()}; +template static constexpr auto getYZ() -> std::vector { + auto &&PauliY = getPauliY(); + return {PauliY[0], -PauliY[1], PauliY[2], -PauliY[3]}; } /** - * @brief Create a matrix representation of the PauliZ@PauliY data in row-major - * format. + * @brief Create a matrix representation of the PauliY@Hadamard data in + * row-major format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliZ@PauliY data. + * of PauliY@Hadamard data. */ -template static constexpr auto getZY() -> std::vector { - return {cuUtil::ZERO(), -cuUtil::IMAG(), - -cuUtil::IMAG(), cuUtil::ZERO()}; +template static constexpr auto getYH() -> std::vector { + return {-cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG(), + cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG()}; } /** - * @brief Create a matrix representation of the PauliZ@Hadamard data in - * row-major format. + * @brief Create a matrix representation of the PauliZ@PauliY data in row-major + * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliZ@Hadamard data. + * of PauliZ@PauliY data. */ -template static constexpr auto getZH() -> std::vector { - return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), - -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +template static constexpr auto getZY() -> std::vector { + auto &&PauliY = getPauliY(); + return {PauliY[0], PauliY[1], -PauliY[2], -PauliY[3]}; } /** - * @brief Create a matrix representation of the Hadamard@PauliX data in + * @brief Create a matrix representation of the PauliZ@Hadamard data in * row-major format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of Hadamard@PauliX data. + * of PauliZ@Hadamard data. */ -template static constexpr auto getHX() -> std::vector { - return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), - -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +template static constexpr auto getZH() -> std::vector { + auto &&Hadamard = getHadamard(); + return {Hadamard[0], Hadamard[1], -Hadamard[2], -Hadamard[3]}; } /** @@ -1624,8 +1624,8 @@ template static constexpr auto getHY() -> std::vector { * of Hadamard@PauliZ data. */ template static constexpr auto getHZ() -> std::vector { - return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), - cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; + auto &&Hadamard = getHadamard(); + return {Hadamard[0], -Hadamard[1], Hadamard[2], -Hadamard[3]}; } /* From 42fe47e9c7cb20417b92bd295512e0e54a48ca31 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 31 Jul 2024 16:10:21 +0000 Subject: [PATCH 056/227] Auto update version from '0.38.0-dev21' to '0.38.0-dev22' --- 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 b0db6142fe..69ef0e05e7 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.38.0-dev21" +__version__ = "0.38.0-dev22" From 7054b9c78cd0e71b67bea53d7a7875381e30f8df Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 14:19:10 +0000 Subject: [PATCH 057/227] update C++ unit tests and changelog --- .github/CHANGELOG.md | 2 +- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 89 ++++++------------- 2 files changed, 30 insertions(+), 61 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 420790540d..404cd6d271 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs^2`. +* Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs^2` and this implementation scales `O(num_obs^2)`. [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) ### Breaking changes diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 6e42fb79a3..502c995685 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include #include @@ -179,7 +180,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, SECTION("Using TensorProd") { std::size_t bondDim = GENERATE(2); - std::size_t num_qubits = 5; + constexpr std::size_t num_qubits = 5; std::size_t maxBondDim = bondDim; TensorNetT mps_state{num_qubits, maxBondDim}; @@ -220,67 +221,35 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - auto I0 = std::make_shared("Identity", - std::vector{0}); - auto I1 = std::make_shared("Identity", - std::vector{1}); - auto I2 = std::make_shared("Identity", - std::vector{2}); - auto I3 = std::make_shared("Identity", - std::vector{3}); - auto I4 = std::make_shared("Identity", - std::vector{4}); + std::array, num_qubits> I; + std::array, num_qubits> X; + std::array, num_qubits> Y; + std::array, num_qubits> Z; + std::array, num_qubits> H; - auto X0 = - std::make_shared("PauliX", std::vector{0}); - auto X1 = - std::make_shared("PauliX", std::vector{1}); - auto X2 = - std::make_shared("PauliX", std::vector{2}); - auto X3 = - std::make_shared("PauliX", std::vector{3}); - auto X4 = - std::make_shared("PauliX", std::vector{4}); - - auto Y0 = - std::make_shared("PauliY", std::vector{0}); - auto Y1 = - std::make_shared("PauliY", std::vector{1}); - auto Y2 = - std::make_shared("PauliY", std::vector{2}); - auto Y3 = - std::make_shared("PauliY", std::vector{3}); - auto Y4 = - std::make_shared("PauliY", std::vector{4}); + for (std::size_t i = 0; i < num_qubits; i++) { + I[i] = std::make_shared("Identity", + std::vector{i}); - auto Z0 = - std::make_shared("PauliZ", std::vector{0}); - auto Z1 = - std::make_shared("PauliZ", std::vector{1}); - auto Z2 = - std::make_shared("PauliZ", std::vector{2}); - auto Z3 = - std::make_shared("PauliZ", std::vector{3}); - auto Z4 = - std::make_shared("PauliZ", std::vector{4}); - - auto H0 = std::make_shared("Hadamard", - std::vector{0}); - auto H1 = std::make_shared("Hadamard", - std::vector{1}); - auto H2 = std::make_shared("Hadamard", - std::vector{2}); - auto H3 = std::make_shared("Hadamard", - std::vector{3}); - auto H4 = std::make_shared("Hadamard", - std::vector{4}); - - auto ob0 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); - auto ob1 = TensorProdObsT::create({I0, X1, Y2, Z3, H4}); - auto ob2 = TensorProdObsT::create({I1, X2, Y3, Z4, H0}); - auto ob3 = TensorProdObsT::create({I2, X3, Y4, Z0, H1}); - auto ob4 = TensorProdObsT::create({I3, X4, Y0, Z1, H2}); - auto ob5 = TensorProdObsT::create({I4, X0, Y1, Z2, H3}); + X[i] = std::make_shared("PauliX", + std::vector{i}); + + Y[i] = std::make_shared("PauliY", + std::vector{i}); + + Z[i] = std::make_shared("PauliZ", + std::vector{i}); + + H[i] = std::make_shared("Hadamard", + std::vector{i}); + } + + auto ob0 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); + auto ob1 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); + auto ob2 = TensorProdObsT::create({I[1], X[2], Y[3], Z[4], H[0]}); + auto ob3 = TensorProdObsT::create({I[2], X[3], Y[4], Z[0], H[1]}); + auto ob4 = TensorProdObsT::create({I[3], X[4], Y[0], Z[1], H[2]}); + auto ob5 = TensorProdObsT::create({I[4], X[0], Y[1], Z[2], H[3]}); auto ob = HamiltonianObsT::create({TestType{0.3}, TestType{0.5}, TestType{0.3}, TestType{0.5}, From 200c8791afadaf85505f9907d73f3f4201d30e18 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 15:34:10 +0000 Subject: [PATCH 058/227] further tidy up the code --- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 502c995685..7360c52e42 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -181,6 +181,8 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, SECTION("Using TensorProd") { std::size_t bondDim = GENERATE(2); constexpr std::size_t num_qubits = 5; + constexpr std::size_t num_paulis = 5; + constexpr std::size_t num_obs_terms = 6; std::size_t maxBondDim = bondDim; TensorNetT mps_state{num_qubits, maxBondDim}; @@ -221,43 +223,46 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, auto m = MeasurementsTNCuda(mps_state); - std::array, num_qubits> I; - std::array, num_qubits> X; - std::array, num_qubits> Y; - std::array, num_qubits> Z; - std::array, num_qubits> H; - - for (std::size_t i = 0; i < num_qubits; i++) { - I[i] = std::make_shared("Identity", - std::vector{i}); - - X[i] = std::make_shared("PauliX", - std::vector{i}); - - Y[i] = std::make_shared("PauliY", - std::vector{i}); - - Z[i] = std::make_shared("PauliZ", - std::vector{i}); + std::array paulis = { + "Identity", "PauliX", "PauliY", "PauliZ", "Hadamard"}; + + std::array, num_qubits>, + num_paulis> + named_obs; + // create Paulis(0)-Paulis(num_qubits-1) for each Pauli + for (std::size_t i = 0; i < num_paulis; i++) { + for (std::size_t j = 0; j < num_qubits; j++) { + named_obs[i][j] = std::make_shared( + paulis[i], std::vector{j}); + } + } - H[i] = std::make_shared("Hadamard", - std::vector{i}); + std::array, num_obs_terms> + obs_tensor_prod; + + // Create the tensor product of the observables + // I(i % num_qubits)@X((i + 1) % num_qubits)@Y((i + 2) % + // num_qubits)@Z((i + 3) % num_qubits)@H((i + 4) % num_qubits) + for (std::size_t i = 0; i < num_obs_terms - 1; i++) { + obs_tensor_prod[i + 1] = + TensorProdObsT::create({named_obs[0][i % num_qubits], + named_obs[1][(i + 1) % num_qubits], + named_obs[2][(i + 2) % num_qubits], + named_obs[3][(i + 3) % num_qubits], + named_obs[4][(i + 4) % num_qubits]}); } - auto ob0 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); - auto ob1 = TensorProdObsT::create({I[0], X[1], Y[2], Z[3], H[4]}); - auto ob2 = TensorProdObsT::create({I[1], X[2], Y[3], Z[4], H[0]}); - auto ob3 = TensorProdObsT::create({I[2], X[3], Y[4], Z[0], H[1]}); - auto ob4 = TensorProdObsT::create({I[3], X[4], Y[0], Z[1], H[2]}); - auto ob5 = TensorProdObsT::create({I[4], X[0], Y[1], Z[2], H[3]}); + obs_tensor_prod[0] = obs_tensor_prod[1]; + + std::initializer_list coeffs{0.3, 0.5, 0.3, 0.5, 0.3, 0.5}; + std::initializer_list>> + obs{obs_tensor_prod[0], obs_tensor_prod[1], obs_tensor_prod[2], + obs_tensor_prod[3], obs_tensor_prod[4], obs_tensor_prod[5]}; - auto ob = HamiltonianObsT::create({TestType{0.3}, TestType{0.5}, - TestType{0.3}, TestType{0.5}, - TestType{0.3}, TestType{0.5}}, - {ob0, ob1, ob2, ob3, ob4, ob5}); + auto ob = HamiltonianObsT::create(coeffs, obs); auto res = m.var(*ob); - CHECK(res == Approx(1.0830144)); + CHECK(res == Approx(1.0830144)); // results from default.qubit } SECTION("Using 1 Hermitian") { From 79af327a9dcac5af94317c22edf0e04b6ef53262 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 16:07:56 +0000 Subject: [PATCH 059/227] update getPauliPauli with rotation of one Pauli --- .../src/utils/cuda_utils/cuGates_host.hpp | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp index a95363fd9c..53b712ed53 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp @@ -1481,8 +1481,8 @@ static constexpr auto getP1111_CU() -> std::vector { * of PauliX@PauliY data. */ template static constexpr auto getXY() -> std::vector { - return {cuUtil::IMAG(), cuUtil::ZERO(), cuUtil::ZERO(), - -cuUtil::IMAG()}; + auto &&PauliY = getPauliY(); + return {PauliY[2], PauliY[3], PauliY[0], PauliY[1]}; } /** @@ -1494,8 +1494,8 @@ template static constexpr auto getXY() -> std::vector { * of PauliX@PauliZ data. */ template static constexpr auto getXZ() -> std::vector { - return {cuUtil::ZERO(), -cuUtil::ONE(), cuUtil::ONE(), - cuUtil::ZERO()}; + auto &&PauliZ = getPauliZ(); + return {PauliZ[2], PauliZ[3], PauliZ[0], PauliZ[1]}; } /** @@ -1507,8 +1507,8 @@ template static constexpr auto getXZ() -> std::vector { * of PauliX@Hadamard data. */ template static constexpr auto getXH() -> std::vector { - return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), - cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; + auto &&Hadamard = getHadamard(); + return {Hadamard[2], Hadamard[3], Hadamard[0], Hadamard[1]}; } /** @@ -1520,86 +1520,86 @@ template static constexpr auto getXH() -> std::vector { * of PauliY@PauliX data. */ template static constexpr auto getYX() -> std::vector { - return {-cuUtil::IMAG(), cuUtil::ZERO(), - cuUtil::ZERO(), cuUtil::IMAG()}; + auto &&PauliY = getPauliY(); + return {PauliY[1], PauliY[0], PauliY[3], PauliY[2]}; } /** - * @brief Create a matrix representation of the PauliY@PauliZ data in row-major + * @brief Create a matrix representation of the PauliZ@PauliX data in row-major * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliY@PauliZ data. + * of PauliZ@PauliX data. */ -template static constexpr auto getYZ() -> std::vector { - return {cuUtil::ZERO(), cuUtil::IMAG(), cuUtil::IMAG(), - cuUtil::ZERO()}; +template static constexpr auto getZX() -> std::vector { + auto &&PauliZ = getPauliZ(); + return {PauliZ[1], PauliZ[0], PauliZ[3], PauliZ[2]}; } /** - * @brief Create a matrix representation of the PauliY@Hadamard data in + * @brief Create a matrix representation of the Hadamard@PauliX data in * row-major format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliY@Hadamard data. + * of Hadamard@PauliX data. */ -template static constexpr auto getYH() -> std::vector { - return {-cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG(), - cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG()}; +template static constexpr auto getHX() -> std::vector { + auto &&Hadamard = getHadamard(); + return {Hadamard[1], Hadamard[0], Hadamard[3], Hadamard[2]}; } /** - * @brief Create a matrix representation of the PauliZ@PauliX data in row-major + * @brief Create a matrix representation of the PauliY@PauliZ data in row-major * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliZ@PauliX data. + * of PauliY@PauliZ data. */ -template static constexpr auto getZX() -> std::vector { - return {cuUtil::ZERO(), cuUtil::ONE(), -cuUtil::ONE(), - cuUtil::ZERO()}; +template static constexpr auto getYZ() -> std::vector { + auto &&PauliY = getPauliY(); + return {PauliY[0], -PauliY[1], PauliY[2], -PauliY[3]}; } /** - * @brief Create a matrix representation of the PauliZ@PauliY data in row-major - * format. + * @brief Create a matrix representation of the PauliY@Hadamard data in + * row-major format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliZ@PauliY data. + * of PauliY@Hadamard data. */ -template static constexpr auto getZY() -> std::vector { - return {cuUtil::ZERO(), -cuUtil::IMAG(), - -cuUtil::IMAG(), cuUtil::ZERO()}; +template static constexpr auto getYH() -> std::vector { + return {-cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG(), + cuUtil::INVSQRT2IMAG(), cuUtil::INVSQRT2IMAG()}; } /** - * @brief Create a matrix representation of the PauliZ@Hadamard data in - * row-major format. + * @brief Create a matrix representation of the PauliZ@PauliY data in row-major + * format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of PauliZ@Hadamard data. + * of PauliZ@PauliY data. */ -template static constexpr auto getZH() -> std::vector { - return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), - -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +template static constexpr auto getZY() -> std::vector { + auto &&PauliY = getPauliY(); + return {PauliY[0], PauliY[1], -PauliY[2], -PauliY[3]}; } /** - * @brief Create a matrix representation of the Hadamard@PauliX data in + * @brief Create a matrix representation of the PauliZ@Hadamard data in * row-major format. * * @tparam CFP_t Required precision of gate (`float` or `double`). * @return constexpr std::vector Return constant expression - * of Hadamard@PauliX data. + * of PauliZ@Hadamard data. */ -template static constexpr auto getHX() -> std::vector { - return {cuUtil::INVSQRT2(), cuUtil::INVSQRT2(), - -cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; +template static constexpr auto getZH() -> std::vector { + auto &&Hadamard = getHadamard(); + return {Hadamard[0], Hadamard[1], -Hadamard[2], -Hadamard[3]}; } /** @@ -1624,8 +1624,8 @@ template static constexpr auto getHY() -> std::vector { * of Hadamard@PauliZ data. */ template static constexpr auto getHZ() -> std::vector { - return {cuUtil::INVSQRT2(), -cuUtil::INVSQRT2(), - cuUtil::INVSQRT2(), cuUtil::INVSQRT2()}; + auto &&Hadamard = getHadamard(); + return {Hadamard[0], -Hadamard[1], Hadamard[2], -Hadamard[3]}; } /* From d696534e8855977c8f0b965afb05ed011dd7d60d Mon Sep 17 00:00:00 2001 From: Shuli Shu <31480676+multiphaseCFD@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:20:27 -0400 Subject: [PATCH 060/227] Default `ENABLE_LAPACK` as `OFF` (#825) ### Before submitting Please complete the following checklist when submitting a PR: - [ ] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [ ] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [ ] Ensure that the test suite passes, by running `make test`. - [x] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [x] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** [SC-70045] **Description of the Change:** **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** --------- Co-authored-by: ringo-but-quantum Co-authored-by: Vincent Michaud-Rioux Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- .github/CHANGELOG.md | 3 +++ .github/workflows/tests_lgpu_cpp.yml | 4 +++- .github/workflows/tests_linux_cpp.yml | 4 +++- .github/workflows/tests_lkcuda_cpp.yml | 4 +++- .github/workflows/tests_windows_cpp.yml | 1 - CMakeLists.txt | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 404cd6d271..c962bd62f9 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -18,6 +18,9 @@ ### Improvements +* `ENABLE_LAPACK` is off by default for all Lightning backends. + [(#825)](https://github.com/PennyLaneAI/pennylane-lightning/pull/825) + * Update `LightingQubit.preprocess` to work with changes to preprocessing for mid-circuit measurements. [(#812)](https://github.com/PennyLaneAI/pennylane-lightning/pull/812) diff --git a/.github/workflows/tests_lgpu_cpp.yml b/.github/workflows/tests_lgpu_cpp.yml index 1c8a6cebde..b3061bb4b5 100644 --- a/.github/workflows/tests_lgpu_cpp.yml +++ b/.github/workflows/tests_lgpu_cpp.yml @@ -61,9 +61,10 @@ jobs: strategy: matrix: pl_backend: ["lightning_gpu"] + enable_lapack: ["OFF", "ON"] cuda_version: ["12"] - name: C++ Tests (${{ matrix.pl_backend }}, cuda-${{ matrix.cuda_version }}) + name: C++ Tests (${{ matrix.pl_backend }}, cuda-${{ matrix.cuda_version }}, enable_lapack=${{ matrix.enable_lapack }}) runs-on: - ubuntu-22.04 - self-hosted @@ -136,6 +137,7 @@ jobs: -DCUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')")\ -DBUILD_TESTS=ON \ -DENABLE_PYTHON=OFF \ + -DENABLE_LAPACK=${{ matrix.enable_lapack }} \ -DPL_BACKEND=${{ matrix.pl_backend }} \ -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) \ -DENABLE_COVERAGE=ON \ diff --git a/.github/workflows/tests_linux_cpp.yml b/.github/workflows/tests_linux_cpp.yml index 34d1184d10..2023a7a511 100644 --- a/.github/workflows/tests_linux_cpp.yml +++ b/.github/workflows/tests_linux_cpp.yml @@ -48,11 +48,12 @@ jobs: pl_backend: ["lightning_qubit"] enable_kernel_omp: ["OFF", "ON"] enable_kernel_avx_streaming: ["OFF", "ON"] + enable_lapack: ["OFF", "ON"] exclude: - enable_kernel_omp: OFF enable_kernel_avx_streaming: ON timeout-minutes: 60 - name: C++ Tests (${{ matrix.pl_backend }}, ENABLE_KERNEL_OMP=${{ matrix.enable_kernel_omp }}, ENABLE_KERNEL_AVX_STREAMING=${{ matrix.enable_kernel_avx_streaming }}) + name: C++ Tests (${{ matrix.pl_backend }}, ENABLE_KERNEL_OMP=${{ matrix.enable_kernel_omp }}, ENABLE_KERNEL_AVX_STREAMING=${{ matrix.enable_kernel_avx_streaming }}), ENABLE_LAPACK=${{ matrix.enable_lapack }}) runs-on: ${{ needs.determine_runner.outputs.runner_group }} steps: @@ -75,6 +76,7 @@ jobs: -DCMAKE_BUILD_TYPE=Debug \ -DBUILD_TESTS=ON \ -DENABLE_PYTHON=OFF \ + -DENABLE_LAPACK=${{ matrix.enable_lapack }} \ -DPL_BACKEND=${{ matrix.pl_backend }} \ -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) \ -DENABLE_COVERAGE=ON \ diff --git a/.github/workflows/tests_lkcuda_cpp.yml b/.github/workflows/tests_lkcuda_cpp.yml index 230ed51f85..96ef4e1bd0 100644 --- a/.github/workflows/tests_lkcuda_cpp.yml +++ b/.github/workflows/tests_lkcuda_cpp.yml @@ -111,8 +111,9 @@ jobs: pl_backend: ["lightning_kokkos"] exec_model: ["CUDA"] kokkos_version: ["4.3.01"] + enable_lapack: ["OFF", "ON"] - name: C++ Tests (${{ matrix.pl_backend }}, kokkos-${{ matrix.kokkos_version }}, model-${{ matrix.exec_model }}) + name: C++ Tests (${{ matrix.pl_backend }}, kokkos-${{ matrix.kokkos_version }}, model-${{ matrix.exec_model }}), enable_lapack-${{ matrix.enable_lapack }} runs-on: - ${{ matrix.os }} - self-hosted @@ -190,6 +191,7 @@ jobs: -DCMAKE_BUILD_TYPE=Debug \ -DBUILD_TESTS=ON \ -DENABLE_PYTHON=OFF \ + -DENABLE_LAPACK=${{ matrix.enable_lapack }} \ -DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos \ -DPL_BACKEND=${{ matrix.pl_backend }} \ -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) \ diff --git a/.github/workflows/tests_windows_cpp.yml b/.github/workflows/tests_windows_cpp.yml index 2faccc0831..1b2e7522a6 100644 --- a/.github/workflows/tests_windows_cpp.yml +++ b/.github/workflows/tests_windows_cpp.yml @@ -131,7 +131,6 @@ jobs: -DBUILD_TESTS=ON ` -DENABLE_OPENMP=OFF ` -DENABLE_PYTHON=OFF ` - -DENABLE_LAPACK=OFF ` -DENABLE_GATE_DISPATCHER=OFF ` -DPL_BACKEND=${{ matrix.pl_backend }} ` -DENABLE_WARNINGS=OFF diff --git a/CMakeLists.txt b/CMakeLists.txt index c7674d90b8..a7e50f9004 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ option(ENABLE_WARNINGS "Enable warnings" ON) option(ENABLE_NATIVE "Enable native CPU build tuning" OFF) option(ENABLE_PYTHON "Enable compilation of the Python module" ON) -option(ENABLE_LAPACK "Enable compilation with scipy/LAPACK" ON) +option(ENABLE_LAPACK "Enable compilation with scipy/LAPACK" OFF) # OpenMP find_package(OpenMP) From 012a545acc7df11d2e26c4522b9b1e1ee446439a Mon Sep 17 00:00:00 2001 From: Lee James O'Riordan Date: Wed, 31 Jul 2024 08:49:23 -0400 Subject: [PATCH 061/227] Add paper to readme (#818) Please complete the following checklist when submitting a PR: - [x] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [x] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [x] Ensure that the test suite passes, by running `make test`. - [x] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [x] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** This adds a link to the readme pointing to https://arxiv.org/abs/2403.02512 **Description of the Change:** **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** --------- Co-authored-by: ringo-but-quantum Co-authored-by: Josh Izaac --- .github/CHANGELOG.md | 5 ++- CITATION.cff | 59 ++++++++++++++++++++++++++++ README.rst | 21 +++++++--- doc/index.rst | 15 ++++++- doc/lightning_tensor/device.rst | 2 +- pennylane_lightning/core/_version.py | 2 +- 6 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 CITATION.cff diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index c962bd62f9..0617d996f3 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -65,6 +65,9 @@ ### Documentation +* Updated the README and added citation format for Lightning arxiv preprint. + [#818](https://github.com/PennyLaneAI/pennylane-lightning/pull/818) + ### Bug fixes * Check for the number of wires for Hermitian observables in Lightning-Tensor. Only 1-wire Hermitian observables are supported as of `cuTensorNet-v24.03.0`. @@ -86,7 +89,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Mudit Pandey, Shuli Shu, Paul Haochen Wang +Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang --- diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000000..4256080288 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,59 @@ +cff-version: "1.2.0" +authors: +- family-names: Asadi + given-names: Ali + orcid: "https://orcid.org/0009-0004-6010-2110" +- family-names: Dusko + given-names: Amintor + orcid: "https://orcid.org/0000-0002-0910-7715" +- family-names: Park + given-names: Chae-Yeun + orcid: "https://orcid.org/0000-0003-4430-1000" +- family-names: Michaud-Rioux + given-names: Vincent + orcid: "https://orcid.org/0000-0003-4367-5940" +- family-names: Schoch + given-names: Isidor +- family-names: Shu + given-names: Shuli + orcid: "https://orcid.org/0000-0001-6528-8584" +- family-names: Vincent + given-names: Trevor +- family-names: O'Riordan + given-names: Lee J. + orcid: "https://orcid.org/0000-0002-6758-9433" +contact: +- family-names: O'Riordan + given-names: Lee J. + orcid: "https://orcid.org/0000-0002-6758-9433" +message: If you use this software, please cite as follows. +preferred-citation: + authors: + - family-names: Asadi + given-names: Ali + orcid: "https://orcid.org/0009-0004-6010-2110" + - family-names: Dusko + given-names: Amintor + orcid: "https://orcid.org/0000-0002-0910-7715" + - family-names: Park + given-names: Chae-Yeun + orcid: "https://orcid.org/0000-0003-4430-1000" + - family-names: Michaud-Rioux + given-names: Vincent + orcid: "https://orcid.org/0000-0003-4367-5940" + - family-names: Schoch + given-names: Isidor + - family-names: Shu + given-names: Shuli + orcid: "https://orcid.org/0000-0001-6528-8584" + - family-names: Vincent + given-names: Trevor + - family-names: O'Riordan + given-names: Lee J. + orcid: "https://orcid.org/0000-0002-6758-9433" + - url: "https://arxiv.org/abs/2403.02512" + - type: other + value: "arXiv:2403.02512" + title: "Hybrid quantum programming with PennyLane Lightning on HPC platforms" + type: article +title: "Hybrid quantum programming with PennyLane Lightning on HPC platforms" diff --git a/README.rst b/README.rst index 93303ed132..ea8ba722a4 100644 --- a/README.rst +++ b/README.rst @@ -448,15 +448,26 @@ Please make your best effort to comply with `black` and `pylint` before using di Authors ******* +.. citation-start-inclusion-marker-do-not-remove + Lightning is the work of `many contributors `_. -If you are doing research using PennyLane and Lightning, please cite `our paper `_: +If you are using Lightning for research, please cite: + +.. code-block:: bibtex - Ville Bergholm, Josh Izaac, Maria Schuld, Christian Gogolin, M. Sohaib Alam, Shahnawaz Ahmed, - Juan Miguel Arrazola, Carsten Blank, Alain Delgado, Soran Jahangiri, Keri McKiernan, Johannes Jakob Meyer, - Zeyue Niu, Antal Száva, and Nathan Killoran. - *PennyLane: Automatic differentiation of hybrid quantum-classical computations.* 2018. arXiv:1811.04968 + @misc{ + asadi2024, + title={{Hybrid quantum programming with PennyLane Lightning on HPC platforms}}, + author={Ali Asadi and Amintor Dusko and Chae-Yeun Park and Vincent Michaud-Rioux and Isidor Schoch and Shuli Shu and Trevor Vincent and Lee James O'Riordan}, + year={2024}, + eprint={2403.02512}, + archivePrefix={arXiv}, + primaryClass={quant-ph}, + url={https://arxiv.org/abs/2403.02512}, + } +.. citation-end-inclusion-marker-do-not-remove .. support-start-inclusion-marker-do-not-remove Support diff --git a/doc/index.rst b/doc/index.rst index d73ddad326..b89f369e94 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -12,7 +12,6 @@ Lightning plugins :start-after: header-start-inclusion-marker-do-not-remove :end-before: header-end-inclusion-marker-do-not-remove - Devices ******* @@ -35,7 +34,7 @@ The Lightning ecosystem provides the following devices: .. title-card:: :name: 'lightning.tensor' - :description: A heterogeneous backend tensor network simulator with NVIDIA cuQuantum library support. + :description: A tensor network simulator with NVIDIA cuQuantum library support. :link: lightning_tensor/device.html .. raw:: html @@ -43,6 +42,18 @@ The Lightning ecosystem provides the following devices:

+Authors +******* + +.. include:: ../README.rst + :start-after: citation-start-inclusion-marker-do-not-remove + :end-before: citation-end-inclusion-marker-do-not-remove + +.. raw:: html + +
+
+ .. toctree:: :maxdepth: 2 :titlesonly: diff --git a/doc/lightning_tensor/device.rst b/doc/lightning_tensor/device.rst index 109e909408..3e17424c4b 100644 --- a/doc/lightning_tensor/device.rst +++ b/doc/lightning_tensor/device.rst @@ -184,4 +184,4 @@ Users can not create a ``Hamiltonian`` or ``Prod`` observable from ``Hamiltonian .. raw:: html - \ No newline at end of file + diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 69ef0e05e7..b0db6142fe 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.38.0-dev22" +__version__ = "0.38.0-dev21" From bf838ee46b931890a1983d8591dc9e196417e1f3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 17:47:50 +0000 Subject: [PATCH 062/227] make format --- .../tncuda/cuda_kernels_ltensor.cu | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu index f31c2fb02e..93b66694bc 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu @@ -18,7 +18,8 @@ namespace Pennylane::LightningTensor::TNCuda { /** - * @brief Explicitly get the probability of given state tensor data on GPU device. + * @brief Explicitly get the probability of given state tensor data on GPU + * device. * * @param state Complex data pointer of state tensor on device. * @param probs The probability result on device. @@ -32,11 +33,12 @@ void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, const std::size_t thread_per_block, cudaStream_t stream_id); /** - * @brief The CUDA kernel that calculate the probability from a given state tensor data on GPU device. + * @brief The CUDA kernel that calculate the probability from a given state + * tensor data on GPU device. * * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). * @tparam PrecisionT Floating data type. - * + * * @param state Complex data pointer of state tensor on device. * @param probs The probability result on device. * @param data_size The length of state tensor on device. @@ -55,10 +57,10 @@ __global__ void getProbsKernel(GPUDataT *state, PrecisionT *probs, /** * @brief The CUDA kernel call wrapper. - * + * * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). * @tparam PrecisionT Floating data type. - * + * * @param state Complex data pointer of state tensor on device. * @param probs The probability result on device. * @param data_size The length of state tensor on device. @@ -79,7 +81,7 @@ void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, PL_CUDA_IS_SUCCESS(cudaGetLastError()); } -//Definitions +// Definitions void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, const std::size_t thread_per_block, cudaStream_t stream_id) { getProbs_CUDA_call(state, probs, data_size, From 4c031da09c92e7c96ed5e2dacf6876a98d0c9e3d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 17:50:07 +0000 Subject: [PATCH 063/227] separate probs support from qml.state support --- .../lightning_tensor/tncuda/CMakeLists.txt | 4 +- .../tncuda/cuda_kernels_ltensor.cu | 96 ------------------- .../measurements/MeasurementsTNCuda.hpp | 36 ------- 3 files changed, 2 insertions(+), 134 deletions(-) delete mode 100644 pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt index 39250497d8..49630b536f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt @@ -9,7 +9,7 @@ message(${LOGO}) project(${PL_BACKEND} DESCRIPTION "Lightning-Tensor MPS bindings for PennyLane. Backed by NVIDIA cuQuantum SDK." - LANGUAGES CXX C CUDA + LANGUAGES CXX C ) include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pllgpu.cmake") @@ -17,7 +17,7 @@ include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pltensortncuda.cmake") findCUDATK(lightning_external_libs) findCutensornet(lightning_external_libs) -set(LTENSOR_MPS_FILES MPSTNCuda.cpp cuda_kernels_ltensor.cu CACHE INTERNAL "" FORCE) +set(LTENSOR_MPS_FILES MPSTNCuda.cpp CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND} STATIC ${LTENSOR_MPS_FILES}) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu deleted file mode 100644 index 93b66694bc..0000000000 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2024 Xanadu Quantum Technologies Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -/** - * @file cuda_kernels_ltensor.cu - */ -#include - -#include "cuError.hpp" -#include "cuda_helpers.hpp" - -namespace Pennylane::LightningTensor::TNCuda { -/** - * @brief Explicitly get the probability of given state tensor data on GPU - * device. - * - * @param state Complex data pointer of state tensor on device. - * @param probs The probability result on device. - * @param data_size The length of state tensor on device. - * @param thread_per_block Number of threads set per block. - * @param stream_id Stream id of CUDA calls - */ -void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, - const std::size_t thread_per_block, cudaStream_t stream_id); -void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, - const std::size_t thread_per_block, cudaStream_t stream_id); - -/** - * @brief The CUDA kernel that calculate the probability from a given state - * tensor data on GPU device. - * - * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). - * @tparam PrecisionT Floating data type. - * - * @param state Complex data pointer of state tensor on device. - * @param probs The probability result on device. - * @param data_size The length of state tensor on device. - */ -template -__global__ void getProbsKernel(GPUDataT *state, PrecisionT *probs, - const int data_size) { - const unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; - - if (i < data_size) { - PrecisionT real = state[i].x; - PrecisionT imag = state[i].y; - probs[i] = real * real + imag * imag; - } -} - -/** - * @brief The CUDA kernel call wrapper. - * - * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). - * @tparam PrecisionT Floating data type. - * - * @param state Complex data pointer of state tensor on device. - * @param probs The probability result on device. - * @param data_size The length of state tensor on device. - * @param thread_per_block Number of threads set per block. - * @param stream_id Stream id of CUDA calls - */ -template -void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, - std::size_t thread_per_block, cudaStream_t stream_id) { - auto dv = std::div(data_size, thread_per_block); - std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); - const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); - dim3 blockSize(thread_per_block, 1, 1); - dim3 gridSize(block_per_grid, 1); - - getProbsKernel - <<>>(state, probs, data_size); - PL_CUDA_IS_SUCCESS(cudaGetLastError()); -} - -// Definitions -void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, - const std::size_t thread_per_block, cudaStream_t stream_id) { - getProbs_CUDA_call(state, probs, data_size, - thread_per_block, stream_id); -} - -void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, - const std::size_t thread_per_block, cudaStream_t stream_id) { - getProbs_CUDA_call(state, probs, data_size, - thread_per_block, stream_id); -} -} // namespace Pennylane::LightningTensor::TNCuda \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 4700ac7104..17be05301f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -67,42 +67,6 @@ template class MeasurementsTNCuda { explicit MeasurementsTNCuda(const TensorNetT &tensor_network) : tensor_network_(tensor_network){}; - /** - * @brief Probabilities for a subset of the full system. - * - * @param wires Wires will restrict probabilities to a subset - * of the full system. - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. - * - * @return Floating point std::vector with probabilities. - */ - template - auto probs(const std::vector &wires, - const int32_t numHyperSamples = 1) -> std::vector { - const std::size_t length = std::size_t{1} << wires.size(); - - std::vector h_res(length); - - DataBuffer d_output_tensor( - length, tensor_network_.getDevTag(), true); - - DataBuffer d_output_probs( - length, tensor_network_.getDevTag(), true); - - tensor_network_.get_state_tensor(d_output_tensor.getData(), - d_output_tensor.getLength(), wires, - numHyperSamples); - - getProbs_CUDA(d_output_tensor.getData(), d_output_probs.getData(), - length, static_cast(thread_per_block), - tensor_network_.getDevTag().getStreamID()); - - d_output_probs.CopyGpuDataToHost(h_res.data(), h_res.size()); - - return h_res; - } - /** * @brief Calculate var value for a general ObservableTNCuda Observable. * From 6b320796ac16102b4992b077f96e69451a3a26c6 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 17:51:34 +0000 Subject: [PATCH 064/227] revert more changes --- .../tncuda/measurements/MeasurementsTNCuda.hpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 17be05301f..fed9f489b0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -21,7 +21,6 @@ #pragma once #include -#include #include #include @@ -40,13 +39,6 @@ using namespace Pennylane::LightningTensor::TNCuda::Util; /// @endcond namespace Pennylane::LightningTensor::TNCuda::Measures { -extern void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, - const std::size_t thread_per_block, - cudaStream_t stream_id); -extern void getProbs_CUDA(cuDoubleComplex *state, double *probs, - const int data_size, - const std::size_t thread_per_block, - cudaStream_t stream_id); /** * @brief ObservablesTNCuda's Measurement Class. * @@ -59,7 +51,6 @@ template class MeasurementsTNCuda { private: using PrecisionT = typename TensorNetT::PrecisionT; using ComplexT = typename TensorNetT::ComplexT; - using CFP_t = typename TensorNetT::CFP_t; const TensorNetT &tensor_network_; From 15d0ae2a6ea5d901d85eba373005f0ac0d9072f1 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 18:01:21 +0000 Subject: [PATCH 065/227] Trigger CIs From 1944b36c701e67e922296365cb9bc2bfe1876d9b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 18:17:37 +0000 Subject: [PATCH 066/227] update pybind11 --- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index c205ac2021..ff7f072718 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -71,9 +71,8 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { auto *data_ptr = static_cast *>(numpyArrayInfo.ptr); if (state.size()) { - std::copy(tensor_network.getDataVector(), - tensor_network.getDataVector() + - tensor_network.getDataVector().size(), + auto &&state_tensor = tensor_network.getDataVector(); + std::copy(state_tensor.begin(), state_tensor.end(), data_ptr); } }, From 2f9662bc28cb997b15292a04f158dd2f0ec563ae Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 18:32:29 +0000 Subject: [PATCH 067/227] update pybind11 --- .../lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index ff7f072718..aedca37728 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -66,7 +66,7 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { DevTag>()) // num_qubits, max_bond_dim, dev-tag .def( "getState", - [](const TensorNet &tensor_network, np_arr_c &state) { + [](TensorNet &tensor_network, np_arr_c &state) { py::buffer_info numpyArrayInfo = state.request(); auto *data_ptr = static_cast *>(numpyArrayInfo.ptr); From b7ff938fc9f39b8f7bdc906dd928f4387625eeb2 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 31 Jul 2024 20:00:32 +0000 Subject: [PATCH 068/227] enable test_comparison --- tests/test_comparison.py | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 6cacca8c8a..18625a0ca6 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -59,14 +59,14 @@ def one_qubit_block(wires=None): qml.PauliX(wires=wires) -@pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor device dose not support state return", -) class TestComparison: """A test that compares the output states of the lightning device and ``default.qubit`` for a variety of different circuits. This uses ``default.qubit`` as a reference.""" + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor device dose not support 1 wires tensor network", + ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 1)) @pytest.mark.parametrize("wires", [1]) @pytest.mark.parametrize( @@ -102,10 +102,14 @@ def circuit(measurement): assert np.allclose(lightning_state, default_state) assert os.getenv("OMP_NUM_THREADS") == str(num_threads) + # @pytest.mark.skipif( + # device_name == "lightning.tensor", + # reason="lightning.tensor device dose not support state return", + # ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 2)) @pytest.mark.parametrize("wires", [2]) @pytest.mark.parametrize( - "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] + "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] if device_name != "lightning.tensor" else [lightning_backend_dev] ) @pytest.mark.parametrize("num_threads", [1, 2]) def test_two_qubit_circuit( @@ -138,13 +142,21 @@ def circuit(measurement): default = qml.QNode(circuit, dev_d) lightning(qml.expval(qml.PauliZ(0))) - # pylint: disable=protected-access - lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state default_state = default(qml.state) - assert np.allclose(lightning_state, default_state) - + # pylint: disable=protected-access + if device_name == "lightning.tensor": + lightning_state = dev_l._tensornet.state + assert np.allclose(lightning_state, default_state) + else: + lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state + assert np.allclose(lightning_state, default_state) + + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor device dose not support state return", + ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 3)) @pytest.mark.parametrize("wires", [3]) @pytest.mark.parametrize( @@ -196,6 +208,10 @@ def circuit(measurement): assert np.allclose(lightning_state, default_state) + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor device dose not support state return", + ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 4)) @pytest.mark.parametrize("wires", [4]) @pytest.mark.parametrize( @@ -252,6 +268,10 @@ def circuit(measurement): assert np.allclose(lightning_state, default_state) + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor device dose not support state return", + ) @pytest.mark.parametrize( "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] ) From 4fba5026eede03cdb379d77842e07db3f7c64a5e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 12:56:15 +0000 Subject: [PATCH 069/227] resolve more comments --- .../observables/ObservablesTNCudaOperator.hpp | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index d41aba0660..391a3e3e9a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -100,7 +100,7 @@ template class ObservableTNCudaOperator { std::vector ids_; // ids for each term in the graph - const bool var_cal_ = false; + const bool var_cal_{false}; private: /** @@ -145,7 +145,7 @@ template class ObservableTNCudaOperator { } /** - * @brief Create a map of modes to observable meta data. + * @brief Create a map of modes to observable metadata. * * @param obs An observableTNCuda object. * @param modes Modes of all observable terms. @@ -162,8 +162,8 @@ template class ObservableTNCudaOperator { -> std::unordered_map> { std::unordered_map> modes_obsname_map; - auto modes_termx = modes[term_idx]; - auto modes_termy = modes[term_idy]; + auto &&modes_termx = modes[term_idx]; + auto &&modes_termy = modes[term_idy]; for (std::size_t tensor_idx = 0; tensor_idx < modes_termx.size(); tensor_idx++) { @@ -177,12 +177,13 @@ template class ObservableTNCudaOperator { for (std::size_t tensor_idy = 0; tensor_idy < modes_termy.size(); tensor_idy++) { - auto it = modes_obsname_map.find(modes_termy[tensor_idy].front()); + auto &&termy = modes_termy[tensor_idy]; + auto it = modes_obsname_map.find(termy.front()); if (it != modes_obsname_map.end()) { - modes_obsname_map[modes_termy[tensor_idy].front()].push_back( + modes_obsname_map[termy.front()].push_back( obs.getMetaData()[term_idy][tensor_idy]); } else { - modes_obsname_map[modes_termy[tensor_idy].front()] = { + modes_obsname_map[termy.front()] = { obs.getMetaData()[term_idy][tensor_idy]}; } } @@ -223,14 +224,11 @@ template class ObservableTNCudaOperator { * @return obs_key The key of observable tensor operator. */ auto add_meta_data_(const MetaDataT &metaData) -> obs_key { - auto obsName = std::get<0>(metaData); - auto param = std::get<1>(metaData); - auto hermitianMatrix = std::get<2>(metaData); - std::size_t hash_val = 0; - - if (!hermitianMatrix.empty()) { - hash_val = MatrixHasher()(hermitianMatrix); - } + auto &&obsName = std::get<0>(metaData); + auto &¶m = std::get<1>(metaData); + auto &&hermitianMatrix = std::get<2>(metaData); + std::size_t hash_val = + hermitianMatrix.empty() ? 0 : MatrixHasher()(hermitianMatrix); auto obsKey = std::make_tuple(obsName, param, hash_val); @@ -259,6 +257,13 @@ template class ObservableTNCudaOperator { } public: + /** + * @brief Construct a new ObservableTNCudaOperator object. + * + * @param tensor_network Tensor network object. + * @param obs ObservableTNCuda object. + * @param var_cal If true, calculate the variance of the observable. + */ ObservableTNCudaOperator(const TensorNetT &tensor_network, ObservableTNCuda &obs, const bool var_cal = false) @@ -268,11 +273,10 @@ template class ObservableTNCudaOperator { for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { PrecisionT coeff_real = obs.getCoeffs()[term_idx]; - auto coeff = - cuDoubleComplex{static_cast(coeff_real), 0.0}; auto numTensors = obs.getNumTensors()[term_idx]; - coeffs_.emplace_back(coeff); + coeffs_.emplace_back( + cuDoubleComplex{static_cast(coeff_real), 0.0}); numTensors_.emplace_back(numTensors); // number of state modes of each tensor in each term @@ -336,10 +340,12 @@ template class ObservableTNCudaOperator { term_idy++) { PrecisionT coeff_real = obs.getCoeffs()[term_idx] * obs.getCoeffs()[term_idy]; - auto coeff = - cuDoubleComplex{static_cast(coeff_real), 0.0}; + // auto coeff = + // cuDoubleComplex{static_cast(coeff_real), + // 0.0}; - coeffs_.emplace_back(coeff); + coeffs_.emplace_back( + cuDoubleComplex{static_cast(coeff_real), 0.0}); auto modes_obsname_map = create_modes_obsname_map_( obs, modes, term_idx, term_idy); From 4f62281e241950f1c81553f70af3c6fea9404932 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 13:49:40 +0000 Subject: [PATCH 070/227] resolve more comments --- .github/CHANGELOG.md | 2 +- .../measurements/tests/Test_MPSTNCuda_Var.cpp | 6 +++--- .../observables/ObservablesTNCudaOperator.hpp | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 0617d996f3..1754767b4d 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs^2` and this implementation scales `O(num_obs^2)`. +* Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs**2` and this implementation scales `O(num_obs**2)`. [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) ### Breaking changes diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp index 7360c52e42..6e7f209b18 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Var.cpp @@ -179,7 +179,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, using HamiltonianObsT = HamiltonianTNCuda; SECTION("Using TensorProd") { - std::size_t bondDim = GENERATE(2); + std::size_t bondDim = GENERATE(2, 3, 4, 5); constexpr std::size_t num_qubits = 5; constexpr std::size_t num_paulis = 5; constexpr std::size_t num_obs_terms = 6; @@ -266,7 +266,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, } SECTION("Using 1 Hermitian") { - std::size_t bondDim = GENERATE(2); + std::size_t bondDim = GENERATE(2, 3, 4, 5); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; @@ -305,7 +305,7 @@ TEMPLATE_TEST_CASE("Test var value of HamiltonianObs", "[MPSTNCuda_Var]", float, } SECTION("Using 2 Hermitians") { - std::size_t bondDim = GENERATE(2); + std::size_t bondDim = GENERATE(2, 3, 4, 5); std::size_t num_qubits = 3; std::size_t maxBondDim = bondDim; diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 391a3e3e9a..5111fbd468 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -179,12 +179,12 @@ template class ObservableTNCudaOperator { tensor_idy++) { auto &&termy = modes_termy[tensor_idy]; auto it = modes_obsname_map.find(termy.front()); - if (it != modes_obsname_map.end()) { - modes_obsname_map[termy.front()].push_back( - obs.getMetaData()[term_idy][tensor_idy]); - } else { + if (it == modes_obsname_map.end()) { modes_obsname_map[termy.front()] = { obs.getMetaData()[term_idy][tensor_idy]}; + } else { + modes_obsname_map[termy.front()].push_back( + obs.getMetaData()[term_idy][tensor_idy]); } } @@ -224,9 +224,9 @@ template class ObservableTNCudaOperator { * @return obs_key The key of observable tensor operator. */ auto add_meta_data_(const MetaDataT &metaData) -> obs_key { - auto &&obsName = std::get<0>(metaData); - auto &¶m = std::get<1>(metaData); - auto &&hermitianMatrix = std::get<2>(metaData); + auto obsName = std::get<0>(metaData); + auto param = std::get<1>(metaData); + auto hermitianMatrix = std::get<2>(metaData); std::size_t hash_val = hermitianMatrix.empty() ? 0 : MatrixHasher()(hermitianMatrix); From b2c8c2b74c9eff8e2701f7fd6e01d9af788052cc Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 14:27:10 +0000 Subject: [PATCH 071/227] further tidy up code --- .../observables/ObservablesTNCudaOperator.hpp | 47 ++++++------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 5111fbd468..21e49e205f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -340,9 +340,6 @@ template class ObservableTNCudaOperator { term_idy++) { PrecisionT coeff_real = obs.getCoeffs()[term_idx] * obs.getCoeffs()[term_idy]; - // auto coeff = - // cuDoubleComplex{static_cast(coeff_real), - // 0.0}; coeffs_.emplace_back( cuDoubleComplex{static_cast(coeff_real), 0.0}); @@ -373,21 +370,13 @@ template class ObservableTNCudaOperator { auto obsName0 = std::get<0>(metaDataArr[0]); auto obsName1 = std::get<0>(metaDataArr[1]); - auto param0 = std::get<1>(metaDataArr[0]); - auto param1 = std::get<1>(metaDataArr[1]); - - std::string obsName; - if (pauli_map_.find(obsName0) != pauli_map_.end() && pauli_map_.find(obsName1) != pauli_map_.end()) { // Branch for Pauli strings - obsName0 = pauli_map_[obsName0]; - obsName1 = pauli_map_[obsName1]; - obsName = obsName0 + "@" + obsName1; - - MetaDataT metaData = {obsName, {}, {}}; - - auto obsKey = add_meta_data_(metaData); + auto obsName = pauli_map_[obsName0] + "@" + + pauli_map_[obsName1]; + auto &&obsKey = + add_meta_data_(MetaDataT{obsName, {}, {}}); tensorDataPtrPerTerm_.emplace_back( static_cast( @@ -397,13 +386,13 @@ template class ObservableTNCudaOperator { // add both observables matrix to GPU cache auto obsName = obsName0 + "@" + obsName1; - auto hermitianMatrix = - std::get<2>(metaDataArr[0]); + auto obsMat0 = std::get<2>(metaDataArr[0]); + auto obsMat1 = std::get<2>(metaDataArr[1]); - hermitianMatrix.insert( - hermitianMatrix.end(), - std::get<2>(metaDataArr[1]).begin(), - std::get<2>(metaDataArr[1]).end()); + auto hermitianMatrix = obsMat0; + hermitianMatrix.insert(hermitianMatrix.end(), + obsMat1.begin(), + obsMat1.end()); std::size_t hash_val = MatrixHasher()(hermitianMatrix); @@ -414,21 +403,15 @@ template class ObservableTNCudaOperator { if (device_obs_cache_.find(obsKey) == device_obs_cache_.end()) { - auto hermitianMatrix_cu = - cuUtil::complexToCu( - std::get<2>(metaDataArr[0])); - - if (hermitianMatrix_cu.empty()) { - hermitianMatrix_cu = - cuUtil::complexToCu( - std::get<2>(metaDataArr[1])); - } + std::vector hermitianMatrix_cu( + obsMat0.empty() ? obsMat1.size() + : obsMat0.size()); add_obs_(obsKey, hermitianMatrix_cu); - auto obsKey0 = + auto &&obsKey0 = add_meta_data_(metaDataArr[0]); - auto obsKey1 = + auto &&obsKey1 = add_meta_data_(metaDataArr[1]); // update the matrix data with MM operation From 63cd387c29593f9ced2799335e33b9345632029e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 15:42:31 +0000 Subject: [PATCH 072/227] refactor ObservableTNCudaOperator ctor --- .../observables/ObservablesTNCudaOperator.hpp | 377 ++++++++++-------- 1 file changed, 203 insertions(+), 174 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 21e49e205f..85473a1a47 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -245,6 +245,59 @@ template class ObservableTNCudaOperator { return obsKey; } + /** + * @brief Add metadata of product of two observables at the same target. + * + * @param metaData0 Metadata of the first observable. + * @param metaData1 Metadata of the second observable. + * @param cublas CublasCaller object. + * + * @return obs_key The key of observable tensor operator. + */ + auto add_meta_data_(const MetaDataT &metaData0, const MetaDataT &metaData1, + const CublasCaller &cublascaller) -> obs_key { + auto obsName0 = std::get<0>(metaData0); + auto obsName1 = std::get<0>(metaData1); + + auto obsName = obsName0 + "@" + obsName1; + + auto obsMat0 = std::get<2>(metaData0); + auto obsMat1 = std::get<2>(metaData1); + + auto hermitianMatrix = obsMat0; + hermitianMatrix.insert(hermitianMatrix.end(), obsMat1.begin(), + obsMat1.end()); + + std::size_t hash_val = MatrixHasher()(hermitianMatrix); + + auto obsKey = + std::make_tuple(obsName, std::vector{}, hash_val); + + if (device_obs_cache_.find(obsKey) == device_obs_cache_.end()) { + std::vector hermitianMatrix_cu( + obsMat0.empty() ? obsMat1.size() : obsMat0.size()); + + add_obs_(obsKey, hermitianMatrix_cu); + + auto &&obsKey0 = add_meta_data_(metaData0); + auto &&obsKey1 = add_meta_data_(metaData1); + + // update the matrix data with MM operation + CFP_t *mat0 = const_cast(get_obs_device_ptr_(obsKey0)); + CFP_t *mat1 = const_cast(get_obs_device_ptr_(obsKey1)); + CFP_t *res = const_cast(get_obs_device_ptr_(obsKey)); + const std::size_t m = + Pennylane::Util::log2(hermitianMatrix_cu.size()); + + GEMM_CUDA_device(mat0, mat1, res, m, m, m, + tensor_network_.getDevTag().getDeviceID(), + tensor_network_.getDevTag().getStreamID(), + cublascaller); + } + + return obsKey; + } + /** * @brief Returns a pointer to the GPU device memory where the observable is * stored. @@ -256,203 +309,179 @@ template class ObservableTNCudaOperator { return device_obs_cache_.at(obsKey).getDataBuffer().getData(); } - public: /** - * @brief Construct a new ObservableTNCudaOperator object. + * @brief Initialize the observable tensor operator for expectation value + * calculation. * * @param tensor_network Tensor network object. * @param obs ObservableTNCuda object. - * @param var_cal If true, calculate the variance of the observable. */ - ObservableTNCudaOperator(const TensorNetT &tensor_network, - ObservableTNCuda &obs, - const bool var_cal = false) - : tensor_network_{tensor_network}, - numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { - if (!var_cal) { - for (std::size_t term_idx = 0; term_idx < numObsTerms_; - term_idx++) { - PrecisionT coeff_real = obs.getCoeffs()[term_idx]; - auto numTensors = obs.getNumTensors()[term_idx]; + void initHelper_expval_(const TensorNetT &tensor_network, + ObservableTNCuda &obs) { + for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { + PrecisionT coeff_real = obs.getCoeffs()[term_idx]; + auto numTensors = obs.getNumTensors()[term_idx]; + + coeffs_.emplace_back( + cuDoubleComplex{static_cast(coeff_real), 0.0}); + numTensors_.emplace_back(numTensors); + + // number of state modes of each tensor in each term + numModes_.emplace_back(cast_vector( + obs.getNumStateModes()[term_idx])); + + // modes initialization + vector2D modes_per_term; + for (std::size_t tensor_idx = 0; tensor_idx < numTensors; + tensor_idx++) { + modes_per_term.emplace_back( + cuUtil::NormalizeCastIndices( + obs.getStateModes()[term_idx][tensor_idx], + tensor_network.getNumQubits())); + } + modes_.emplace_back(modes_per_term); + + // Not required for var calculation below + // modes pointer initialization + vector1D modesPtrPerTerm; + for (std::size_t tensor_idx = 0; + tensor_idx < modes_[term_idx].size(); tensor_idx++) { + modesPtrPerTerm.emplace_back( + modes_[term_idx][tensor_idx].data()); + } + modesPtr_.emplace_back(modesPtrPerTerm); + + // tensor data initialization + vector1D tensorDataPtrPerTerm_; + for (std::size_t tensor_idx = 0; tensor_idx < numTensors; + tensor_idx++) { + auto obsKey = + add_meta_data_(obs.getMetaData()[term_idx][tensor_idx]); + + tensorDataPtrPerTerm_.emplace_back(get_obs_device_ptr_(obsKey)); + } + tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); + } + } + + /** + * @brief Initialize the observable tensor operator for variance + * calculation. + * + * @param tensor_network Tensor network object. + * @param obs ObservableTNCuda object. + */ + void initHelper_var_(const TensorNetT &tensor_network, + ObservableTNCuda &obs) { + SharedCublasCaller cublascaller = make_shared_cublas_caller(); + + // convert obs modes to cutensornet compatible format/order + vector3D modes; + for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { + vector2D modes_per_term; + for (std::size_t tensor_idx = 0; + tensor_idx < obs.getNumTensors()[term_idx]; tensor_idx++) { + modes_per_term.emplace_back( + cuUtil::NormalizeCastIndices( + obs.getStateModes()[term_idx][tensor_idx], + tensor_network.getNumQubits())); + } + modes.emplace_back(modes_per_term); + } + + for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { + for (std::size_t term_idy = 0; term_idy < numObsTerms_; + term_idy++) { + PrecisionT coeff_real = + obs.getCoeffs()[term_idx] * obs.getCoeffs()[term_idy]; coeffs_.emplace_back( cuDoubleComplex{static_cast(coeff_real), 0.0}); - numTensors_.emplace_back(numTensors); - // number of state modes of each tensor in each term - numModes_.emplace_back(cast_vector( - obs.getNumStateModes()[term_idx])); + auto modes_obsname_map = + create_modes_obsname_map_(obs, modes, term_idx, term_idy); + + auto numTensorsPerTerm = modes_obsname_map.size(); + + numTensors_.emplace_back(numTensorsPerTerm); - // modes initialization vector2D modes_per_term; - for (std::size_t tensor_idx = 0; tensor_idx < numTensors; - tensor_idx++) { + vector1D tensorDataPtrPerTerm_; + vector1D num_modes_per_term; + + for (const auto &tensors_info : modes_obsname_map) { modes_per_term.emplace_back( - cuUtil::NormalizeCastIndices( - obs.getStateModes()[term_idx][tensor_idx], - tensor_network.getNumQubits())); + std::vector{tensors_info.first}); + + num_modes_per_term.emplace_back( + modes_per_term.back().size()); + + auto metaDataArr = tensors_info.second; + + obs_key obsKey; + + if (metaDataArr.size() == 1) { + obsKey = std::move(add_meta_data_(metaDataArr[0])); + } else if (metaDataArr.size() == 2) { + auto obsName0 = std::get<0>(metaDataArr[0]); + auto obsName1 = std::get<0>(metaDataArr[1]); + + if (pauli_map_.find(obsName0) != pauli_map_.end() && + pauli_map_.find(obsName1) != pauli_map_.end()) { + // Branch for Pauli strings + auto obsName = pauli_map_[obsName0] + "@" + + pauli_map_[obsName1]; + obsKey = std::move( + add_meta_data_(MetaDataT{obsName, {}, {}})); + } else { + // Branch for Hermtian involving Pauli strings + // add both observables matrix to GPU cache + obsKey = std::move(add_meta_data_( + metaDataArr[0], metaDataArr[1], *cublascaller)); + } + } else { + PL_ABORT("Only one wire observables are supported " + "for cutensornet v24.03"); + } + + tensorDataPtrPerTerm_.emplace_back( + static_cast(get_obs_device_ptr_(obsKey))); } + modes_.emplace_back(modes_per_term); - // Not required for var calculation below - // modes pointer initialization + numModes_.emplace_back(num_modes_per_term); + + // modes pointer initialization vector1D modesPtrPerTerm; for (std::size_t tensor_idx = 0; - tensor_idx < modes_[term_idx].size(); tensor_idx++) { + tensor_idx < modes_.back().size(); tensor_idx++) { modesPtrPerTerm.emplace_back( - modes_[term_idx][tensor_idx].data()); + modes_.back()[tensor_idx].data()); } modesPtr_.emplace_back(modesPtrPerTerm); - - // tensor data initialization - vector1D tensorDataPtrPerTerm_; - for (std::size_t tensor_idx = 0; tensor_idx < numTensors; - tensor_idx++) { - auto obsKey = - add_meta_data_(obs.getMetaData()[term_idx][tensor_idx]); - - tensorDataPtrPerTerm_.emplace_back( - get_obs_device_ptr_(obsKey)); - } tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); } - } else { - SharedCublasCaller cublascaller = make_shared_cublas_caller(); - - // convert obs modes from std::size_t to int32_t - vector3D modes; - for (std::size_t term_idx = 0; term_idx < numObsTerms_; - term_idx++) { - vector2D modes_per_term; - for (std::size_t tensor_idx = 0; - tensor_idx < obs.getNumTensors()[term_idx]; tensor_idx++) { - modes_per_term.emplace_back( - cuUtil::NormalizeCastIndices( - obs.getStateModes()[term_idx][tensor_idx], - tensor_network.getNumQubits())); - } - modes.emplace_back(modes_per_term); - } + } + } - for (std::size_t term_idx = 0; term_idx < numObsTerms_; - term_idx++) { - for (std::size_t term_idy = 0; term_idy < numObsTerms_; - term_idy++) { - PrecisionT coeff_real = - obs.getCoeffs()[term_idx] * obs.getCoeffs()[term_idy]; - - coeffs_.emplace_back( - cuDoubleComplex{static_cast(coeff_real), 0.0}); - - auto modes_obsname_map = create_modes_obsname_map_( - obs, modes, term_idx, term_idy); - - auto numTensorsPerTerm = modes_obsname_map.size(); - - numTensors_.emplace_back(numTensorsPerTerm); - - vector2D modes_per_term; - vector1D tensorDataPtrPerTerm_; - vector1D num_modes_per_term; - - for (const auto &tensors_info : modes_obsname_map) { - modes_per_term.emplace_back( - std::vector{tensors_info.first}); - - num_modes_per_term.emplace_back( - modes_per_term.back().size()); - auto metaDataArr = tensors_info.second; - if (metaDataArr.size() == 1) { - auto obsKey = add_meta_data_(metaDataArr[0]); - tensorDataPtrPerTerm_.emplace_back( - get_obs_device_ptr_(obsKey)); - } else if (metaDataArr.size() == 2) { - auto obsName0 = std::get<0>(metaDataArr[0]); - auto obsName1 = std::get<0>(metaDataArr[1]); - - if (pauli_map_.find(obsName0) != pauli_map_.end() && - pauli_map_.find(obsName1) != pauli_map_.end()) { - // Branch for Pauli strings - auto obsName = pauli_map_[obsName0] + "@" + - pauli_map_[obsName1]; - auto &&obsKey = - add_meta_data_(MetaDataT{obsName, {}, {}}); - - tensorDataPtrPerTerm_.emplace_back( - static_cast( - get_obs_device_ptr_(obsKey))); - } else { - // Branch for Hermtian involving Pauli strings - // add both observables matrix to GPU cache - auto obsName = obsName0 + "@" + obsName1; - - auto obsMat0 = std::get<2>(metaDataArr[0]); - auto obsMat1 = std::get<2>(metaDataArr[1]); - - auto hermitianMatrix = obsMat0; - hermitianMatrix.insert(hermitianMatrix.end(), - obsMat1.begin(), - obsMat1.end()); - - std::size_t hash_val = - MatrixHasher()(hermitianMatrix); - - auto obsKey = std::make_tuple( - obsName, std::vector{}, - hash_val); - - if (device_obs_cache_.find(obsKey) == - device_obs_cache_.end()) { - std::vector hermitianMatrix_cu( - obsMat0.empty() ? obsMat1.size() - : obsMat0.size()); - - add_obs_(obsKey, hermitianMatrix_cu); - - auto &&obsKey0 = - add_meta_data_(metaDataArr[0]); - auto &&obsKey1 = - add_meta_data_(metaDataArr[1]); - - // update the matrix data with MM operation - CFP_t *mat0 = const_cast( - get_obs_device_ptr_(obsKey0)); - CFP_t *mat1 = const_cast( - get_obs_device_ptr_(obsKey1)); - CFP_t *res = const_cast( - get_obs_device_ptr_(obsKey)); - std::size_t m = Pennylane::Util::log2( - hermitianMatrix_cu.size()); - - GEMM_CUDA_device(mat0, mat1, res, m, m, m, - tensor_network_.getDevTag() - .getDeviceID(), - tensor_network_.getDevTag() - .getStreamID(), - *cublascaller); - } - tensorDataPtrPerTerm_.emplace_back( - get_obs_device_ptr_(obsKey)); - } - } else { - PL_ABORT("Only one wire observables are supported " - "for cutensornet v24.03"); - } - } - modes_.emplace_back(modes_per_term); - numModes_.emplace_back(num_modes_per_term); - - // modes pointer initialization - vector1D modesPtrPerTerm; - for (std::size_t tensor_idx = 0; - tensor_idx < modes_.back().size(); tensor_idx++) { - modesPtrPerTerm.emplace_back( - modes_.back()[tensor_idx].data()); - } - modesPtr_.emplace_back(modesPtrPerTerm); - tensorDataPtr_.emplace_back(tensorDataPtrPerTerm_); - } - } + public: + /** + * @brief Construct a new ObservableTNCudaOperator object. + * + * @param tensor_network Tensor network object. + * @param obs ObservableTNCuda object. + * @param var_cal If true, calculate the variance of the observable. + */ + ObservableTNCudaOperator(const TensorNetT &tensor_network, + ObservableTNCuda &obs, + const bool var_cal = false) + : tensor_network_{tensor_network}, + numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { + if (!var_cal) { + initHelper_expval_(tensor_network, obs); + } else { + initHelper_var_(tensor_network, obs); } PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateNetworkOperator( From bf670fceca15cf8429b311806239c5c30acc785f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 15:59:11 +0000 Subject: [PATCH 073/227] update python layer --- .../lightning_tensor/_measurements.py | 5 ++- .../lightning_tensor/test_gates_and_expval.py | 42 ++++++++++++------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 14855e4897..1bfa9570d4 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -84,7 +84,9 @@ def expval(self, measurementprocess: MeasurementProcess): return self._measurement_lightning.expval(ob_serialized) def var(self, measurementprocess: MeasurementProcess): - """Variance of the supplied observable contained in the MeasurementProcess. + """Variance of the supplied observable contained in the MeasurementProcess. Note that the variance is + calculated as - **2. The current implementation only supports single-wire observables. + 2 and 2+-wires observables, projector and sparse-hamiltonian are not supported. Args: measurementprocess (StateMeasurement): measurement to apply to the state @@ -92,7 +94,6 @@ def var(self, measurementprocess: MeasurementProcess): Returns: Variance of the observable """ - if isinstance(measurementprocess.obs, qml.SparseHamiltonian): raise NotImplementedError("Sparse Hamiltonian Observables are not supported.") diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index ba4d58e0fd..97fb6f9113 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -239,45 +239,55 @@ def circuit_expval(): with pytest.raises(DeviceError): circuit_expval() - def test_measurement_sparseH_not_supported(self): - """Test that expval/var of SparseH is not supported.""" - with qml.queuing.AnnotatedQueue() as q0: + def test_expval_sparseH_not_supported(self): + """Test that expval of SparseH is not supported.""" + with qml.queuing.AnnotatedQueue() as q: qml.expval(qml.SparseHamiltonian(qml.PauliX.compute_sparse_matrix(), wires=0)) - with qml.queuing.AnnotatedQueue() as q1: - qml.var(qml.SparseHamiltonian(qml.PauliX.compute_sparse_matrix(), wires=0)) - tensornet = LightningTensorNet(4, 10) m = LightningTensorMeasurements(tensornet) with pytest.raises(NotImplementedError, match="Sparse Hamiltonians are not supported."): - m.expval(q0.queue[0]) + m.expval(q.queue[0]) + + def test_var_sparseH_not_supported(self): + """Test that var of SparseH is not supported.""" + with qml.queuing.AnnotatedQueue() as q: + qml.var(qml.SparseHamiltonian(qml.PauliX.compute_sparse_matrix(), wires=0)) + + tensornet = LightningTensorNet(4, 10) + m = LightningTensorMeasurements(tensornet) with pytest.raises( NotImplementedError, match="Sparse Hamiltonian Observables are not supported." ): - m.var(q1.queue[0]) + m.var(q.queue[0]) - def test_measurement_hermitian_not_supported(self): - """Test that expval/var of Hermitian with 1+ wires is not supported.""" - with qml.queuing.AnnotatedQueue() as q0: + def test_expval_hermitian_not_supported(self): + """Test that expval of Hermitian with 1+ wires is not supported.""" + with qml.queuing.AnnotatedQueue() as q: qml.expval(qml.Hermitian(np.eye(4), wires=[0, 1])) - with qml.queuing.AnnotatedQueue() as q1: - qml.var(qml.Hermitian(np.eye(4), wires=[0, 1])) - tensornet = LightningTensorNet(4, 10) m = LightningTensorMeasurements(tensornet) with pytest.raises( ValueError, match="The number of Hermitian observables target wires should be 1." ): - m.expval(q0.queue[0]) + m.expval(q.queue[0]) + + def test_var_hermitian_not_supported(self): + """Test that var of Hermitian with 1+ wires is not supported.""" + with qml.queuing.AnnotatedQueue() as q: + qml.var(qml.Hermitian(np.eye(4), wires=[0, 1])) + + tensornet = LightningTensorNet(4, 10) + m = LightningTensorMeasurements(tensornet) with pytest.raises( ValueError, match="The number of Hermitian observables target wires should be 1." ): - m.var(q1.queue[0]) + m.var(q.queue[0]) def test_measurement_shot_not_supported(self): """Test shots measurement error for measure_tensor_network.""" From cbb0d8d5865af71846a26b86c0f3412069e149f7 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 16:07:42 +0000 Subject: [PATCH 074/227] mark pauli_map_ as static --- .../tncuda/observables/ObservablesTNCudaOperator.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 85473a1a47..0411f4436d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -71,11 +71,12 @@ template class ObservableTNCudaOperator { std::tuple, std::size_t>; private: - std::unordered_map pauli_map_{{"Identity", "I"}, - {"PauliX", "X"}, - {"PauliY", "Y"}, - {"PauliZ", "Z"}, - {"Hadamard", "H"}}; + static inline std::unordered_map pauli_map_{ + {"Identity", "I"}, + {"PauliX", "X"}, + {"PauliY", "Y"}, + {"PauliZ", "Z"}, + {"Hadamard", "H"}}; private: cutensornetNetworkOperator_t obsOperator_{ From 7c35f9ce90f37248f83605a14b0c8084603a1f9e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 17:16:10 +0000 Subject: [PATCH 075/227] move two paulis obskey construction to helper methods as well --- .../observables/ObservablesTNCudaOperator.hpp | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 0411f4436d..e7fbaf1ba5 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -259,6 +259,13 @@ template class ObservableTNCudaOperator { const CublasCaller &cublascaller) -> obs_key { auto obsName0 = std::get<0>(metaData0); auto obsName1 = std::get<0>(metaData1); + + // Branch for two Pauli observables + if (pauli_map_.find(obsName0) != pauli_map_.end() && + pauli_map_.find(obsName1) != pauli_map_.end()) { + auto obsName = pauli_map_[obsName0] + "@" + pauli_map_[obsName1]; + return add_meta_data_(MetaDataT{obsName, {}, {}}); + } auto obsName = obsName0 + "@" + obsName1; @@ -424,22 +431,8 @@ template class ObservableTNCudaOperator { if (metaDataArr.size() == 1) { obsKey = std::move(add_meta_data_(metaDataArr[0])); } else if (metaDataArr.size() == 2) { - auto obsName0 = std::get<0>(metaDataArr[0]); - auto obsName1 = std::get<0>(metaDataArr[1]); - - if (pauli_map_.find(obsName0) != pauli_map_.end() && - pauli_map_.find(obsName1) != pauli_map_.end()) { - // Branch for Pauli strings - auto obsName = pauli_map_[obsName0] + "@" + - pauli_map_[obsName1]; - obsKey = std::move( - add_meta_data_(MetaDataT{obsName, {}, {}})); - } else { - // Branch for Hermtian involving Pauli strings - // add both observables matrix to GPU cache - obsKey = std::move(add_meta_data_( - metaDataArr[0], metaDataArr[1], *cublascaller)); - } + obsKey = std::move(add_meta_data_( + metaDataArr[0], metaDataArr[1], *cublascaller)); } else { PL_ABORT("Only one wire observables are supported " "for cutensornet v24.03"); From fb1d7bcd086e5861e9bd00fd742ef5b406ab2c02 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 17:40:11 +0000 Subject: [PATCH 076/227] add unit tests to cover exceptions --- .../observables/ObservablesTNCudaOperator.hpp | 1 - .../tncuda/observables/tests/CMakeLists.txt | 3 +- .../Test_Observables_TNCudaOperators.cpp | 65 +++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/Test_Observables_TNCudaOperators.cpp diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index e7fbaf1ba5..92ee85433b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -259,7 +259,6 @@ template class ObservableTNCudaOperator { const CublasCaller &cublascaller) -> obs_key { auto obsName0 = std::get<0>(metaData0); auto obsName1 = std::get<0>(metaData1); - // Branch for two Pauli observables if (pauli_map_.find(obsName0) != pauli_map_.end() && pauli_map_.find(obsName1) != pauli_map_.end()) { diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/CMakeLists.txt index 50819374b5..cd15b47f88 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/CMakeLists.txt @@ -28,7 +28,8 @@ target_sources(${PL_BACKEND}_observables_tests INTERFACE runner_${PL_BACKEND}_ob ################################################################################ # Define targets ################################################################################ -set(TEST_SOURCES Test_Observables_TNCuda.cpp) +set(TEST_SOURCES Test_Observables_TNCuda.cpp + Test_Observables_TNCudaOperators.cpp) add_executable(${PL_BACKEND}_observables_test_runner ${TEST_SOURCES}) target_link_libraries(${PL_BACKEND}_observables_test_runner PRIVATE ${PL_BACKEND}_observables_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/Test_Observables_TNCudaOperators.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/Test_Observables_TNCudaOperators.cpp new file mode 100644 index 0000000000..0ff0d40013 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/tests/Test_Observables_TNCudaOperators.cpp @@ -0,0 +1,65 @@ +// Copyright 2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include + +#include + +#include "MPSTNCuda.hpp" +#include "ObservablesTNCuda.hpp" +#include "ObservablesTNCudaOperator.hpp" + +#include "TestHelpers.hpp" + +/// @cond DEV +namespace { +using namespace Pennylane::LightningTensor::TNCuda::Observables; +using Pennylane::Util::LightningException; +} // namespace +/// @endcond + +TEMPLATE_TEST_CASE("[CTOR]", "[ObservablesTNCudaOperator]", float, double) { + { + using TensorNetT = MPSTNCuda; + using PrecisionT = typename TensorNetT::PrecisionT; + // using ComplexT = typename TensorNetT::ComplexT; + using NamedObsT = NamedObsTNCuda; + using HamiltonianT = HamiltonianTNCuda; + + auto cnot = std::make_shared( + "CNOT", std::vector{0, 1}); // codecov test only + + auto x0 = + std::make_shared("PauliX", std::vector{0}); + auto x1 = + std::make_shared("PauliX", std::vector{1}); + + auto obs = HamiltonianT::create( + {PrecisionT{1.0}, PrecisionT{1.0}, PrecisionT{1.0}}, + {cnot, x0, x1}); + + SECTION("Test TNCudaOperator ctor failures") { + std::size_t num_qubits = 3; + std::size_t maxExtent = 2; + DevTag dev_tag{0, 0}; + + TensorNetT mps_state{num_qubits, maxExtent, dev_tag}; + + const bool val_cal = true; + + REQUIRE_THROWS_AS( + ObservableTNCudaOperator(mps_state, *obs, val_cal), + LightningException); + } + } +} \ No newline at end of file From 6862e122607e6774a95e6b07b174b92700907566 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 19:29:59 +0000 Subject: [PATCH 077/227] update python layer for qml.state support --- .../lightning_tensor/_measurements.py | 15 +++++ .../lightning_tensor/_tensornet.py | 1 - .../lightning_tensor/lightning_tensor.py | 12 ++++ tests/test_apply.py | 63 ++++++++++--------- tests/test_comparison.py | 57 ++++++++++------- tests/test_gates.py | 6 -- 6 files changed, 96 insertions(+), 58 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 1bfa9570d4..16565917db 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -61,6 +61,18 @@ def _measurement_dtype(self): """ return MeasurementsC64 if self.dtype == np.complex64 else MeasurementsC128 + def state_diagonalizing_gates(self, measurementprocess: StateMeasurement) -> TensorLike: + """Apply a measurement to state when the measurement process has an observable with diagonalizing gates. + This method is bypassing the measurement process to default.qubit implementation. + + Args: + measurementprocess (StateMeasurement): measurement to apply to the state + + Returns: + TensorLike: the result of the measurement + """ + return self._tensornet.state + # pylint: disable=protected-access def expval(self, measurementprocess: MeasurementProcess): """Expectation value of the supplied observable contained in the MeasurementProcess. @@ -124,6 +136,9 @@ def get_measurement_function( if isinstance(measurementprocess, VarianceMP): return self.var + if measurementprocess.obs is None: + return self.state_diagonalizing_gates + raise NotImplementedError( "Does not support current measurement. Only ExpectationMP measurements are supported." ) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index eab81f6be0..88c414f4eb 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -194,7 +194,6 @@ def set_tensor_network(self, circuit: QuantumScript): Returns: LightningTensorNet: Lightning final state class. - """ self.apply_operations(circuit.operations) if self._method == "mps": diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index bcbda55334..7a108e18f7 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -299,6 +299,8 @@ def __init__( if not isinstance(self._max_bond_dim, int) or self._max_bond_dim < 1: raise ValueError("The maximum bond dimension must be an integer greater than 0.") + self._tensor_network = None + @property def name(self): """The name of the device.""" @@ -326,6 +328,16 @@ def c_dtype(self): def _tensornet(self): """Return the tensornet object.""" + if self._tensor_network is None: + self._tensor_network = LightningTensorNet( + self._num_wires, + self._method, + self._c_dtype, + self._max_bond_dim, + self._cutoff, + self._cutoff_mode, + ) + return self._tensor_network return LightningTensorNet( self._num_wires, self._method, diff --git a/tests/test_apply.py b/tests/test_apply.py index cb441753d2..a055d5e4b3 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -183,24 +183,31 @@ def test_apply_operation_preserve_pointer_three_wires_no_parameters( @pytest.mark.parametrize( "operation,expected_output,par", - [ - (qml.BasisState, [0, 0, 1, 0], [1, 0]), - (qml.BasisState, [0, 0, 0, 1], [1, 1]), - (qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]), - (qml.QubitStateVector, [0, 0, 0, 1], [0, 0, 0, 1]), - (qml.StatePrep, [0, 0, 1, 0], [0, 0, 1, 0]), - (qml.StatePrep, [0, 0, 0, 1], [0, 0, 0, 1]), - ( - qml.StatePrep, - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ( - qml.StatePrep, - [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], - [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ], + ( + [ + (qml.BasisState, [0, 0, 1, 0], [1, 0]), + (qml.BasisState, [0, 0, 0, 1], [1, 1]), + (qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]), + (qml.QubitStateVector, [0, 0, 0, 1], [0, 0, 0, 1]), + (qml.StatePrep, [0, 0, 1, 0], [0, 0, 1, 0]), + (qml.StatePrep, [0, 0, 0, 1], [0, 0, 0, 1]), + ( + qml.StatePrep, + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + ), + ( + qml.StatePrep, + [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], + [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], + ), + ] + if device_name != "lightning.tensor" + else [ + (qml.BasisState, [0, 0, 1, 0], [1, 0]), + (qml.BasisState, [0, 0, 0, 1], [1, 1]), + ] + ), ) def test_apply_operation_state_preparation( self, qubit_device, tol, operation, expected_output, par @@ -529,7 +536,7 @@ class TestExpval: @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector & qml.StatePrep", + reason="lightning.tensor does not support single wire devices", ) @pytest.mark.parametrize( "operation,input,expected_output", @@ -593,7 +600,7 @@ class TestVar: @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector & qml.StatePrep", + reason="lightning.tensor does not support single wire devices", ) @pytest.mark.parametrize( "operation,input,expected_output", @@ -635,7 +642,7 @@ def test_var_single_wire_no_parameters( @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support shot measurement", + reason="lightning.tensor does not support shot measurement and single-wire devices", ) def test_var_estimate(self): """Test that the variance is not analytically calculated""" @@ -855,7 +862,7 @@ def circuit(x): # This test is ran against the state |0> with one Z expval @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support shot measurements", + reason="lightning.tensor does not support shot measurements and single-wire devices", ) @pytest.mark.parametrize( "name,expected_output", @@ -1471,7 +1478,7 @@ def compute_matrix(*params, **hyperparams): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.state()", + reason="lightning.tensor does not support StatePrep", ) @pytest.mark.parametrize( "ops0", @@ -1516,10 +1523,6 @@ def circuit(): assert np.allclose(results, expected) -@pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.StatePrep()", -) @pytest.mark.parametrize( "op", [ @@ -1542,7 +1545,11 @@ def test_circuit_with_stateprep(op, theta, phi, tol): init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) def circuit(): - qml.StatePrep(init_state, wires=range(n_qubits)) + ( + qml.StatePrep(init_state, wires=range(n_qubits)) + if device_name != "lightning.tensor" + else qml.BasisState([0, 0, 0, 0, 0], wires=[0, 1, 2, 3, 4]) + ) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 18625a0ca6..504e23aed9 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -102,14 +102,15 @@ def circuit(measurement): assert np.allclose(lightning_state, default_state) assert os.getenv("OMP_NUM_THREADS") == str(num_threads) - # @pytest.mark.skipif( - # device_name == "lightning.tensor", - # reason="lightning.tensor device dose not support state return", - # ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 2)) @pytest.mark.parametrize("wires", [2]) @pytest.mark.parametrize( - "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] if device_name != "lightning.tensor" else [lightning_backend_dev] + "lightning_dev_version", + ( + [lightning_backend_dev, lightning_backend_batch_obs_dev] + if device_name != "lightning.tensor" + else [lightning_backend_dev] + ), ) @pytest.mark.parametrize("num_threads", [1, 2]) def test_two_qubit_circuit( @@ -147,20 +148,21 @@ def circuit(measurement): # pylint: disable=protected-access if device_name == "lightning.tensor": - lightning_state = dev_l._tensornet.state + lightning_state = dev_l._tensor_network.state assert np.allclose(lightning_state, default_state) else: lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state assert np.allclose(lightning_state, default_state) - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor device dose not support state return", - ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 3)) @pytest.mark.parametrize("wires", [3]) @pytest.mark.parametrize( - "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] + "lightning_dev_version", + ( + [lightning_backend_dev, lightning_backend_batch_obs_dev] + if device_name != "lightning.tensor" + else [lightning_backend_dev] + ), ) @pytest.mark.parametrize("num_threads", [1, 2]) def test_three_qubit_circuit( @@ -201,21 +203,26 @@ def circuit(measurement): default = qml.QNode(circuit, dev_d) lightning(qml.expval(qml.PauliZ(0))) - # pylint: disable=protected-access - lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state default_state = default(qml.state) - assert np.allclose(lightning_state, default_state) + # pylint: disable=protected-access + if device_name == "lightning.tensor": + lightning_state = dev_l._tensor_network.state + assert np.allclose(lightning_state, default_state) + else: + lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state + assert np.allclose(lightning_state, default_state) - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor device dose not support state return", - ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 4)) @pytest.mark.parametrize("wires", [4]) @pytest.mark.parametrize( - "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] + "lightning_dev_version", + ( + [lightning_backend_dev, lightning_backend_batch_obs_dev] + if device_name != "lightning.tensor" + else [lightning_backend_dev] + ), ) @pytest.mark.parametrize("num_threads", [1, 2]) def test_four_qubit_circuit( @@ -261,16 +268,20 @@ def circuit(measurement): default = qml.QNode(circuit, dev_d) lightning(qml.expval(qml.PauliZ(0))) - # pylint: disable=protected-access - lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state default_state = default(qml.state) - assert np.allclose(lightning_state, default_state) + # pylint: disable=protected-access + if device_name == "lightning.tensor": + lightning_state = dev_l._tensor_network.state + assert np.allclose(lightning_state, default_state) + else: + lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state + assert np.allclose(lightning_state, default_state) @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor device dose not support state return", + reason="lightning.tensor device dose not support initialization with a state vector", ) @pytest.mark.parametrize( "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] diff --git a/tests/test_gates.py b/tests/test_gates.py index d4e99ebada..4958c7ccc1 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -27,12 +27,6 @@ if not ld._CPP_BINARY_AVAILABLE: pytest.skip("No binary module found. Skipping.", allow_module_level=True) -if device_name == "lightning.tensor": - pytest.skip( - "lightning.tensor doesn't support qml.state() used across this module.", - allow_module_level=True, - ) - @pytest.fixture def op(op_name): From 90f9dc9569ba6ec49388080b17224c635fea4935 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 20:32:18 +0000 Subject: [PATCH 078/227] update python unit tests --- .../lightning_tensor/lightning_tensor.py | 2 - .../lightning_tensor/test_gates_and_expval.py | 2 - tests/test_gates.py | 44 +++++++++++++++-- tests/test_templates.py | 48 ++++++++----------- 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 7a108e18f7..0270bce6bc 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -117,8 +117,6 @@ "OrbitalRotation", "QFT", "ECR", - "BlockEncode", - "C(BlockEncode)", } ) diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index 97fb6f9113..ee60dffba9 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -118,8 +118,6 @@ def circuit_ansatz(params, wires): qml.OrbitalRotation(params[20], wires=[wires[0], wires[1], wires[5], wires[6]]) qml.QFT(wires=[wires[0]]) qml.ECR(wires=[wires[1], wires[3]]) - qml.BlockEncode([[0.1, 0.2], [0.3, 0.4]], wires=[wires[0], wires[3]]) - qml.ctrl(qml.BlockEncode([0.1], wires=[wires[0]]), control=wires[1]) @pytest.mark.parametrize( diff --git a/tests/test_gates.py b/tests/test_gates.py index 4958c7ccc1..855619efc5 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -99,6 +99,14 @@ def test_gate_unitary_correct(op, op_name): wires = len(op[2]["wires"]) + if wires == 1 and device_name == "lightning.tensor": + pytest.skip("Skipping single wire device on lightning.tensor.") + + if op_name == "QubitUnitary" and device_name == "lightning.tensor": + pytest.skip( + "Skipping QubitUnitary on lightning.tensor. It can't be decomposed into 1-wire or 2-wire gates" + ) + dev = qml.device(device_name, wires=wires) @qml.qnode(dev) @@ -157,6 +165,14 @@ def test_inverse_unitary_correct(op, op_name): wires = len(op[2]["wires"]) + if wires == 1 and device_name == "lightning.tensor": + pytest.skip("Skipping single wire device on lightning.tensor.") + + if op_name == "QubitUnitary" and device_name == "lightning.tensor": + pytest.skip( + "Skipping QubitUnitary on lightning.tensor. It can't be decomposed into 1-wire or 2-wire gates" + ) + dev = qml.device(device_name, wires=wires) @qml.qnode(dev) @@ -283,9 +299,15 @@ def test_qubit_RY(theta, phi, tol): init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) def circuit(): - qml.StatePrep(init_state, wires=range(n_qubits)) + ( + qml.StatePrep(init_state, wires=range(n_qubits)) + if device_name != "lightning.tensor" + else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) + ) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) + qml.RY(theta, wires=[2]) + qml.RY(phi, wires=[3]) return qml.state() circ = qml.QNode(circuit, dev) @@ -294,7 +316,7 @@ def circuit(): @pytest.mark.parametrize("theta,phi", list(zip(THETA, PHI))) -@pytest.mark.parametrize("n_wires", range(1, 7)) +@pytest.mark.parametrize("n_wires", range(1, 7) if device_name != "lightning.tensor" else [1, 2]) def test_qubit_unitary(n_wires, theta, phi, tol): """Test that Hadamard expectation value is correct""" n_qubits = 10 @@ -312,9 +334,21 @@ def test_qubit_unitary(n_wires, theta, phi, tol): for perm in perms: def circuit(): - qml.StatePrep(init_state, wires=range(n_qubits)) + ( + qml.StatePrep(init_state, wires=range(n_qubits)) + if device_name != "lightning.tensor" + else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) + ) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) + qml.RY(theta, wires=[2]) + qml.RY(phi, wires=[3]) + qml.RY(theta, wires=[4]) + qml.RY(phi, wires=[5]) + qml.RY(theta, wires=[6]) + qml.RY(phi, wires=[7]) + qml.RY(phi, wires=[8]) + qml.RY(phi, wires=[9]) qml.CNOT(wires=[0, 1]) qml.QubitUnitary(U, wires=perm) return qml.state() @@ -499,6 +533,10 @@ def cnot_circuit(): assert np.allclose(circ(), circ_def(), tol) +@pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor does not support controlled globalphase gate.", +) @pytest.mark.parametrize("control_value", [False, True]) @pytest.mark.parametrize("n_qubits", list(range(2, 8))) def test_controlled_globalphase(n_qubits, control_value, tol): diff --git a/tests/test_templates.py b/tests/test_templates.py index 142e397ac7..b6d290cb10 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -98,7 +98,7 @@ def test_angleembedding(self, n_qubits): def circuit(feature_vector): qml.AngleEmbedding(features=feature_vector, wires=range(n_qubits), rotation="Z") - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() X = np.random.rand(n_qubits) @@ -151,7 +151,7 @@ def test_basisembedding(self, n_qubits): def circuit(feature_vector): qml.BasisEmbedding(features=feature_vector, wires=range(n_qubits)) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() X = np.ones(n_qubits) @@ -256,7 +256,7 @@ def test_randomlayers(self, n_qubits): def circuit(weights): qml.RandomLayers(weights=weights, wires=range(n_qubits)) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() weights = np.array([[0.1, -2.1, 1.4]]) @@ -276,7 +276,7 @@ def test_stronglyentanglinglayers(self, n_qubits): def circuit(weights): qml.StronglyEntanglingLayers(weights=weights, wires=range(n_qubits)) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() shape = qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=n_qubits) weights = np.random.random(size=shape) @@ -419,7 +419,7 @@ def test_allsinglesdoubles(self): def circuit(weights, hf_state, singles, doubles): qml.templates.AllSinglesDoubles(weights, range(n_qubits), hf_state, singles, doubles) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() weights = np.random.normal(0, np.pi, len(singles) + len(doubles)) res = qml.QNode(circuit, dev, diff_method=None)(weights, hf_state, singles, doubles) @@ -442,7 +442,7 @@ def circuit(unitary_matrix): wires=range(3), unitary_matrix=unitary_matrix, ) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() unitary_matrix = np.array( [ @@ -475,7 +475,7 @@ def test_gatefabric(self): def circuit(weights): qml.GateFabric(weights, wires=[0, 1, 2, 3], init_state=ref_state, include_pi=True) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() layers = 2 shape = qml.GateFabric.shape(n_layers=layers, n_wires=n_qubits) @@ -520,7 +520,7 @@ def test_uccsd(self): def circuit(weights): qml.UCCSD(weights, range(n_qubits), s_wires, d_wires, hf_state) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() weights = np.random.random(len(singles) + len(doubles)) @@ -559,7 +559,7 @@ def test_kupccgsd(self): def circuit(weights): qml.kUpCCGSD(weights, range(n_qubits), k=1, delta_sz=0, init_state=hf_state) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() # Get the shape of the weights for this template layers = 1 @@ -593,7 +593,7 @@ def test_particleconservingu1(self): # Define the cost function def circuit(params): ansatz(params) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() layers = 2 shape = qml.ParticleConservingU1.shape(layers, n_qubits) @@ -626,7 +626,7 @@ def test_particleconservingu2(self): # Define the cost function def circuit(params): ansatz(params) - return qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) + return qml.state() layers = 2 shape = qml.ParticleConservingU2.shape(layers, n_qubits) @@ -652,10 +652,7 @@ def test_approxtimeevolution(self, n_qubits): def circuit(time): qml.ApproxTimeEvolution(hamiltonian, time, 1) - return ( - qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) - ) # lightning.tensor does not support qml.state() - + return qml.state() res = qml.QNode(circuit, dev, diff_method=None)(1.3) ref = qml.QNode(circuit, dq, diff_method=None)(1.3) @@ -676,9 +673,7 @@ def test_qdrift(self, n_qubits): def circuit(time): qml.QDrift(hamiltonian, time=time, n=10, seed=10) - return ( - qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) - ) # lightning.tensor does not support qml.state() + return qml.state() res = qml.QNode(circuit, dev, diff_method=None)(1.3) ref = qml.QNode(circuit, dq, diff_method=None)(1.3) @@ -700,9 +695,7 @@ def test_trotterproduct(self, n_qubits): def circuit(time): qml.TrotterProduct(hamiltonian, time=time, order=2) - return ( - qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) - ) # lightning.tensor does not support qml.state() + return qml.state() res = qml.QNode(circuit, dev, diff_method=None)(1.3) ref = qml.QNode(circuit, dq, diff_method=None)(1.3) @@ -757,9 +750,7 @@ def test_qft(self, n_qubits): def circuit(basis_state): qml.BasisState(basis_state, wires=range(n_qubits)) qml.QFT(wires=range(n_qubits)) - return ( - qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) - ) # lightning.tensor does not support qml.state() + return qml.state() basis_state = [0] * n_qubits basis_state[0] = 1 @@ -797,9 +788,7 @@ def test_aqft(self, n_qubits): def circuit(basis_state): qml.BasisState(basis_state, wires=range(n_qubits)) qml.AQFT(order=1, wires=range(n_qubits)) - return ( - qml.state() if device_name != "lightning.tensor" else qml.expval(qml.PauliZ(0)) - ) # lightning.tensor does not support qml.state() + return qml.state() basis_state = [0] * n_qubits basis_state[0] = 1 @@ -811,7 +800,10 @@ def circuit(basis_state): class TestQSVT: """Test the QSVT algorithm.""" - + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor does not support BlockEncode", + ) @pytest.mark.parametrize("n_qubits", range(2, 20, 2)) def test_qsvt(self, n_qubits): dev = qml.device(device_name, wires=n_qubits) From 8b2d7c0976639a68bb121b23b506702a5ebfa233 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 21:03:27 +0000 Subject: [PATCH 079/227] make format --- doc/lightning_tensor/device.rst | 3 ++- pennylane_lightning/lightning_tensor/lightning_tensor.py | 2 ++ tests/test_execute.py | 2 +- tests/test_templates.py | 4 +++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/lightning_tensor/device.rst b/doc/lightning_tensor/device.rst index 3e17424c4b..c4a0d4ae74 100644 --- a/doc/lightning_tensor/device.rst +++ b/doc/lightning_tensor/device.rst @@ -70,7 +70,6 @@ The "lightning.tensor" supports 1- and 2-wire gate operations and all other oper :nosignatures: ~pennylane.BasisState - ~pennylane.BlockEncode ~pennylane.CNOT ~pennylane.ControlledPhaseShift ~pennylane.ControlledQubitUnitary @@ -134,6 +133,8 @@ The "lightning.tensor" supports 1- and 2-wire gate operations and all other oper ~pennylane.DoubleExcitationMinus ~pennylane.DoubleExcitationPlus ~pennylane.GlobalPhase + ~pennylane.BlockEncode + .. raw:: html diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 0270bce6bc..9b3944e081 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -326,6 +326,8 @@ def c_dtype(self): def _tensornet(self): """Return the tensornet object.""" + # Ensure that the tensor network is only created and calculated once, which enable access to qml.state(). + # parameter-shift/finite-diff calculation will return a new LightningTensorNet object. if self._tensor_network is None: self._tensor_network = LightningTensorNet( self._num_wires, diff --git a/tests/test_execute.py b/tests/test_execute.py index 02a6bfa1f6..8f5ce2745e 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -27,7 +27,7 @@ @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support gates with more than 2 wires, preprocess is required for the following tests", + reason="lightning.tensor does not fully support `enable_new_opmath_cm`", ) @pytest.mark.usefixtures("use_legacy_and_new_opmath") @pytest.mark.parametrize("diff_method", ("param_shift", "finite_diff")) diff --git a/tests/test_templates.py b/tests/test_templates.py index b6d290cb10..d97d1a29a3 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -652,7 +652,8 @@ def test_approxtimeevolution(self, n_qubits): def circuit(time): qml.ApproxTimeEvolution(hamiltonian, time, 1) - return qml.state() + return qml.state() + res = qml.QNode(circuit, dev, diff_method=None)(1.3) ref = qml.QNode(circuit, dq, diff_method=None)(1.3) @@ -800,6 +801,7 @@ def circuit(basis_state): class TestQSVT: """Test the QSVT algorithm.""" + @pytest.mark.skipif( device_name == "lightning.tensor", reason="lightning.tensor does not support BlockEncode", From f462cd464046a287fd33ee356b140d1086fff17a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 21:36:31 +0000 Subject: [PATCH 080/227] revert some changes --- .../lightning_tensor/tncuda/CMakeLists.txt | 4 +- .../tncuda/cuda_kernels_ltensor.cu | 96 +++++++++++++++++++ .../measurements/MeasurementsTNCuda.hpp | 45 +++++++++ 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt index 49630b536f..39250497d8 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt @@ -9,7 +9,7 @@ message(${LOGO}) project(${PL_BACKEND} DESCRIPTION "Lightning-Tensor MPS bindings for PennyLane. Backed by NVIDIA cuQuantum SDK." - LANGUAGES CXX C + LANGUAGES CXX C CUDA ) include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pllgpu.cmake") @@ -17,7 +17,7 @@ include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pltensortncuda.cmake") findCUDATK(lightning_external_libs) findCutensornet(lightning_external_libs) -set(LTENSOR_MPS_FILES MPSTNCuda.cpp CACHE INTERNAL "" FORCE) +set(LTENSOR_MPS_FILES MPSTNCuda.cpp cuda_kernels_ltensor.cu CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND} STATIC ${LTENSOR_MPS_FILES}) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu new file mode 100644 index 0000000000..93b66694bc --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu @@ -0,0 +1,96 @@ +// Copyright 2024 Xanadu Quantum Technologies Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** + * @file cuda_kernels_ltensor.cu + */ +#include + +#include "cuError.hpp" +#include "cuda_helpers.hpp" + +namespace Pennylane::LightningTensor::TNCuda { +/** + * @brief Explicitly get the probability of given state tensor data on GPU + * device. + * + * @param state Complex data pointer of state tensor on device. + * @param probs The probability result on device. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ +void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id); +void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id); + +/** + * @brief The CUDA kernel that calculate the probability from a given state + * tensor data on GPU device. + * + * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). + * @tparam PrecisionT Floating data type. + * + * @param state Complex data pointer of state tensor on device. + * @param probs The probability result on device. + * @param data_size The length of state tensor on device. + */ +template +__global__ void getProbsKernel(GPUDataT *state, PrecisionT *probs, + const int data_size) { + const unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; + + if (i < data_size) { + PrecisionT real = state[i].x; + PrecisionT imag = state[i].y; + probs[i] = real * real + imag * imag; + } +} + +/** + * @brief The CUDA kernel call wrapper. + * + * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). + * @tparam PrecisionT Floating data type. + * + * @param state Complex data pointer of state tensor on device. + * @param probs The probability result on device. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ +template +void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, + std::size_t thread_per_block, cudaStream_t stream_id) { + auto dv = std::div(data_size, thread_per_block); + std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); + const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); + dim3 blockSize(thread_per_block, 1, 1); + dim3 gridSize(block_per_grid, 1); + + getProbsKernel + <<>>(state, probs, data_size); + PL_CUDA_IS_SUCCESS(cudaGetLastError()); +} + +// Definitions +void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id) { + getProbs_CUDA_call(state, probs, data_size, + thread_per_block, stream_id); +} + +void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, + const std::size_t thread_per_block, cudaStream_t stream_id) { + getProbs_CUDA_call(state, probs, data_size, + thread_per_block, stream_id); +} +} // namespace Pennylane::LightningTensor::TNCuda \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index fed9f489b0..4700ac7104 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -21,6 +21,7 @@ #pragma once #include +#include #include #include @@ -39,6 +40,13 @@ using namespace Pennylane::LightningTensor::TNCuda::Util; /// @endcond namespace Pennylane::LightningTensor::TNCuda::Measures { +extern void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, + const std::size_t thread_per_block, + cudaStream_t stream_id); +extern void getProbs_CUDA(cuDoubleComplex *state, double *probs, + const int data_size, + const std::size_t thread_per_block, + cudaStream_t stream_id); /** * @brief ObservablesTNCuda's Measurement Class. * @@ -51,6 +59,7 @@ template class MeasurementsTNCuda { private: using PrecisionT = typename TensorNetT::PrecisionT; using ComplexT = typename TensorNetT::ComplexT; + using CFP_t = typename TensorNetT::CFP_t; const TensorNetT &tensor_network_; @@ -58,6 +67,42 @@ template class MeasurementsTNCuda { explicit MeasurementsTNCuda(const TensorNetT &tensor_network) : tensor_network_(tensor_network){}; + /** + * @brief Probabilities for a subset of the full system. + * + * @param wires Wires will restrict probabilities to a subset + * of the full system. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Floating point std::vector with probabilities. + */ + template + auto probs(const std::vector &wires, + const int32_t numHyperSamples = 1) -> std::vector { + const std::size_t length = std::size_t{1} << wires.size(); + + std::vector h_res(length); + + DataBuffer d_output_tensor( + length, tensor_network_.getDevTag(), true); + + DataBuffer d_output_probs( + length, tensor_network_.getDevTag(), true); + + tensor_network_.get_state_tensor(d_output_tensor.getData(), + d_output_tensor.getLength(), wires, + numHyperSamples); + + getProbs_CUDA(d_output_tensor.getData(), d_output_probs.getData(), + length, static_cast(thread_per_block), + tensor_network_.getDevTag().getStreamID()); + + d_output_probs.CopyGpuDataToHost(h_res.data(), h_res.size()); + + return h_res; + } + /** * @brief Calculate var value for a general ObservableTNCuda Observable. * From cdba823907b0a1a70ee48123392a2b7f84b8592e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 21:47:16 +0000 Subject: [PATCH 081/227] limit scope of the implementation --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index e607145822..d7c1a189cb 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -330,20 +330,15 @@ class TNCudaBase : public TensornetBase { const std::size_t tensor_data_size, const std::vector &wires, const int32_t numHyperSamples = 1) { + // NOTE: this is a solution to get the full state tensor + // TODO: project_modes and projectedModeValues are to be updated for + // prob() support. auto stateModes = cuUtil::NormalizeCastIndices( wires, BaseType::getNumQubits()); - std::vector projected_modes; + std::vector projected_modes{}; - for (std::size_t idx = 0; idx < BaseType::getNumQubits(); idx++) { - auto it = std::find(stateModes.begin(), stateModes.end(), - static_cast(idx)); - if (it == stateModes.end()) { - projected_modes.emplace_back(static_cast(idx)); - } - } - - std::vector projectedModeValues(projected_modes.size(), 1); + std::vector projectedModeValues{}; cutensornetStateAccessor_t accessor; PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateAccessor( From f660c9af626d29f355fe3e2aa2d71ad29bc4bd2c Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 1 Aug 2024 21:50:51 +0000 Subject: [PATCH 082/227] update docs --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index d7c1a189cb..733e6d6d78 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -309,6 +309,15 @@ class TNCudaBase : public TensornetBase { return get_state_tensor(wires, numHyperSamples); } + /** + * @brief Get full state tensor + * + * @param wires Wires to get the state tensor for. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Full state tensor on the host memory + */ auto get_state_tensor(const std::vector &wires, const int32_t numHyperSamples = 1) -> std::vector { @@ -326,6 +335,17 @@ class TNCudaBase : public TensornetBase { return h_res; } + /** + * @brief Get full state tensor + * + * @param tensor_data Pointer to the device memory for state tensor data. + * @param tensor_data_size Size of the state tensor data. + * @param wires Wires to get the state tensor for. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Full state tensor on the host memory + */ void get_state_tensor(CFP_t *tensor_data, const std::size_t tensor_data_size, const std::vector &wires, From b4c195e55933042e7425d9bd0b1168403f38ad73 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 13:28:34 +0000 Subject: [PATCH 083/227] add changelog entry --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 1754767b4d..d047f7eb8e 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add `qml.state()` support to `lightning.tensor`. + [(#827)](https://github.com/PennyLaneAI/pennylane-lightning/pull/827) + * Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs**2` and this implementation scales `O(num_obs**2)`. [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) From 2d404773c43e427d7ddccf5222973840f4ebfa7c Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 13:29:40 +0000 Subject: [PATCH 084/227] remove _tensor_network from lighntningtensor device --- .../lightning_tensor/lightning_tensor.py | 14 ----- tests/test_comparison.py | 54 ++++++++----------- 2 files changed, 21 insertions(+), 47 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 9b3944e081..2029b20faa 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -297,8 +297,6 @@ def __init__( if not isinstance(self._max_bond_dim, int) or self._max_bond_dim < 1: raise ValueError("The maximum bond dimension must be an integer greater than 0.") - self._tensor_network = None - @property def name(self): """The name of the device.""" @@ -326,18 +324,6 @@ def c_dtype(self): def _tensornet(self): """Return the tensornet object.""" - # Ensure that the tensor network is only created and calculated once, which enable access to qml.state(). - # parameter-shift/finite-diff calculation will return a new LightningTensorNet object. - if self._tensor_network is None: - self._tensor_network = LightningTensorNet( - self._num_wires, - self._method, - self._c_dtype, - self._max_bond_dim, - self._cutoff, - self._cutoff_mode, - ) - return self._tensor_network return LightningTensorNet( self._num_wires, self._method, diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 504e23aed9..47d16d7458 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -102,15 +102,15 @@ def circuit(measurement): assert np.allclose(lightning_state, default_state) assert os.getenv("OMP_NUM_THREADS") == str(num_threads) + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor device dose not direct access to state", + ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 2)) @pytest.mark.parametrize("wires", [2]) @pytest.mark.parametrize( "lightning_dev_version", - ( - [lightning_backend_dev, lightning_backend_batch_obs_dev] - if device_name != "lightning.tensor" - else [lightning_backend_dev] - ), + ([lightning_backend_dev, lightning_backend_batch_obs_dev]), ) @pytest.mark.parametrize("num_threads", [1, 2]) def test_two_qubit_circuit( @@ -147,22 +147,18 @@ def circuit(measurement): default_state = default(qml.state) # pylint: disable=protected-access - if device_name == "lightning.tensor": - lightning_state = dev_l._tensor_network.state - assert np.allclose(lightning_state, default_state) - else: - lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state - assert np.allclose(lightning_state, default_state) + lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state + assert np.allclose(lightning_state, default_state) + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor device dose not direct access to state", + ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 3)) @pytest.mark.parametrize("wires", [3]) @pytest.mark.parametrize( "lightning_dev_version", - ( - [lightning_backend_dev, lightning_backend_batch_obs_dev] - if device_name != "lightning.tensor" - else [lightning_backend_dev] - ), + ([lightning_backend_dev, lightning_backend_batch_obs_dev]), ) @pytest.mark.parametrize("num_threads", [1, 2]) def test_three_qubit_circuit( @@ -207,22 +203,18 @@ def circuit(measurement): default_state = default(qml.state) # pylint: disable=protected-access - if device_name == "lightning.tensor": - lightning_state = dev_l._tensor_network.state - assert np.allclose(lightning_state, default_state) - else: - lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state - assert np.allclose(lightning_state, default_state) + lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state + assert np.allclose(lightning_state, default_state) + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor device dose not direct access to state", + ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 4)) @pytest.mark.parametrize("wires", [4]) @pytest.mark.parametrize( "lightning_dev_version", - ( - [lightning_backend_dev, lightning_backend_batch_obs_dev] - if device_name != "lightning.tensor" - else [lightning_backend_dev] - ), + ([lightning_backend_dev, lightning_backend_batch_obs_dev]), ) @pytest.mark.parametrize("num_threads", [1, 2]) def test_four_qubit_circuit( @@ -272,12 +264,8 @@ def circuit(measurement): default_state = default(qml.state) # pylint: disable=protected-access - if device_name == "lightning.tensor": - lightning_state = dev_l._tensor_network.state - assert np.allclose(lightning_state, default_state) - else: - lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state - assert np.allclose(lightning_state, default_state) + lightning_state = dev_l._statevector.state if dev_l._new_API else dev_l.state + assert np.allclose(lightning_state, default_state) @pytest.mark.skipif( device_name == "lightning.tensor", From aa1c72cb3530c12cd36005f8a40c45ba250e3f74 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 14:01:31 +0000 Subject: [PATCH 085/227] update `state_diagonalizing_gates` --- .../lightning_tensor/_measurements.py | 13 +++++++++---- tests/lightning_tensor/test_gates_and_expval.py | 5 +---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 16565917db..5addc7188f 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -28,6 +28,7 @@ from pennylane.measurements import ExpectationMP, MeasurementProcess, StateMeasurement, VarianceMP from pennylane.tape import QuantumScript from pennylane.typing import Result, TensorLike +from pennylane.wires import Wires from pennylane_lightning.core._serialize import QuantumScriptSerializer @@ -71,7 +72,13 @@ def state_diagonalizing_gates(self, measurementprocess: StateMeasurement) -> Ten Returns: TensorLike: the result of the measurement """ - return self._tensornet.state + diagonalizing_gates = measurementprocess.diagonalizing_gates() + self._tensornet.apply_operations(diagonalizing_gates) + state_array = self._tensornet.state + wires = Wires(range(self._tensornet.num_wires)) + result = measurementprocess.process_state(state_array, wires) + self._tensornet.apply_operations([qml.adjoint(g) for g in reversed(diagonalizing_gates)]) + return result # pylint: disable=protected-access def expval(self, measurementprocess: MeasurementProcess): @@ -139,9 +146,7 @@ def get_measurement_function( if measurementprocess.obs is None: return self.state_diagonalizing_gates - raise NotImplementedError( - "Does not support current measurement. Only ExpectationMP measurements are supported." - ) + raise NotImplementedError def measurement(self, measurementprocess: MeasurementProcess) -> TensorLike: """Apply a measurement process to a tensor network. diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index ee60dffba9..5eaaa00bb4 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -308,10 +308,7 @@ def test_measurement_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs) m = LightningTensorMeasurements(tensornet) - with pytest.raises( - NotImplementedError, - match="Does not support current measurement. Only ExpectationMP measurements are supported.", - ): + with pytest.raises(NotImplementedError): m.measure_tensor_network(tape) From d34f4f10cbbaf81111fc5970ea3a3034fc4e9c98 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 2 Aug 2024 15:25:45 +0000 Subject: [PATCH 086/227] Auto update version from '0.38.0-dev23' to '0.38.0-dev24' --- 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 2231d11aec..e195d6231f 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.38.0-dev23" +__version__ = "0.38.0-dev24" From 96af3aa8af2814278b8c155340ce2bd6888e4f49 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 17:53:39 +0000 Subject: [PATCH 087/227] initial commit --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 4 ++- .../lightning_tensor/tncuda/TNCudaBase.hpp | 26 ++++++++++++++++++- .../lightning_tensor/lightning_tensor.py | 22 +++++++--------- tests/test_expval.py | 6 +---- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index e6754f92f2..7244bf7220 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -156,10 +156,12 @@ class MPSTNCuda final : public TNCudaBase> { } /** - * @brief Set current quantum state as zero state. + * @brief Set current quantum state as zero state and clear the tensor + * network graph. */ void reset() { const std::vector zeroState(BaseType::getNumQubits(), 0); + BaseType::reset_graph(); setBasisState(zeroState); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index ea21984a39..42aa3c638b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -128,7 +128,31 @@ class TNCudaBase : public TensornetBase { } ~TNCudaBase() { - PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyState(quantumState_)); + if (quantumState_ != nullptr) { + PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyState(quantumState_)); + } + } + + /** + * @brief Reset the quantum state / tensor network graph. + */ + void reset_graph() { + // Clear the existing quantum graph + if (quantumState_ != nullptr) { + PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyState(quantumState_)); + quantumState_ = nullptr; + } + + // Create a new quantum graph + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateState( + /* const cutensornetHandle_t */ handle_.get(), + /* cutensornetStatePurity_t */ purity_, + /* int32_t numStateModes */ + static_cast(BaseType::getNumQubits()), + /* const int64_t *stateModeExtents */ + reinterpret_cast(BaseType::getQubitDims().data()), + /* cudaDataType_t */ typeData_, + /* cutensornetState_t * */ &quantumState_)); } /** diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index bcbda55334..be295f74eb 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -299,6 +299,15 @@ def __init__( if not isinstance(self._max_bond_dim, int) or self._max_bond_dim < 1: raise ValueError("The maximum bond dimension must be an integer greater than 0.") + self._tensor_network = LightningTensorNet( + self._num_wires, + self._method, + self._c_dtype, + self._max_bond_dim, + self._cutoff, + self._cutoff_mode, + ) + @property def name(self): """The name of the device.""" @@ -324,17 +333,6 @@ def c_dtype(self): """Tensor complex data type.""" return self._c_dtype - def _tensornet(self): - """Return the tensornet object.""" - return LightningTensorNet( - self._num_wires, - self._method, - self._c_dtype, - self._max_bond_dim, - self._cutoff, - self._cutoff_mode, - ) - dtype = c_dtype def _setup_execution_config( @@ -412,7 +410,7 @@ def execute( for circuit in circuits: if self._wire_map is not None: [circuit], _ = qml.map_wires(circuit, self._wire_map) - results.append(simulate(circuit, self._tensornet())) + results.append(simulate(circuit, self._tensor_network)) return tuple(results) diff --git a/tests/test_expval.py b/tests/test_expval.py index dfdc2a72d8..273349dec0 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -198,11 +198,7 @@ def circuit(): circ = qml.QNode(circuit, dev) circ_def = qml.QNode(circuit, dev_def) if device_name == "lightning.tensor" and n_wires > 1: - with pytest.raises( - ValueError, - match="The number of Hermitian observables target wires should be 1.", - ): - assert np.allclose(circ(), circ_def(), tol) + pytest.skip("lightning.tensor does not support multi-wire Hermitian observables.") else: assert np.allclose(circ(), circ_def(), tol) From a18130428272605748f87443a8ca414e38625400 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 18:21:53 +0000 Subject: [PATCH 088/227] Revert "TOML files update (#826)" This reverts commit cfc3006415c695aff5237ffbe82510d1d608f781. --- .github/CHANGELOG.md | 5 +---- pennylane_lightning/core/_version.py | 2 +- pennylane_lightning/lightning_gpu/lightning_gpu.toml | 2 -- pennylane_lightning/lightning_kokkos/lightning_kokkos.toml | 2 -- pennylane_lightning/lightning_qubit/lightning_qubit.toml | 3 --- 5 files changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 44cc701137..d047f7eb8e 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -66,9 +66,6 @@ * Add a Catalyst-specific wrapping class for Lightning Kokkos. [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) -* Add `initial_state_prep` option to Catalyst TOML file. - [(#826)](https://github.com/PennyLaneAI/pennylane-lightning/pull/826) - ### Documentation * Updated the README and added citation format for Lightning arxiv preprint. @@ -95,7 +92,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang +Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang --- diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index e195d6231f..2231d11aec 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.38.0-dev24" +__version__ = "0.38.0-dev23" diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.toml b/pennylane_lightning/lightning_gpu/lightning_gpu.toml index 003b248fa4..4e410efbc3 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.toml +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.toml @@ -109,5 +109,3 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true -# Whether the device supports (arbitrary) initial state preparation. -initial_state_prep = true diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml index 0ede05a262..2821507220 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml @@ -112,5 +112,3 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true -# Whether the device supports (arbitrary) initial state preparation. -initial_state_prep = true diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.toml b/pennylane_lightning/lightning_qubit/lightning_qubit.toml index 5656934889..beaca2391d 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.toml +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.toml @@ -107,9 +107,6 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true -# Whether the device supports (arbitrary) initial state preparation. -initial_state_prep = true - [options] mcmc = "_mcmc" From 799bfe24935eea471c7a3884208596e23958b066 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 18:22:59 +0000 Subject: [PATCH 089/227] Revert "initial commit" This reverts commit 96af3aa8af2814278b8c155340ce2bd6888e4f49. --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 4 +-- .../lightning_tensor/tncuda/TNCudaBase.hpp | 26 +------------------ .../lightning_tensor/lightning_tensor.py | 22 +++++++++------- tests/test_expval.py | 6 ++++- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index c70919f539..ff5542c473 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -156,12 +156,10 @@ class MPSTNCuda final : public TNCudaBase> { } /** - * @brief Set current quantum state as zero state and clear the tensor - * network graph. + * @brief Set current quantum state as zero state. */ void reset() { const std::vector zeroState(BaseType::getNumQubits(), 0); - BaseType::reset_graph(); setBasisState(zeroState); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 0b72c1666a..733e6d6d78 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -129,31 +129,7 @@ class TNCudaBase : public TensornetBase { } ~TNCudaBase() { - if (quantumState_ != nullptr) { - PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyState(quantumState_)); - } - } - - /** - * @brief Reset the quantum state / tensor network graph. - */ - void reset_graph() { - // Clear the existing quantum graph - if (quantumState_ != nullptr) { - PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyState(quantumState_)); - quantumState_ = nullptr; - } - - // Create a new quantum graph - PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateState( - /* const cutensornetHandle_t */ handle_.get(), - /* cutensornetStatePurity_t */ purity_, - /* int32_t numStateModes */ - static_cast(BaseType::getNumQubits()), - /* const int64_t *stateModeExtents */ - reinterpret_cast(BaseType::getQubitDims().data()), - /* cudaDataType_t */ typeData_, - /* cutensornetState_t * */ &quantumState_)); + PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyState(quantumState_)); } /** diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index b9824890fd..2029b20faa 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -297,15 +297,6 @@ def __init__( if not isinstance(self._max_bond_dim, int) or self._max_bond_dim < 1: raise ValueError("The maximum bond dimension must be an integer greater than 0.") - self._tensor_network = LightningTensorNet( - self._num_wires, - self._method, - self._c_dtype, - self._max_bond_dim, - self._cutoff, - self._cutoff_mode, - ) - @property def name(self): """The name of the device.""" @@ -331,6 +322,17 @@ def c_dtype(self): """Tensor complex data type.""" return self._c_dtype + def _tensornet(self): + """Return the tensornet object.""" + return LightningTensorNet( + self._num_wires, + self._method, + self._c_dtype, + self._max_bond_dim, + self._cutoff, + self._cutoff_mode, + ) + dtype = c_dtype def _setup_execution_config( @@ -408,7 +410,7 @@ def execute( for circuit in circuits: if self._wire_map is not None: [circuit], _ = qml.map_wires(circuit, self._wire_map) - results.append(simulate(circuit, self._tensor_network)) + results.append(simulate(circuit, self._tensornet())) return tuple(results) diff --git a/tests/test_expval.py b/tests/test_expval.py index 273349dec0..dfdc2a72d8 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -198,7 +198,11 @@ def circuit(): circ = qml.QNode(circuit, dev) circ_def = qml.QNode(circuit, dev_def) if device_name == "lightning.tensor" and n_wires > 1: - pytest.skip("lightning.tensor does not support multi-wire Hermitian observables.") + with pytest.raises( + ValueError, + match="The number of Hermitian observables target wires should be 1.", + ): + assert np.allclose(circ(), circ_def(), tol) else: assert np.allclose(circ(), circ_def(), tol) From b3d076e20b90e5ebf98a2349550c1766fe037bbd Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 2 Aug 2024 18:24:31 +0000 Subject: [PATCH 090/227] Auto update version from '0.38.0-dev23' to '0.38.0-dev25' --- 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 2231d11aec..3961045c01 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.38.0-dev23" +__version__ = "0.38.0-dev25" From 1a1e14f8cac3bee61ad65798f12ca8702ed2cebe Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 19:06:31 +0000 Subject: [PATCH 091/227] turn on more pytests --- tests/new_api/test_device.py | 122 +++++++++++++++++++++++------------ tests/new_api/test_var.py | 6 +- 2 files changed, 82 insertions(+), 46 deletions(-) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 7ecb6fb684..fb3d4fef45 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -187,10 +187,6 @@ def test_invalid_kernel_name(self): _ = LightningDevice(wires=2, shots=1000, mcmc=True, kernel_name="bleh") -@pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support adjoint_observables", -) class TestExecution: """Unit tests for executing quantum tapes on a device""" @@ -217,6 +213,9 @@ def process_and_execute(device, tape): "num_burnin": 0, } + @pytest.mark.skipif( + device_name="lightning.tensor", reason="lightning.tensor does not support rng key" + ) @pytest.mark.parametrize( "config, expected_config", [ @@ -277,6 +276,9 @@ def test_preprocess_correct_config_setup(self, config, expected_config): assert new_config == expected_config + @pytest.mark.skipif( + device_name="lightning.tensor", reason="lightning.tensor does not support adjoint" + ) @pytest.mark.parametrize("adjoint", [True, False]) def test_preprocess(self, adjoint): """Test that the transform program returned by preprocess is correct""" @@ -324,13 +326,19 @@ def test_preprocess(self, adjoint): @pytest.mark.parametrize( "op, is_trainable", - [ - (qml.StatePrep([1 / np.sqrt(2), 1 / np.sqrt(2)], wires=0), False), - (qml.StatePrep(qml.numpy.array([1 / np.sqrt(2), 1 / np.sqrt(2)]), wires=0), True), - (qml.StatePrep(np.array([1, 0]), wires=0), False), - (qml.BasisState([1, 1], wires=[0, 1]), False), - (qml.BasisState(qml.numpy.array([1, 1]), wires=[0, 1]), True), - ], + ( + [ + (qml.StatePrep([1 / np.sqrt(2), 1 / np.sqrt(2)], wires=0), False), + (qml.StatePrep(qml.numpy.array([1 / np.sqrt(2), 1 / np.sqrt(2)]), wires=0), True), + (qml.StatePrep(np.array([1, 0]), wires=0), False), + (qml.BasisState([1, 1], wires=[0, 1]), False), + (qml.BasisState(qml.numpy.array([1, 1]), wires=[0, 1]), True), + ] + if device_name != "lightning.tensor" + else [ + (qml.BasisState([1, 1], wires=[0, 1]), False), + ] + ), ) def test_preprocess_state_prep_first_op_decomposition(self, op, is_trainable): """Test that state prep ops in the beginning of a tape are decomposed with adjoint @@ -383,26 +391,38 @@ def test_preprocess_state_prep_middle_op_decomposition(self, op, decomp_depth): @pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) @pytest.mark.parametrize( "mp", - [ - qml.probs(wires=[1, 2]), - qml.probs(op=qml.Z(2)), - qml.expval(qml.Z(2)), - qml.var(qml.X(2)), - qml.expval(qml.X(0) + qml.Z(0)), - qml.expval(qml.Hamiltonian([-0.5, 1.5], [qml.Y(1), qml.X(1)])), - qml.expval(2.5 * qml.Z(0)), - qml.expval(qml.Z(0) @ qml.X(1)), - qml.expval(qml.operation.Tensor(qml.Z(0), qml.X(1))), - qml.expval( - qml.SparseHamiltonian( - qml.Hamiltonian([-1.0, 1.5], [qml.Z(1), qml.X(1)]).sparse_matrix( - wire_order=[0, 1, 2] - ), - wires=[0, 1, 2], - ) - ), - qml.expval(qml.Projector([1], wires=2)), - ], + ( + [ + qml.probs(wires=[1, 2]), + qml.probs(op=qml.Z(2)), + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.expval(qml.X(0) + qml.Z(0)), + qml.expval(qml.Hamiltonian([-0.5, 1.5], [qml.Y(1), qml.X(1)])), + qml.expval(2.5 * qml.Z(0)), + qml.expval(qml.Z(0) @ qml.X(1)), + qml.expval(qml.operation.Tensor(qml.Z(0), qml.X(1))), + qml.expval( + qml.SparseHamiltonian( + qml.Hamiltonian([-1.0, 1.5], [qml.Z(1), qml.X(1)]).sparse_matrix( + wire_order=[0, 1, 2] + ), + wires=[0, 1, 2], + ) + ), + qml.expval(qml.Projector([1], wires=2)), + ] + if device_name != "lightning.tensor" + else [ + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.expval(qml.X(0) + qml.Z(0)), + qml.expval(qml.Hamiltonian([-0.5, 1.5], [qml.Y(1), qml.X(1)])), + qml.expval(2.5 * qml.Z(0)), + qml.expval(qml.Z(0) @ qml.X(1)), + qml.expval(qml.operation.Tensor(qml.Z(0), qml.X(1))), + ] + ), ) def test_execute_single_measurement(self, theta, phi, mp, dev): """Test that execute returns the correct results with a single measurement.""" @@ -426,21 +446,37 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): @pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) @pytest.mark.parametrize( "mp1", - [ - qml.probs(wires=[1, 2]), - qml.expval(qml.Z(2)), - qml.var(qml.X(2)), - qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), - ], + ( + [ + qml.probs(wires=[1, 2]), + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), + ] + if device_name != "lightning.tensor" + else [ + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), + ] + ), ) @pytest.mark.parametrize( "mp2", - [ - qml.probs(op=qml.X(2)), - qml.expval(qml.Y(2)), - qml.var(qml.Y(2)), - qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), - ], + ( + [ + qml.probs(op=qml.X(2)), + qml.expval(qml.Y(2)), + qml.var(qml.Y(2)), + qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), + ] + if device_name != "lightning.tensor" + else [ + qml.expval(qml.Y(2)), + qml.var(qml.Y(2)), + qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), + ] + ), ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): """Test that execute returns the correct results with multiple measurements.""" diff --git a/tests/new_api/test_var.py b/tests/new_api/test_var.py index 8feb620c82..29b795d9ad 100644 --- a/tests/new_api/test_var.py +++ b/tests/new_api/test_var.py @@ -22,9 +22,6 @@ from conftest import PHI, THETA, VARPHI, LightningDevice, device_name from pennylane.tape import QuantumScript -if device_name == "lightning.tensor": - pytest.skip("lightning.tensor does not support qml.var()", allow_module_level=True) - if not LightningDevice._new_API: pytest.skip("Exclusive tests for new API. Skipping.", allow_module_level=True) @@ -211,6 +208,9 @@ def test_hamiltonian_variance(self, theta, phi, dev): tol = 1e-5 if dev.c_dtype == np.complex64 else 1e-7 assert np.allclose(calculated_val, reference_val, atol=tol, rtol=0) + @pytest.mark.skipif( + device_name == "lightning.tensor", reason="SparseH not supported on lightning.tensor." + ) def test_sparse_hamiltonian_variance(self, theta, phi, dev): """Tests a Hamiltonian.""" From 86e41f0f225d8c26b0da3b0ac707eb773db82da2 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 19:09:36 +0000 Subject: [PATCH 092/227] revert some changes in test_execute.py --- tests/test_execute.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_execute.py b/tests/test_execute.py index 8f5ce2745e..02a6bfa1f6 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -27,7 +27,7 @@ @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not fully support `enable_new_opmath_cm`", + reason="lightning.tensor does not support gates with more than 2 wires, preprocess is required for the following tests", ) @pytest.mark.usefixtures("use_legacy_and_new_opmath") @pytest.mark.parametrize("diff_method", ("param_shift", "finite_diff")) From c21ee4e56b7b56e6cf9b725675aee5fd0f3cbcc3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 19:15:07 +0000 Subject: [PATCH 093/227] revert some removers --- .github/CHANGELOG.md | 5 ++++- pennylane_lightning/lightning_gpu/lightning_gpu.toml | 2 ++ pennylane_lightning/lightning_kokkos/lightning_kokkos.toml | 2 ++ pennylane_lightning/lightning_qubit/lightning_qubit.toml | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index d047f7eb8e..163caab326 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -66,6 +66,9 @@ * Add a Catalyst-specific wrapping class for Lightning Kokkos. [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) +* Add `initial_state_prep` option to Catalyst TOML file. + [(#826)](https://github.com/PennyLaneAI/pennylane-lightning/pull/826) + ### Documentation * Updated the README and added citation format for Lightning arxiv preprint. @@ -92,7 +95,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang +Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang --- diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.toml b/pennylane_lightning/lightning_gpu/lightning_gpu.toml index 4e410efbc3..75c9019f02 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.toml +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.toml @@ -109,3 +109,5 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true \ No newline at end of file diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml index 2821507220..b6ff8fe2f8 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml @@ -112,3 +112,5 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true \ No newline at end of file diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.toml b/pennylane_lightning/lightning_qubit/lightning_qubit.toml index beaca2391d..40abaaeccf 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.toml +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.toml @@ -107,6 +107,9 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true + [options] mcmc = "_mcmc" From d0f8e1660be852ea844ac358c4b8c963f337c157 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 19:18:16 +0000 Subject: [PATCH 094/227] tidy up --- .github/CHANGELOG.md | 2 +- pennylane_lightning/lightning_gpu/lightning_gpu.toml | 4 ++-- pennylane_lightning/lightning_kokkos/lightning_kokkos.toml | 4 ++-- pennylane_lightning/lightning_qubit/lightning_qubit.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 163caab326..44cc701137 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -66,7 +66,7 @@ * Add a Catalyst-specific wrapping class for Lightning Kokkos. [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) -* Add `initial_state_prep` option to Catalyst TOML file. +* Add `initial_state_prep` option to Catalyst TOML file. [(#826)](https://github.com/PennyLaneAI/pennylane-lightning/pull/826) ### Documentation diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.toml b/pennylane_lightning/lightning_gpu/lightning_gpu.toml index 75c9019f02..003b248fa4 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.toml +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.toml @@ -109,5 +109,5 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true -# Whether the device supports (arbitrary) initial state preparation. -initial_state_prep = true \ No newline at end of file +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml index b6ff8fe2f8..0ede05a262 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml @@ -112,5 +112,5 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true -# Whether the device supports (arbitrary) initial state preparation. -initial_state_prep = true \ No newline at end of file +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.toml b/pennylane_lightning/lightning_qubit/lightning_qubit.toml index 40abaaeccf..5656934889 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.toml +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.toml @@ -107,7 +107,7 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true -# Whether the device supports (arbitrary) initial state preparation. +# Whether the device supports (arbitrary) initial state preparation. initial_state_prep = true [options] From 2c8d1da2678536a7457da2d17dc7d3f3a3188c67 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 19:34:17 +0000 Subject: [PATCH 095/227] add memory check --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 5 +++- .../tncuda/tests/Tests_MPSTNCuda.cpp | 24 ++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 733e6d6d78..32eb574dc6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -323,10 +323,13 @@ class TNCudaBase : public TensornetBase { -> std::vector { const std::size_t length = std::size_t{1} << wires.size(); - std::vector h_res(length); + PL_ABORT_IF(length * sizeof(CFP_t) >= getFreeMemorySize(), + "State tensor size exceeds the available GPU memory!"); DataBuffer d_output_tensor(length, getDevTag(), true); + std::vector h_res(length); + get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), wires, numHyperSamples); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index 2ba1dd04b5..2eb361f2cf 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -163,13 +163,12 @@ TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", } TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { - std::size_t num_qubits = 10; - std::size_t maxBondDim = 2; - DevTag dev_tag{0, 0}; - - MPSTNCuda mps_state{num_qubits, maxBondDim, dev_tag}; - SECTION("Get zero state") { + std::size_t num_qubits = 10; + std::size_t maxBondDim = 2; + DevTag dev_tag{0, 0}; + + MPSTNCuda mps_state{num_qubits, maxBondDim, dev_tag}; std::vector> expected_state( std::size_t{1} << num_qubits, std::complex({0.0, 0.0})); @@ -178,4 +177,17 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { CHECK(expected_state == Pennylane::Util::approx(mps_state.getDataVector())); } + + SECTION("Throw error for getDataVector() on device") { + std::size_t num_qubits = 100; + std::size_t maxBondDim = 2; + DevTag dev_tag{0, 0}; + + MPSTNCuda mps_state{num_qubits, maxBondDim, dev_tag}; + + REQUIRE_THROWS_WITH( + mps_state.getDataVector(), + Catch::Matchers::Contains( + "State tensor size exceeds the available GPU memory!")); + } } From 29c1acd2f1b3ce49ec400f9e26cecda0a57f3349 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 20:32:44 +0000 Subject: [PATCH 096/227] Trigger CIs From 708e680c4806be42f524adfc63318f008ad1bf4b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 21:20:38 +0000 Subject: [PATCH 097/227] update pytests --- pennylane_lightning/lightning_tensor/_measurements.py | 2 +- tests/lightning_tensor/test_gates_and_expval.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 67cbb6d2a6..7b68806863 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -146,7 +146,7 @@ def get_measurement_function( if measurementprocess.obs is None: return self.state_diagonalizing_gates - raise NotImplementedError + raise NotImplementedError ("Not supported measurement.") def measurement(self, measurementprocess: MeasurementProcess) -> TensorLike: """Apply a measurement process to a tensor network. diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index 5eaaa00bb4..595e3d0439 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -302,13 +302,13 @@ def test_measurement_shot_not_supported(self): def test_measurement_not_supported(self): """Test error for measure_tensor_network.""" - obs = [qml.sample(wires=0)] + obs = [qml.sample(wires=[0])] tensornet = LightningTensorNet(4, 10) tape = qml.tape.QuantumScript(measurements=obs) m = LightningTensorMeasurements(tensornet) - with pytest.raises(NotImplementedError): + with pytest.raises(NotImplementedError, match="Not supported measurement."): m.measure_tensor_network(tape) From 5d2aae4a3e22857f2c3ba6563b3077d87a46a9c4 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 21:24:10 +0000 Subject: [PATCH 098/227] make format --- pennylane_lightning/lightning_tensor/_measurements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 7b68806863..8229a36148 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -146,7 +146,7 @@ def get_measurement_function( if measurementprocess.obs is None: return self.state_diagonalizing_gates - raise NotImplementedError ("Not supported measurement.") + raise NotImplementedError("Not supported measurement.") def measurement(self, measurementprocess: MeasurementProcess) -> TensorLike: """Apply a measurement process to a tensor network. From 31d1e35033da2131a251059e8d68bcb87651393d Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 2 Aug 2024 21:26:18 +0000 Subject: [PATCH 099/227] Auto update version from '0.38.0-dev25' to '0.38.0-dev26' --- 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 3961045c01..444de99a58 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.38.0-dev25" +__version__ = "0.38.0-dev26" From ab04912cbfe7a2e47923bf2186aeae31182bc41e Mon Sep 17 00:00:00 2001 From: Lee James O'Riordan Date: Fri, 2 Aug 2024 17:14:53 -0400 Subject: [PATCH 100/227] Fix sync issues with calls to CUSV APIs on aarch64 (#823) Please complete the following checklist when submitting a PR: - [x] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [x] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [x] Ensure that the test suite passes, by running `make test`. - [x] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [x] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** Fixes the known sync issues on aarch64 + GraceHopper when using custatevec API calls. **Description of the Change:** Adds stream sync to all CUSV async API calls. **Benefits:** Fixes #793 **Possible Drawbacks:** Potential sync point may introduce (minimal) overhead for smaller problems. **Related GitHub Issues:** --------- Co-authored-by: Lee J. O'Riordan Co-authored-by: ringo-but-quantum Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- .github/CHANGELOG.md | 6 ++++++ .github/workflows/tests_lgpumpi_cpp.yml | 3 ++- .github/workflows/tests_lgpumpi_python.yml | 2 +- README.rst | 4 ++-- cmake/support_pllgpu.cmake | 4 ++++ pennylane_lightning/core/_version.py | 2 +- .../lightning_gpu/StateVectorCudaManaged.hpp | 8 ++++++++ .../measurements/MeasurementsGPU.hpp | 18 +++++++++++++++++- 8 files changed, 41 insertions(+), 6 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 44cc701137..1e6c75a5bd 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -76,6 +76,12 @@ ### Bug fixes +* Fix cuQuantum SDK path pass-though in CMake. + [(#831)](https://github.com/PennyLaneAI/pennylane-lightning/pull/831) + +* Fix CUDA sync issues on aarch64+GraceHopper. + [(#823)](https://github.com/PennyLaneAI/pennylane-lightning/pull/823) + * Check for the number of wires for Hermitian observables in Lightning-Tensor. Only 1-wire Hermitian observables are supported as of `cuTensorNet-v24.03.0`. [(#806)](https://github.com/PennyLaneAI/pennylane-lightning/pull/806) diff --git a/.github/workflows/tests_lgpumpi_cpp.yml b/.github/workflows/tests_lgpumpi_cpp.yml index 58c86ce22c..fdcd17c122 100644 --- a/.github/workflows/tests_lgpumpi_cpp.yml +++ b/.github/workflows/tests_lgpumpi_cpp.yml @@ -123,7 +123,7 @@ jobs: - name: Build and run unit tests run: | source /etc/profile.d/modules.sh && module use /opt/modules/ && module load ${{ matrix.mpilib }}/cuda-${{ matrix.cuda_version_maj }}.${{ matrix.cuda_version_min }} - export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") cmake . -BBuild \ -DPL_BACKEND=lightning_gpu \ -DENABLE_PYTHON=OFF \ @@ -134,6 +134,7 @@ jobs: -DCMAKE_CXX_COMPILER=mpicxx \ -DCMAKE_CUDA_COMPILER=$(which nvcc) \ -DCMAKE_CUDA_ARCHITECTURES="86" \ + -DCUQUANTUM_SDK=${CUQUANTUM_SDK} \ -DPython_EXECUTABLE:FILE="${{ steps.python_path.outputs.python }}" \ -G Ninja cmake --build ./Build diff --git a/.github/workflows/tests_lgpumpi_python.yml b/.github/workflows/tests_lgpumpi_python.yml index 705ae79540..9a27030a07 100644 --- a/.github/workflows/tests_lgpumpi_python.yml +++ b/.github/workflows/tests_lgpumpi_python.yml @@ -129,7 +129,7 @@ jobs: - name: Build and install package env: - CUQUANTUM_SDK: $(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + CUQUANTUM_SDK: $(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") run: | source /etc/profile.d/modules.sh && module use /opt/modules/ && module load ${{ matrix.mpilib }}/cuda-${{ matrix.cuda_version_maj }}.${{ matrix.cuda_version_min }} CMAKE_ARGS="-DCMAKE_C_COMPILER=mpicc -DCMAKE_CXX_COMPILER=mpicxx -DENABLE_MPI=ON -DCMAKE_CUDA_COMPILER=$(which nvcc) -DCMAKE_CUDA_ARCHITECTURES=${{ env.CI_CUDA_ARCH }} -DPython_EXECUTABLE=${{ steps.python_path.outputs.python }}" \ diff --git a/README.rst b/README.rst index ea8ba722a4..3f9b6b19f6 100644 --- a/README.rst +++ b/README.rst @@ -249,7 +249,7 @@ Then the `cuStateVec`_ library can be installed and set a ``CUQUANTUM_SDK`` envi .. code-block:: console python -m pip install wheel custatevec-cu12 - export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") The Lightning-GPU can then be installed with ``pip``: @@ -386,7 +386,7 @@ Then the `cutensornet`_ library can be installed and set a ``CUQUANTUM_SDK`` env .. code-block:: console pip install cutensornet-cu12 - export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") The Lightning-Tensor can then be installed with ``pip``: diff --git a/cmake/support_pllgpu.cmake b/cmake/support_pllgpu.cmake index 490e02c075..3822040b23 100644 --- a/cmake/support_pllgpu.cmake +++ b/cmake/support_pllgpu.cmake @@ -47,6 +47,7 @@ endmacro() # Macro to aid in finding cuStateVec lib macro(findCustatevec external_libs) + set(CUQUANTUM_ENV "$ENV{CUQUANTUM_SDK}") find_library(CUSTATEVEC_LIB NAMES libcustatevec.so.1 custatevec.so.1 HINTS /usr/lib @@ -58,6 +59,8 @@ macro(findCustatevec external_libs) lib64 ${CUQUANTUM_SDK}/lib ${CUQUANTUM_SDK}/lib64 + ${CUQUANTUM_ENV}/lib + ${CUQUANTUM_ENV}/lib64 ${CUDAToolkit_LIBRARY_DIR} ${CUDA_TOOLKIT_ROOT_DIR}/lib ${CUDA_TOOLKIT_ROOT_DIR}/lib64 @@ -74,6 +77,7 @@ macro(findCustatevec external_libs) /opt/cuda include ${CUQUANTUM_SDK}/include + ${CUQUANTUM_ENV}/include ${CUDAToolkit_INCLUDE_DIRS} ${CUDA_TOOLKIT_ROOT_DIR}/include ${Python_SITELIB}/cuquantum/include diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 444de99a58..3961045c01 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.38.0-dev26" +__version__ = "0.38.0-dev25" diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp index 153dd6a782..e7bcadcb18 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp @@ -1359,6 +1359,8 @@ class StateVectorCudaManaged /* const int32_t* */ ctrlsInt.data(), /* const int32_t* */ nullptr, /* const uint32_t */ ctrls.size())); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + BaseType::getDataBuffer().getDevTag().getStreamID())); } /** @@ -1419,6 +1421,9 @@ class StateVectorCudaManaged /* custatevecComputeType_t */ compute_type, /* std::size_t* */ &extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + BaseType::getDataBuffer().getDevTag().getStreamID())); + // allocate external workspace if necessary // LCOV_EXCL_START if (extraWorkspaceSizeInBytes > 0) { @@ -1445,6 +1450,9 @@ class StateVectorCudaManaged /* custatevecComputeType_t */ compute_type, /* void* */ extraWorkspace, /* std::size_t */ extraWorkspaceSizeInBytes)); + + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + BaseType::getDataBuffer().getDevTag().getStreamID())); // LCOV_EXCL_START if (extraWorkspaceSizeInBytes) PL_CUDA_IS_SUCCESS(cudaFree(extraWorkspace)); 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 41045821aa..a229425175 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -135,6 +135,8 @@ class Measurements final /* const int32_t* */ maskBitString, /* const int32_t* */ maskOrdering, /* const uint32_t */ maskLen)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); if constexpr (std::is_same_v || std::is_same_v) { @@ -252,6 +254,8 @@ class Measurements final this->_statevector.getCusvHandle(), this->_statevector.getData(), data_type, num_qubits, &sampler, num_samples, &extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // allocate external workspace if necessary if (extraWorkspaceSizeInBytes > 0) @@ -262,12 +266,16 @@ class Measurements final PL_CUSTATEVEC_IS_SUCCESS(custatevecSamplerPreprocess( this->_statevector.getCusvHandle(), sampler, extraWorkspace, extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // sample bit strings PL_CUSTATEVEC_IS_SUCCESS(custatevecSamplerSample( this->_statevector.getCusvHandle(), sampler, bitStrings.data(), bitOrdering.data(), bitStringLen, rand_nums.data(), num_samples, CUSTATEVEC_SAMPLER_OUTPUT_ASCENDING_ORDER)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // destroy descriptor and handle PL_CUSTATEVEC_IS_SUCCESS(custatevecSamplerDestroy(sampler)); @@ -497,6 +505,9 @@ class Measurements final const_cast(basisBits_ptr.data()), /* const uint32_t */ n_basisBits.data())); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); + std::complex result{0, 0}; if constexpr (std::is_same_v) { @@ -804,6 +815,8 @@ class Measurements final /* const uint32_t */ tgtsInt.size(), /* custatevecComputeType_t */ compute_type, /* std::size_t* */ &extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // LCOV_EXCL_START if (extraWorkspaceSizeInBytes > 0) { @@ -832,6 +845,9 @@ class Measurements final /* void* */ extraWorkspace, /* std::size_t */ extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); + // LCOV_EXCL_START if (extraWorkspaceSizeInBytes) PL_CUDA_IS_SUCCESS(cudaFree(extraWorkspace)); @@ -840,4 +856,4 @@ class Measurements final return static_cast(expect.x); } }; // class Measurements -} // namespace Pennylane::LightningGPU::Measures \ No newline at end of file +} // namespace Pennylane::LightningGPU::Measures From daeb0e4d3e75dbf1798ce60a235cfb5d02c63bcd Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 2 Aug 2024 21:28:11 +0000 Subject: [PATCH 101/227] Auto update version from '0.38.0-dev25' to '0.38.0-dev26' --- 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 3961045c01..444de99a58 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.38.0-dev25" +__version__ = "0.38.0-dev26" From ba4c216771a087d329d3e6e8c95cadaf1a52d0c4 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 2 Aug 2024 21:30:12 +0000 Subject: [PATCH 102/227] Auto update version from '0.38.0-dev25' to '0.38.0-dev26' --- 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 92e91f6a15..401de26541 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.38.0-dev25" \ No newline at end of file +__version__ = "0.38.0-dev26" \ No newline at end of file From 5f84ab697096935a62b30373a29defc3970598fe Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 2 Aug 2024 21:31:26 +0000 Subject: [PATCH 103/227] tidy up code --- 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 401de26541..444de99a58 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.38.0-dev26" \ No newline at end of file +__version__ = "0.38.0-dev26" From 48e7e37a372a9caeb2733579aee6baf3746a310a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 13:51:03 +0000 Subject: [PATCH 104/227] add C++ unit tests --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- .../tncuda/cuda_kernels_ltensor.cu | 4 +- .../tncuda/measurements/tests/CMakeLists.txt | 3 +- .../tests/Test_MPSTNCuda_Measure.cpp | 71 +++++++++++++++++++ 4 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index e607145822..8aeae44572 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -329,7 +329,7 @@ class TNCudaBase : public TensornetBase { void get_state_tensor(CFP_t *tensor_data, const std::size_t tensor_data_size, const std::vector &wires, - const int32_t numHyperSamples = 1) { + const int32_t numHyperSamples = 1) const { auto stateModes = cuUtil::NormalizeCastIndices( wires, BaseType::getNumQubits()); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu index 93b66694bc..deb308dc5a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu @@ -16,7 +16,7 @@ #include "cuError.hpp" #include "cuda_helpers.hpp" -namespace Pennylane::LightningTensor::TNCuda { +namespace Pennylane::LightningTensor::TNCuda::Measures { /** * @brief Explicitly get the probability of given state tensor data on GPU * device. @@ -93,4 +93,4 @@ void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, getProbs_CUDA_call(state, probs, data_size, thread_per_block, stream_id); } -} // namespace Pennylane::LightningTensor::TNCuda \ No newline at end of file +} // namespace Pennylane::LightningTensor::TNCuda::Measures \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt index 9ed838c230..e18e336449 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/CMakeLists.txt @@ -31,7 +31,8 @@ target_sources(${PL_BACKEND}_measurements_tests INTERFACE runner_${PL_BACKEND}_m # Define targets ################################################################################ set(TEST_SOURCES Test_MPSTNCuda_Expval.cpp - Test_MPSTNCuda_Var.cpp) + Test_MPSTNCuda_Var.cpp + Test_MPSTNCuda_Measure.cpp) add_executable(${PL_BACKEND}_measurements_test_runner ${TEST_SOURCES}) target_link_libraries(${PL_BACKEND}_measurements_test_runner PRIVATE ${PL_BACKEND}_measurements_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp new file mode 100644 index 0000000000..3585ff9b71 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp @@ -0,0 +1,71 @@ +// Copyright 2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "MPSTNCuda.hpp" +#include "MeasurementsTNCuda.hpp" +#include "TNCudaGateCache.hpp" +#include "cuda_helpers.hpp" + +/// @cond DEV +namespace { +using namespace Pennylane::LightningTensor::TNCuda::Measures; +using namespace Pennylane::LightningTensor::TNCuda::Observables; +using namespace Pennylane::LightningTensor::TNCuda; +} // namespace +/// @endcond + +TEMPLATE_TEST_CASE("Probabilities", "[Measures]", float, double) { + using TensorNetT = MPSTNCuda; + // Probabilities calculated with Pennylane default.qubit: + std::vector, std::vector>> + input = { + {{2, 1, 0}, + {7.67899385e-01, 9.97094446e-02, 1.54593908e-02, 2.00735578e-03, + 9.97094446e-02, 1.29469740e-02, 2.00735578e-03, 2.60649160e-04}}}; + + // Defining the State Vector that will be measured. + std::size_t bondDim = GENERATE(2, 3, 4, 5); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RY"}, {"RX"}, {"RY"}, {"RX"}, {"RY"}}, + {{0}, {0}, {1}, {1}, {2}, {2}}, + {{false}, {false}, {false}, {false}, {false}, {false}}, + {{0.5}, {0.5}, {0.2}, {0.2}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); + + auto measure = MeasurementsTNCuda(mps_state); + + SECTION("Looping over different wire configurations:") { + for (const auto &term : input) { + auto probabilities = measure.probs(term.first); + REQUIRE_THAT(term.second, + Catch::Approx(probabilities).margin(1e-6)); + } + } +} \ No newline at end of file From 1a6a927e61dcd98542ab935bff3b6dd54aa61f2b Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 5 Aug 2024 13:51:57 +0000 Subject: [PATCH 105/227] Auto update version from '0.38.0-dev22' to '0.38.0-dev26' --- 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 69ef0e05e7..444de99a58 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.38.0-dev22" +__version__ = "0.38.0-dev26" From f2c9a4b00d62381a7f2934eac0d1212de780338d Mon Sep 17 00:00:00 2001 From: Pietropaolo Frisoni Date: Fri, 2 Aug 2024 09:02:15 -0400 Subject: [PATCH 106/227] Adding semantic-version to workflow reqs (#835) This PR should fix [this test](https://github.com/PennyLaneAI/pennylane-lightning/actions/runs/10208461253/job/28245011292) in the plugin-test-matrix. The latest PL version does not use `semantic-version`, but the stable version still does, so we add such a package to the workflow requirements. --------- Co-authored-by: ringo-but-quantum --- .github/workflows/tests_lqcpu_python.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests_lqcpu_python.yml b/.github/workflows/tests_lqcpu_python.yml index d4cdc35f08..80a9827f74 100644 --- a/.github/workflows/tests_lqcpu_python.yml +++ b/.github/workflows/tests_lqcpu_python.yml @@ -150,6 +150,7 @@ jobs: mv ${{ github.workspace }}/wheel_${{ matrix.pl_backend }}-${{ matrix.blas }}.whl ${{ github.workspace }}/$WHEEL_NAME python -m pip install -r requirements-dev.txt python -m pip install openfermionpyscf + python -m pip install semantic-version python -m pip install ${{ github.workspace }}/$WHEEL_NAME --no-deps --force-reinstall - name: Checkout PennyLane for release build From eca7f286484bd3cded7224443aded714a6c46278 Mon Sep 17 00:00:00 2001 From: Shuli Shu <31480676+multiphaseCFD@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:03:13 -0400 Subject: [PATCH 107/227] Add var support to LTensor (#804) Please complete the following checklist when submitting a PR: - [x] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [ ] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [ ] Ensure that the test suite passes, by running `make test`. - [x] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [x] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** [SC-65783] **Description of the Change:** **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** --------- Co-authored-by: ringo-but-quantum --- .../tncuda/observables/ObservablesTNCudaOperator.hpp | 6 +++--- pennylane_lightning/lightning_tensor/_measurements.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 92ee85433b..62aabc360c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -471,10 +471,10 @@ template class ObservableTNCudaOperator { const bool var_cal = false) : tensor_network_{tensor_network}, numObsTerms_(obs.getNumTensors().size()), var_cal_{var_cal} { - if (!var_cal) { - initHelper_expval_(tensor_network, obs); - } else { + if (var_cal) { initHelper_var_(tensor_network, obs); + } else { + initHelper_expval_(tensor_network, obs); } PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateNetworkOperator( diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 16565917db..ef9cc65eb1 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -98,7 +98,7 @@ def expval(self, measurementprocess: MeasurementProcess): def var(self, measurementprocess: MeasurementProcess): """Variance of the supplied observable contained in the MeasurementProcess. Note that the variance is calculated as - **2. The current implementation only supports single-wire observables. - 2 and 2+-wires observables, projector and sparse-hamiltonian are not supported. + Observables with more than 1 wire, projector and sparse-hamiltonian are not supported. Args: measurementprocess (StateMeasurement): measurement to apply to the state From b72fd22c2c13193ad23b151c21356d013fb1f409 Mon Sep 17 00:00:00 2001 From: erick-xanadu <110487834+erick-xanadu@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:43:05 -0400 Subject: [PATCH 108/227] TOML files update (#826) **Context:** We would like Catalyst to optimize the first instance of `qml.StatePrep` by just setting the state vector in PennyLane lightning. **Description of the Change:** To achieve this, we set a flag in the TOML files where it denotes whether the value for the flag `skip_initial_state_prep` used during decomposition. This flag is already in PennyLane and will skip the initial state preparation. There are other ways to achieve this but this is the least invasive way to do so. Some other alternatives that were discussed: 1. Adding StatePrep to the list of supported operations: this is not a good idea as it would lead StatePrep to not be decomposed ever. 2. Creating a new operation and map StatePrep directly into this new operation only in the context of Catalyst. This would lead to setting this new `qml` Operation in the list of supported operations on the device, even though it would never be seen except when using with Catalyst. The way this was achieved was not to create a new `qml` Operation, only an JAXPR/MLIR operation and bind `StatePrep` to this JAXPR operation and lower it through MLIR. So, no new `qml` operations. **Benefits:** Optimization **Possible Drawbacks:** More flags. No one likes flags. **Related GitHub Issues:** Will be followed by this https://github.com/PennyLaneAI/catalyst/pull/955 pull request in Catalyst. [sc-69069] --------- Co-authored-by: ringo-but-quantum Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- .github/CHANGELOG.md | 5 ++++- pennylane_lightning/lightning_gpu/lightning_gpu.toml | 2 ++ pennylane_lightning/lightning_kokkos/lightning_kokkos.toml | 2 ++ pennylane_lightning/lightning_qubit/lightning_qubit.toml | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 1754767b4d..4d53bf6369 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -63,6 +63,9 @@ * Add a Catalyst-specific wrapping class for Lightning Kokkos. [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) +* Add `initial_state_prep` option to Catalyst TOML file. + [(#826)](https://github.com/PennyLaneAI/pennylane-lightning/pull/826) + ### Documentation * Updated the README and added citation format for Lightning arxiv preprint. @@ -89,7 +92,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang +Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang --- diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.toml b/pennylane_lightning/lightning_gpu/lightning_gpu.toml index 4e410efbc3..003b248fa4 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.toml +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.toml @@ -109,3 +109,5 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml index 2821507220..0ede05a262 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml @@ -112,3 +112,5 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.toml b/pennylane_lightning/lightning_qubit/lightning_qubit.toml index beaca2391d..5656934889 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.toml +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.toml @@ -107,6 +107,9 @@ dynamic_qubit_management = false # in a single execution non_commuting_observables = true +# Whether the device supports (arbitrary) initial state preparation. +initial_state_prep = true + [options] mcmc = "_mcmc" From 044ece872baea5766b94af2d9a902771bc2f2a8f Mon Sep 17 00:00:00 2001 From: Lee James O'Riordan Date: Fri, 2 Aug 2024 17:14:53 -0400 Subject: [PATCH 109/227] Fix sync issues with calls to CUSV APIs on aarch64 (#823) Please complete the following checklist when submitting a PR: - [x] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [x] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [x] Ensure that the test suite passes, by running `make test`. - [x] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [x] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** Fixes the known sync issues on aarch64 + GraceHopper when using custatevec API calls. **Description of the Change:** Adds stream sync to all CUSV async API calls. **Benefits:** Fixes #793 **Possible Drawbacks:** Potential sync point may introduce (minimal) overhead for smaller problems. **Related GitHub Issues:** --------- Co-authored-by: Lee J. O'Riordan Co-authored-by: ringo-but-quantum Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- .github/CHANGELOG.md | 6 ++++++ .github/workflows/tests_lgpumpi_cpp.yml | 3 ++- .github/workflows/tests_lgpumpi_python.yml | 2 +- README.rst | 4 ++-- cmake/support_pllgpu.cmake | 4 ++++ .../lightning_gpu/StateVectorCudaManaged.hpp | 8 ++++++++ .../measurements/MeasurementsGPU.hpp | 18 +++++++++++++++++- 7 files changed, 40 insertions(+), 5 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 4d53bf6369..c0e20d79f8 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -73,6 +73,12 @@ ### Bug fixes +* Fix cuQuantum SDK path pass-though in CMake. + [(#831)](https://github.com/PennyLaneAI/pennylane-lightning/pull/831) + +* Fix CUDA sync issues on aarch64+GraceHopper. + [(#823)](https://github.com/PennyLaneAI/pennylane-lightning/pull/823) + * Check for the number of wires for Hermitian observables in Lightning-Tensor. Only 1-wire Hermitian observables are supported as of `cuTensorNet-v24.03.0`. [(#806)](https://github.com/PennyLaneAI/pennylane-lightning/pull/806) diff --git a/.github/workflows/tests_lgpumpi_cpp.yml b/.github/workflows/tests_lgpumpi_cpp.yml index 58c86ce22c..fdcd17c122 100644 --- a/.github/workflows/tests_lgpumpi_cpp.yml +++ b/.github/workflows/tests_lgpumpi_cpp.yml @@ -123,7 +123,7 @@ jobs: - name: Build and run unit tests run: | source /etc/profile.d/modules.sh && module use /opt/modules/ && module load ${{ matrix.mpilib }}/cuda-${{ matrix.cuda_version_maj }}.${{ matrix.cuda_version_min }} - export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") cmake . -BBuild \ -DPL_BACKEND=lightning_gpu \ -DENABLE_PYTHON=OFF \ @@ -134,6 +134,7 @@ jobs: -DCMAKE_CXX_COMPILER=mpicxx \ -DCMAKE_CUDA_COMPILER=$(which nvcc) \ -DCMAKE_CUDA_ARCHITECTURES="86" \ + -DCUQUANTUM_SDK=${CUQUANTUM_SDK} \ -DPython_EXECUTABLE:FILE="${{ steps.python_path.outputs.python }}" \ -G Ninja cmake --build ./Build diff --git a/.github/workflows/tests_lgpumpi_python.yml b/.github/workflows/tests_lgpumpi_python.yml index 705ae79540..9a27030a07 100644 --- a/.github/workflows/tests_lgpumpi_python.yml +++ b/.github/workflows/tests_lgpumpi_python.yml @@ -129,7 +129,7 @@ jobs: - name: Build and install package env: - CUQUANTUM_SDK: $(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + CUQUANTUM_SDK: $(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") run: | source /etc/profile.d/modules.sh && module use /opt/modules/ && module load ${{ matrix.mpilib }}/cuda-${{ matrix.cuda_version_maj }}.${{ matrix.cuda_version_min }} CMAKE_ARGS="-DCMAKE_C_COMPILER=mpicc -DCMAKE_CXX_COMPILER=mpicxx -DENABLE_MPI=ON -DCMAKE_CUDA_COMPILER=$(which nvcc) -DCMAKE_CUDA_ARCHITECTURES=${{ env.CI_CUDA_ARCH }} -DPython_EXECUTABLE=${{ steps.python_path.outputs.python }}" \ diff --git a/README.rst b/README.rst index ea8ba722a4..3f9b6b19f6 100644 --- a/README.rst +++ b/README.rst @@ -249,7 +249,7 @@ Then the `cuStateVec`_ library can be installed and set a ``CUQUANTUM_SDK`` envi .. code-block:: console python -m pip install wheel custatevec-cu12 - export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") The Lightning-GPU can then be installed with ``pip``: @@ -386,7 +386,7 @@ Then the `cutensornet`_ library can be installed and set a ``CUQUANTUM_SDK`` env .. code-block:: console pip install cutensornet-cu12 - export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") + export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") The Lightning-Tensor can then be installed with ``pip``: diff --git a/cmake/support_pllgpu.cmake b/cmake/support_pllgpu.cmake index 490e02c075..3822040b23 100644 --- a/cmake/support_pllgpu.cmake +++ b/cmake/support_pllgpu.cmake @@ -47,6 +47,7 @@ endmacro() # Macro to aid in finding cuStateVec lib macro(findCustatevec external_libs) + set(CUQUANTUM_ENV "$ENV{CUQUANTUM_SDK}") find_library(CUSTATEVEC_LIB NAMES libcustatevec.so.1 custatevec.so.1 HINTS /usr/lib @@ -58,6 +59,8 @@ macro(findCustatevec external_libs) lib64 ${CUQUANTUM_SDK}/lib ${CUQUANTUM_SDK}/lib64 + ${CUQUANTUM_ENV}/lib + ${CUQUANTUM_ENV}/lib64 ${CUDAToolkit_LIBRARY_DIR} ${CUDA_TOOLKIT_ROOT_DIR}/lib ${CUDA_TOOLKIT_ROOT_DIR}/lib64 @@ -74,6 +77,7 @@ macro(findCustatevec external_libs) /opt/cuda include ${CUQUANTUM_SDK}/include + ${CUQUANTUM_ENV}/include ${CUDAToolkit_INCLUDE_DIRS} ${CUDA_TOOLKIT_ROOT_DIR}/include ${Python_SITELIB}/cuquantum/include diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp index 153dd6a782..e7bcadcb18 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp @@ -1359,6 +1359,8 @@ class StateVectorCudaManaged /* const int32_t* */ ctrlsInt.data(), /* const int32_t* */ nullptr, /* const uint32_t */ ctrls.size())); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + BaseType::getDataBuffer().getDevTag().getStreamID())); } /** @@ -1419,6 +1421,9 @@ class StateVectorCudaManaged /* custatevecComputeType_t */ compute_type, /* std::size_t* */ &extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + BaseType::getDataBuffer().getDevTag().getStreamID())); + // allocate external workspace if necessary // LCOV_EXCL_START if (extraWorkspaceSizeInBytes > 0) { @@ -1445,6 +1450,9 @@ class StateVectorCudaManaged /* custatevecComputeType_t */ compute_type, /* void* */ extraWorkspace, /* std::size_t */ extraWorkspaceSizeInBytes)); + + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + BaseType::getDataBuffer().getDevTag().getStreamID())); // LCOV_EXCL_START if (extraWorkspaceSizeInBytes) PL_CUDA_IS_SUCCESS(cudaFree(extraWorkspace)); 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 41045821aa..a229425175 100644 --- a/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_gpu/measurements/MeasurementsGPU.hpp @@ -135,6 +135,8 @@ class Measurements final /* const int32_t* */ maskBitString, /* const int32_t* */ maskOrdering, /* const uint32_t */ maskLen)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); if constexpr (std::is_same_v || std::is_same_v) { @@ -252,6 +254,8 @@ class Measurements final this->_statevector.getCusvHandle(), this->_statevector.getData(), data_type, num_qubits, &sampler, num_samples, &extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // allocate external workspace if necessary if (extraWorkspaceSizeInBytes > 0) @@ -262,12 +266,16 @@ class Measurements final PL_CUSTATEVEC_IS_SUCCESS(custatevecSamplerPreprocess( this->_statevector.getCusvHandle(), sampler, extraWorkspace, extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // sample bit strings PL_CUSTATEVEC_IS_SUCCESS(custatevecSamplerSample( this->_statevector.getCusvHandle(), sampler, bitStrings.data(), bitOrdering.data(), bitStringLen, rand_nums.data(), num_samples, CUSTATEVEC_SAMPLER_OUTPUT_ASCENDING_ORDER)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // destroy descriptor and handle PL_CUSTATEVEC_IS_SUCCESS(custatevecSamplerDestroy(sampler)); @@ -497,6 +505,9 @@ class Measurements final const_cast(basisBits_ptr.data()), /* const uint32_t */ n_basisBits.data())); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); + std::complex result{0, 0}; if constexpr (std::is_same_v) { @@ -804,6 +815,8 @@ class Measurements final /* const uint32_t */ tgtsInt.size(), /* custatevecComputeType_t */ compute_type, /* std::size_t* */ &extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); // LCOV_EXCL_START if (extraWorkspaceSizeInBytes > 0) { @@ -832,6 +845,9 @@ class Measurements final /* void* */ extraWorkspace, /* std::size_t */ extraWorkspaceSizeInBytes)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize( + this->_statevector.getDataBuffer().getDevTag().getStreamID())); + // LCOV_EXCL_START if (extraWorkspaceSizeInBytes) PL_CUDA_IS_SUCCESS(cudaFree(extraWorkspace)); @@ -840,4 +856,4 @@ class Measurements final return static_cast(expect.x); } }; // class Measurements -} // namespace Pennylane::LightningGPU::Measures \ No newline at end of file +} // namespace Pennylane::LightningGPU::Measures From 2290fdb4a51d9d9022a948bf696bd8e98a55a946 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 5 Aug 2024 13:58:36 +0000 Subject: [PATCH 110/227] Auto update version from '0.38.0-dev25' to '0.38.0-dev26' --- 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 3961045c01..444de99a58 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.38.0-dev25" +__version__ = "0.38.0-dev26" From 671b5c4a2baeb0ae9284f4670b9378c266a8812b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 14:15:59 +0000 Subject: [PATCH 111/227] move cuda kernerls to measurements dir --- .../src/simulators/lightning_tensor/tncuda/CMakeLists.txt | 4 ++-- .../lightning_tensor/tncuda/measurements/CMakeLists.txt | 8 +++++--- .../cuda_kernels_measures.cu} | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) rename pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/{cuda_kernels_ltensor.cu => measurements/cuda_kernels_measures.cu} (99%) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt index 39250497d8..49630b536f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/CMakeLists.txt @@ -9,7 +9,7 @@ message(${LOGO}) project(${PL_BACKEND} DESCRIPTION "Lightning-Tensor MPS bindings for PennyLane. Backed by NVIDIA cuQuantum SDK." - LANGUAGES CXX C CUDA + LANGUAGES CXX C ) include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pllgpu.cmake") @@ -17,7 +17,7 @@ include("${pennylane_lightning_SOURCE_DIR}/cmake/support_pltensortncuda.cmake") findCUDATK(lightning_external_libs) findCutensornet(lightning_external_libs) -set(LTENSOR_MPS_FILES MPSTNCuda.cpp cuda_kernels_ltensor.cu CACHE INTERNAL "" FORCE) +set(LTENSOR_MPS_FILES MPSTNCuda.cpp CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND} STATIC ${LTENSOR_MPS_FILES}) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt index 12ea988efd..490d6d2fa9 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt @@ -1,12 +1,14 @@ cmake_minimum_required(VERSION 3.20) -project(${PL_BACKEND}_measurements LANGUAGES CXX) +project(${PL_BACKEND}_measurements LANGUAGES CXX C CUDA) -add_library(${PL_BACKEND}_measurements INTERFACE) +set(LTENSOR_MPS_FILES cuda_kernels_measures.cu CACHE INTERNAL "" FORCE) + +add_library(${PL_BACKEND}_measurements STATIC ${LTENSOR_MPS_FILES}) target_include_directories(${PL_BACKEND}_measurements INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(${PL_BACKEND}_measurements INTERFACE lightning_compile_options +target_link_libraries(${PL_BACKEND}_measurements PUBLIC lightning_compile_options lightning_external_libs ${PL_BACKEND} ${PL_BACKEND}_utils diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu similarity index 99% rename from pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu rename to pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu index deb308dc5a..c09d644b75 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/cuda_kernels_ltensor.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu @@ -9,7 +9,7 @@ // See the License for the specific language governing permissions and // limitations under the License. /** - * @file cuda_kernels_ltensor.cu + * @file cuda_kernels_measures.cu */ #include From 75352848c2c620030fbac6e429d1bb1cb3a61116 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 20:33:06 +0000 Subject: [PATCH 112/227] add subset probs support --- .../measurements/MeasurementsTNCuda.hpp | 22 ++++++ .../measurements/cuda_kernels_measures.cu | 76 +++++++++++++++++++ .../tests/Test_MPSTNCuda_Measure.cpp | 8 +- .../core/src/utils/cuda_utils/LinearAlg.hpp | 22 ++++++ 4 files changed, 127 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 4700ac7104..99cfc5467d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -25,6 +25,7 @@ #include #include +#include "LinearAlg.hpp" #include "MPSTNCuda.hpp" #include "ObservablesTNCuda.hpp" #include "ObservablesTNCudaOperator.hpp" @@ -47,6 +48,14 @@ extern void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, const std::size_t thread_per_block, cudaStream_t stream_id); +extern void normalizeProbs_CUDA(float *probs, const int data_size, + const float sum, + const std::size_t thread_per_block, + cudaStream_t stream_id); +extern void normalizeProbs_CUDA(double *probs, const int data_size, + const double sum, + const std::size_t thread_per_block, + cudaStream_t stream_id); /** * @brief ObservablesTNCuda's Measurement Class. * @@ -98,6 +107,19 @@ template class MeasurementsTNCuda { length, static_cast(thread_per_block), tensor_network_.getDevTag().getStreamID()); + SharedCublasCaller cublascaller = make_shared_cublas_caller(); + + PrecisionT sum; + + asum_CUDA_device(d_output_probs.getData(), length, + tensor_network_.getDevTag().getDeviceID(), + tensor_network_.getDevTag().getStreamID(), + *cublascaller, &sum); + + normalizeProbs_CUDA(d_output_probs.getData(), length, sum, + static_cast(thread_per_block), + tensor_network_.getDevTag().getStreamID()); + d_output_probs.CopyGpuDataToHost(h_res.data(), h_res.size()); return h_res; diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu index c09d644b75..f95b376a82 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu @@ -32,6 +32,22 @@ void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, const std::size_t thread_per_block, cudaStream_t stream_id); +/** + * @brief Explicitly get the probability of given state tensor data on GPU + * device. + * + * @param probs The probability to be normalized. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ +void normalizeProbs_CUDA(float *probs, const int data_size, const float sum, + const std::size_t thread_per_block, + cudaStream_t stream_id); +void normalizeProbs_CUDA(double *probs, const int data_size, const double sum, + const std::size_t thread_per_block, + cudaStream_t stream_id); + /** * @brief The CUDA kernel that calculate the probability from a given state * tensor data on GPU device. @@ -55,6 +71,26 @@ __global__ void getProbsKernel(GPUDataT *state, PrecisionT *probs, } } +/** + * @brief The CUDA kernel that normalize the probability from a given state + * tensor data on GPU device. + * + * @tparam PrecisionT Floating data type. + * + * @param probs The probability to be normalized. + * @param data_size The length of state tensor on device. + * @param sum The sum of all probabilities. + */ +template +__global__ void normalizeProbsKernel(PrecisionT *probs, const int data_size, + const PrecisionT sum) { + const unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; + + if (i < data_size) { + probs[i] /= sum; + } +} + /** * @brief The CUDA kernel call wrapper. * @@ -81,6 +117,32 @@ void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, PL_CUDA_IS_SUCCESS(cudaGetLastError()); } +/** + * @brief The CUDA kernel call wrapper. + * + * @tparam PrecisionT Floating data type. + * + * @param probs The probability to be normalized. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ +template +void normalizeProbs_CUDA_call(PrecisionT *probs, const int data_size, + const PrecisionT sum, + std::size_t thread_per_block, + cudaStream_t stream_id) { + auto dv = std::div(data_size, thread_per_block); + std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); + const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); + dim3 blockSize(thread_per_block, 1, 1); + dim3 gridSize(block_per_grid, 1); + + normalizeProbsKernel + <<>>(probs, data_size, sum); + PL_CUDA_IS_SUCCESS(cudaGetLastError()); +} + // Definitions void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, const std::size_t thread_per_block, cudaStream_t stream_id) { @@ -93,4 +155,18 @@ void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, getProbs_CUDA_call(state, probs, data_size, thread_per_block, stream_id); } + +void normalizeProbs_CUDA(float *probs, const int data_size, const float sum, + const std::size_t thread_per_block, + cudaStream_t stream_id) { + normalizeProbs_CUDA_call(probs, data_size, sum, thread_per_block, + stream_id); +} + +void normalizeProbs_CUDA(double *probs, const int data_size, const double sum, + const std::size_t thread_per_block, + cudaStream_t stream_id) { + normalizeProbs_CUDA_call(probs, data_size, sum, thread_per_block, + stream_id); +} } // namespace Pennylane::LightningTensor::TNCuda::Measures \ No newline at end of file diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp index 3585ff9b71..ab6b2a3211 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp @@ -43,7 +43,13 @@ TEMPLATE_TEST_CASE("Probabilities", "[Measures]", float, double) { input = { {{2, 1, 0}, {7.67899385e-01, 9.97094446e-02, 1.54593908e-02, 2.00735578e-03, - 9.97094446e-02, 1.29469740e-02, 2.00735578e-03, 2.60649160e-04}}}; + 9.97094446e-02, 1.29469740e-02, 2.00735578e-03, 2.60649160e-04}}, + {{2, 1}, {0.86760883, 0.11265642, 0.01746675, 0.002268}}, + {{2, 0}, {0.78335878, 0.1017168, 0.1017168, 0.01320762}}, + {{0, 1}, {0.86760883, 0.01746675, 0.11265642, 0.002268}}, + {{2}, {0.88507558, 0.11492442}}, + {{1}, {0.98026525, 0.01973475}}, + {{0}, {0.88507558, 0.11492442}}}; // data from default.qubit // Defining the State Vector that will be measured. std::size_t bondDim = GENERATE(2, 3, 4, 5); diff --git a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp index a06765849a..00c995529f 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp @@ -109,6 +109,28 @@ inline void GEMM_CUDA_device(T *A, T *B, T *C, const int m, const int k, n, k, &alpha, A, m, B, n, &beta, C, m); } } + +/** + * @brief cuBLAS backed sum of the absolute value of a vector for GPU data. + * + * @tparam T Float data-type. Accepts float and double + * @tparam DevTypeID Integer type of device id. + * + * @param A Device data pointer of vector A. + * @param n Length of the vector. + * @param res Device data pointer to store the result. + */ +template +inline void asum_CUDA_device(const T *A, const int n, DevTypeID dev_id, + cudaStream_t stream_id, const CublasCaller &cublas, + T *res) { + if constexpr (std::is_same_v) { + cublas.call(cublasSasum, dev_id, stream_id, n, A, 1, res); + } else if constexpr (std::is_same_v) { + cublas.call(cublasDasum, dev_id, stream_id, n, A, 1, res); + } +} + /** * @brief cuBLAS backed inner product for GPU data. * From 1f156dbbb4e8ffe478cf837dae60ac797b62b159 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 20:52:07 +0000 Subject: [PATCH 113/227] add python layer --- .../core/src/bindings/Bindings.hpp | 7 +++++ .../lightning_tensor/_measurements.py | 28 ++++++++++++++++++- tests/test_apply.py | 2 +- tests/test_measurements.py | 4 --- tests/test_templates.py | 12 ++------ 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/pennylane_lightning/core/src/bindings/Bindings.hpp b/pennylane_lightning/core/src/bindings/Bindings.hpp index f1b7acf167..08907f5126 100644 --- a/pennylane_lightning/core/src/bindings/Bindings.hpp +++ b/pennylane_lightning/core/src/bindings/Bindings.hpp @@ -734,6 +734,13 @@ void registerLightningTensorBackendAgnosticMeasurements(PyClass &pyclass) { return M.expval(*ob); }, "Expected value of an observable object.") + .def( + "probs", + [](MeasurementsT &M, const std::vector &wires) { + return py::array_t( + py::cast(M.probs(wires))); + }, + "Probabilities of a set of wires.") .def( "var", [](MeasurementsT &M, const std::shared_ptr &ob) { diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index ef9cc65eb1..da57b12478 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -28,6 +28,7 @@ from pennylane.measurements import ExpectationMP, MeasurementProcess, StateMeasurement, VarianceMP from pennylane.tape import QuantumScript from pennylane.typing import Result, TensorLike +from pennylane.wires import Wires from pennylane_lightning.core._serialize import QuantumScriptSerializer @@ -71,7 +72,13 @@ def state_diagonalizing_gates(self, measurementprocess: StateMeasurement) -> Ten Returns: TensorLike: the result of the measurement """ - return self._tensornet.state + diagonalizing_gates = measurementprocess.diagonalizing_gates() + self._tensornet.apply_operations(diagonalizing_gates) + state_array = self._tensornet.state + wires = Wires(range(self._tensornet.num_wires)) + result = measurementprocess.process_state(state_array, wires) + self._tensornet.apply_operations([qml.adjoint(g) for g in reversed(diagonalizing_gates)]) + return result # pylint: disable=protected-access def expval(self, measurementprocess: MeasurementProcess): @@ -95,6 +102,25 @@ def expval(self, measurementprocess: MeasurementProcess): )._ob(measurementprocess.obs) return self._measurement_lightning.expval(ob_serialized) + def probs(self, measurementprocess: MeasurementProcess): + """Probabilities of the supplied observable or wires contained in the MeasurementProcess. + + Args: + measurementprocess (StateMeasurement): measurement to apply to the state + + Returns: + Probabilities of the supplied observable or wires + """ + diagonalizing_gates = measurementprocess.diagonalizing_gates() + if diagonalizing_gates: + self._qubit_state.apply_operations(diagonalizing_gates) + results = self._measurement_lightning.probs(measurementprocess.wires.tolist()) + if diagonalizing_gates: + self._qubit_state.apply_operations( + [qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)] + ) + return results + def var(self, measurementprocess: MeasurementProcess): """Variance of the supplied observable contained in the MeasurementProcess. Note that the variance is calculated as - **2. The current implementation only supports single-wire observables. diff --git a/tests/test_apply.py b/tests/test_apply.py index a055d5e4b3..7c59e39a42 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -1363,7 +1363,7 @@ def circuit(): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.prob()", + reason="lightning.tensor does not support _tensornet.state access", ) def test_apply_qpe(self, qubit_device, tol): """Test the application of qml.QuantumPhaseEstimation""" diff --git a/tests/test_measurements.py b/tests/test_measurements.py index 88459209b1..1cce1f8616 100644 --- a/tests/test_measurements.py +++ b/tests/test_measurements.py @@ -50,10 +50,6 @@ def circuit(x): circuit(0.65) -@pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.probs()", -) class TestProbs: """Test Probs in Lightning devices""" diff --git a/tests/test_templates.py b/tests/test_templates.py index d97d1a29a3..32952aef28 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -30,11 +30,9 @@ class TestGrover: """Test Grover's algorithm (multi-controlled gates, decomposition, etc.)""" - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support multi-controlled gates and probs()", + @pytest.mark.parametrize( + "n_qubits", range(4, 8) if device_name != "lightning.tensor" else range(4, 6) ) - @pytest.mark.parametrize("n_qubits", range(4, 8)) def test_grover(self, n_qubits): np.random.seed(42) omega = np.random.rand(n_qubits) > 0.5 @@ -728,11 +726,7 @@ def circuit(): estimation_wires=estimation_wires, ) - return ( - qml.probs(estimation_wires) - if device_name != "lightning.tensor" - else qml.expval(qml.PauliZ(0)) - ) # lightning.tensor does not support qml.probs() + return qml.probs(estimation_wires) res = qml.QNode(circuit, dev, diff_method=None)() ref = qml.QNode(circuit, dq, diff_method=None)() From cb41d591d8c8f0ecc5c4639d8128dc3c749d73a8 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 21:09:33 +0000 Subject: [PATCH 114/227] update python layer tests --- .../lightning_tensor/_measurements.py | 4 +- .../lightning_tensor/test_gates_and_expval.py | 5 +- tests/new_api/test_device.py | 110 ++++++++++++------ tests/new_api/test_var.py | 6 +- 4 files changed, 77 insertions(+), 48 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index da57b12478..ff10e65223 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -165,9 +165,7 @@ def get_measurement_function( if measurementprocess.obs is None: return self.state_diagonalizing_gates - raise NotImplementedError( - "Does not support current measurement. Only ExpectationMP measurements are supported." - ) + raise NotImplementedError("Not supported measurement.") def measurement(self, measurementprocess: MeasurementProcess) -> TensorLike: """Apply a measurement process to a tensor network. diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index ee60dffba9..af6fce534a 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -308,10 +308,7 @@ def test_measurement_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs) m = LightningTensorMeasurements(tensornet) - with pytest.raises( - NotImplementedError, - match="Does not support current measurement. Only ExpectationMP measurements are supported.", - ): + with pytest.raises(NotImplementedError, match="Not supported measurement."): m.measure_tensor_network(tape) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 7ecb6fb684..dbc332c020 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -187,10 +187,6 @@ def test_invalid_kernel_name(self): _ = LightningDevice(wires=2, shots=1000, mcmc=True, kernel_name="bleh") -@pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support adjoint_observables", -) class TestExecution: """Unit tests for executing quantum tapes on a device""" @@ -217,6 +213,9 @@ def process_and_execute(device, tape): "num_burnin": 0, } + @pytest.mark.skipif( + device_name="lightning.tensor", reason="lightning.tensor does not support rng key" + ) @pytest.mark.parametrize( "config, expected_config", [ @@ -277,6 +276,9 @@ def test_preprocess_correct_config_setup(self, config, expected_config): assert new_config == expected_config + @pytest.mark.skipif( + device_name="lightning.tensor", reason="lightning.tensor does not support adjoint" + ) @pytest.mark.parametrize("adjoint", [True, False]) def test_preprocess(self, adjoint): """Test that the transform program returned by preprocess is correct""" @@ -324,13 +326,17 @@ def test_preprocess(self, adjoint): @pytest.mark.parametrize( "op, is_trainable", - [ + ([ (qml.StatePrep([1 / np.sqrt(2), 1 / np.sqrt(2)], wires=0), False), (qml.StatePrep(qml.numpy.array([1 / np.sqrt(2), 1 / np.sqrt(2)]), wires=0), True), (qml.StatePrep(np.array([1, 0]), wires=0), False), (qml.BasisState([1, 1], wires=[0, 1]), False), (qml.BasisState(qml.numpy.array([1, 1]), wires=[0, 1]), True), - ], + ] + if device_name != "lightning.tensor" + else [ + (qml.BasisState([1, 1], wires=[0, 1]), False), + ]), ) def test_preprocess_state_prep_first_op_decomposition(self, op, is_trainable): """Test that state prep ops in the beginning of a tape are decomposed with adjoint @@ -383,26 +389,38 @@ def test_preprocess_state_prep_middle_op_decomposition(self, op, decomp_depth): @pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) @pytest.mark.parametrize( "mp", - [ - qml.probs(wires=[1, 2]), - qml.probs(op=qml.Z(2)), - qml.expval(qml.Z(2)), - qml.var(qml.X(2)), - qml.expval(qml.X(0) + qml.Z(0)), - qml.expval(qml.Hamiltonian([-0.5, 1.5], [qml.Y(1), qml.X(1)])), - qml.expval(2.5 * qml.Z(0)), - qml.expval(qml.Z(0) @ qml.X(1)), - qml.expval(qml.operation.Tensor(qml.Z(0), qml.X(1))), - qml.expval( - qml.SparseHamiltonian( - qml.Hamiltonian([-1.0, 1.5], [qml.Z(1), qml.X(1)]).sparse_matrix( - wire_order=[0, 1, 2] - ), - wires=[0, 1, 2], - ) - ), - qml.expval(qml.Projector([1], wires=2)), - ], + ( + [ + qml.probs(wires=[1, 2]), + qml.probs(op=qml.Z(2)), + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.expval(qml.X(0) + qml.Z(0)), + qml.expval(qml.Hamiltonian([-0.5, 1.5], [qml.Y(1), qml.X(1)])), + qml.expval(2.5 * qml.Z(0)), + qml.expval(qml.Z(0) @ qml.X(1)), + qml.expval(qml.operation.Tensor(qml.Z(0), qml.X(1))), + qml.expval( + qml.SparseHamiltonian( + qml.Hamiltonian([-1.0, 1.5], [qml.Z(1), qml.X(1)]).sparse_matrix( + wire_order=[0, 1, 2] + ), + wires=[0, 1, 2], + ) + ), + qml.expval(qml.Projector([1], wires=2)), + ] + if device_name != "lightning.tensor" + else [ + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.expval(qml.X(0) + qml.Z(0)), + qml.expval(qml.Hamiltonian([-0.5, 1.5], [qml.Y(1), qml.X(1)])), + qml.expval(2.5 * qml.Z(0)), + qml.expval(qml.Z(0) @ qml.X(1)), + qml.expval(qml.operation.Tensor(qml.Z(0), qml.X(1))), + ] + ), ) def test_execute_single_measurement(self, theta, phi, mp, dev): """Test that execute returns the correct results with a single measurement.""" @@ -426,21 +444,37 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): @pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) @pytest.mark.parametrize( "mp1", - [ - qml.probs(wires=[1, 2]), - qml.expval(qml.Z(2)), - qml.var(qml.X(2)), - qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), - ], + ( + [ + qml.probs(wires=[1, 2]), + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), + ] + if device_name != "lightning.tensor" + else [ + qml.expval(qml.Z(2)), + qml.var(qml.X(2)), + qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), + ] + ), ) @pytest.mark.parametrize( "mp2", - [ - qml.probs(op=qml.X(2)), - qml.expval(qml.Y(2)), - qml.var(qml.Y(2)), - qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), - ], + ( + [ + qml.probs(op=qml.X(2)), + qml.expval(qml.Y(2)), + qml.var(qml.Y(2)), + qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), + ] + if device_name != "lightning.tensor" + else [ + qml.expval(qml.Y(2)), + qml.var(qml.Y(2)), + qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), + ] + ), ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): """Test that execute returns the correct results with multiple measurements.""" diff --git a/tests/new_api/test_var.py b/tests/new_api/test_var.py index 8feb620c82..29b795d9ad 100644 --- a/tests/new_api/test_var.py +++ b/tests/new_api/test_var.py @@ -22,9 +22,6 @@ from conftest import PHI, THETA, VARPHI, LightningDevice, device_name from pennylane.tape import QuantumScript -if device_name == "lightning.tensor": - pytest.skip("lightning.tensor does not support qml.var()", allow_module_level=True) - if not LightningDevice._new_API: pytest.skip("Exclusive tests for new API. Skipping.", allow_module_level=True) @@ -211,6 +208,9 @@ def test_hamiltonian_variance(self, theta, phi, dev): tol = 1e-5 if dev.c_dtype == np.complex64 else 1e-7 assert np.allclose(calculated_val, reference_val, atol=tol, rtol=0) + @pytest.mark.skipif( + device_name == "lightning.tensor", reason="SparseH not supported on lightning.tensor." + ) def test_sparse_hamiltonian_variance(self, theta, phi, dev): """Tests a Hamiltonian.""" From 51be722e9327a3284d18909edf3cf825b1db9175 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 21:10:54 +0000 Subject: [PATCH 115/227] Trigger CIs From 3f8564f995e2f0a360c5845e4a499897e8b2d7d7 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 21:25:33 +0000 Subject: [PATCH 116/227] fix typo --- pennylane_lightning/lightning_tensor/_measurements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index ff10e65223..f32450e658 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -113,10 +113,10 @@ def probs(self, measurementprocess: MeasurementProcess): """ diagonalizing_gates = measurementprocess.diagonalizing_gates() if diagonalizing_gates: - self._qubit_state.apply_operations(diagonalizing_gates) + self._tensornet.apply_operations(diagonalizing_gates) results = self._measurement_lightning.probs(measurementprocess.wires.tolist()) if diagonalizing_gates: - self._qubit_state.apply_operations( + self._tensornet.apply_operations( [qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)] ) return results From 4e227f12c8a87e7975d20bfd723693b42ed35088 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 5 Aug 2024 21:27:13 +0000 Subject: [PATCH 117/227] make format --- tests/new_api/test_device.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index dbc332c020..fb3d4fef45 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -326,17 +326,19 @@ def test_preprocess(self, adjoint): @pytest.mark.parametrize( "op, is_trainable", - ([ - (qml.StatePrep([1 / np.sqrt(2), 1 / np.sqrt(2)], wires=0), False), - (qml.StatePrep(qml.numpy.array([1 / np.sqrt(2), 1 / np.sqrt(2)]), wires=0), True), - (qml.StatePrep(np.array([1, 0]), wires=0), False), - (qml.BasisState([1, 1], wires=[0, 1]), False), - (qml.BasisState(qml.numpy.array([1, 1]), wires=[0, 1]), True), - ] - if device_name != "lightning.tensor" + ( + [ + (qml.StatePrep([1 / np.sqrt(2), 1 / np.sqrt(2)], wires=0), False), + (qml.StatePrep(qml.numpy.array([1 / np.sqrt(2), 1 / np.sqrt(2)]), wires=0), True), + (qml.StatePrep(np.array([1, 0]), wires=0), False), + (qml.BasisState([1, 1], wires=[0, 1]), False), + (qml.BasisState(qml.numpy.array([1, 1]), wires=[0, 1]), True), + ] + if device_name != "lightning.tensor" else [ (qml.BasisState([1, 1], wires=[0, 1]), False), - ]), + ] + ), ) def test_preprocess_state_prep_first_op_decomposition(self, op, is_trainable): """Test that state prep ops in the beginning of a tape are decomposed with adjoint @@ -389,7 +391,7 @@ def test_preprocess_state_prep_middle_op_decomposition(self, op, decomp_depth): @pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) @pytest.mark.parametrize( "mp", - ( + ( [ qml.probs(wires=[1, 2]), qml.probs(op=qml.Z(2)), From 02b8c9bc0020a8a748eb3707304d95882c83cade Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 6 Aug 2024 14:01:11 +0000 Subject: [PATCH 118/227] update C++ unit tests --- .../measurements/MeasurementsTNCuda.hpp | 4 +++ .../measurements/cuda_kernels_measures.cu | 2 +- .../tests/Test_MPSTNCuda_Measure.cpp | 27 ++++++++++--------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 99cfc5467d..265560c568 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -89,6 +89,10 @@ template class MeasurementsTNCuda { template auto probs(const std::vector &wires, const int32_t numHyperSamples = 1) -> std::vector { + PL_ABORT_IF_NOT(std::is_sorted(wires.begin(), wires.end()), + "Invalid wire indices order. Please ensure that the " + "wire indices are in the ascending order."); + const std::size_t length = std::size_t{1} << wires.size(); std::vector h_res(length); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu index f95b376a82..c43e1e3fb4 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu @@ -169,4 +169,4 @@ void normalizeProbs_CUDA(double *probs, const int data_size, const double sum, normalizeProbs_CUDA_call(probs, data_size, sum, thread_per_block, stream_id); } -} // namespace Pennylane::LightningTensor::TNCuda::Measures \ No newline at end of file +} // namespace Pennylane::LightningTensor::TNCuda::Measures diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp index ab6b2a3211..61dcb732e2 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp @@ -40,16 +40,15 @@ TEMPLATE_TEST_CASE("Probabilities", "[Measures]", float, double) { using TensorNetT = MPSTNCuda; // Probabilities calculated with Pennylane default.qubit: std::vector, std::vector>> - input = { - {{2, 1, 0}, - {7.67899385e-01, 9.97094446e-02, 1.54593908e-02, 2.00735578e-03, - 9.97094446e-02, 1.29469740e-02, 2.00735578e-03, 2.60649160e-04}}, - {{2, 1}, {0.86760883, 0.11265642, 0.01746675, 0.002268}}, - {{2, 0}, {0.78335878, 0.1017168, 0.1017168, 0.01320762}}, - {{0, 1}, {0.86760883, 0.01746675, 0.11265642, 0.002268}}, - {{2}, {0.88507558, 0.11492442}}, - {{1}, {0.98026525, 0.01973475}}, - {{0}, {0.88507558, 0.11492442}}}; // data from default.qubit + input = {{{0, 1, 2}, + {0.65473791, 0.08501576, 0.02690407, 0.00349341, 0.19540418, + 0.02537265, 0.00802942, 0.0010426}}, + {{0, 1}, {0.73975367, 0.03039748, 0.22077683, 0.00907202}}, + {{0, 2}, {0.68164198, 0.08850918, 0.2034336, 0.02641525}}, + {{1, 2}, {0.85014208, 0.11038841, 0.03493349, 0.00453601}}, + {{0}, {0.77015115, 0.22984885}}, + {{1}, {0.9605305, 0.0394695}}, + {{2}, {0.88507558, 0.11492442}}}; // data from default.qubit // Defining the State Vector that will be measured. std::size_t bondDim = GENERATE(2, 3, 4, 5); @@ -59,7 +58,7 @@ TEMPLATE_TEST_CASE("Probabilities", "[Measures]", float, double) { TensorNetT mps_state{num_qubits, maxBondDim}; mps_state.applyOperations( - {{"RX"}, {"RY"}, {"RX"}, {"RY"}, {"RX"}, {"RY"}}, + {{"RX"}, {"RX"}, {"RY"}, {"RY"}, {"RX"}, {"RY"}}, {{0}, {0}, {1}, {1}, {2}, {2}}, {{false}, {false}, {false}, {false}, {false}, {false}}, {{0.5}, {0.5}, {0.2}, {0.2}, {0.5}, {0.5}}); @@ -74,4 +73,8 @@ TEMPLATE_TEST_CASE("Probabilities", "[Measures]", float, double) { Catch::Approx(probabilities).margin(1e-6)); } } -} \ No newline at end of file + + SECTION("Test TNCudaOperator ctor failures") { + REQUIRE_THROWS_AS(measure.probs({2, 1}), LightningException); + } +} From 36be23805f84fd337308d7f150737f7b9b03ed1f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 6 Aug 2024 14:05:29 +0000 Subject: [PATCH 119/227] add more docs --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 8aeae44572..69f715f7fe 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -309,6 +309,15 @@ class TNCudaBase : public TensornetBase { return get_state_tensor(wires, numHyperSamples); } + /** + * @brief Get a slice of the full state tensor + * + * @param wires Wires to get the state tensor for. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Full state tensor on the host memory + */ auto get_state_tensor(const std::vector &wires, const int32_t numHyperSamples = 1) -> std::vector { @@ -326,6 +335,17 @@ class TNCudaBase : public TensornetBase { return h_res; } + /** + * @brief Get a slice of the full state tensor + * + * @param tensor_data Pointer to the tensor data on the device memory. + * @param tensor_data_size Size of the tensor data. + * @param wires Wires to get the state tensor for. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + * + * @return Full state tensor on the host memory + */ void get_state_tensor(CFP_t *tensor_data, const std::size_t tensor_data_size, const std::vector &wires, From 153cfdce8d909900a1520603ae31e226a82e97e1 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 6 Aug 2024 14:10:10 +0000 Subject: [PATCH 120/227] add docs --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 32eb574dc6..07d2286e90 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -295,12 +295,12 @@ class TNCudaBase : public TensornetBase { } /** - * @brief Get full state tensor + * @brief Get the full state tensor * * @param numHyperSamples Number of hyper samples to use in the calculation * and is default as 1. * - * @return Full state tensor on the host memory + * @return Full the state tensor on the host memory */ auto get_state_tensor(const int32_t numHyperSamples = 1) -> std::vector { @@ -310,13 +310,13 @@ class TNCudaBase : public TensornetBase { } /** - * @brief Get full state tensor + * @brief Get a slice of the state tensor * * @param wires Wires to get the state tensor for. * @param numHyperSamples Number of hyper samples to use in the calculation * and is default as 1. * - * @return Full state tensor on the host memory + * @return A slice of the state tensor on the host memory */ auto get_state_tensor(const std::vector &wires, const int32_t numHyperSamples = 1) @@ -339,15 +339,13 @@ class TNCudaBase : public TensornetBase { } /** - * @brief Get full state tensor + * @brief Get a slice of the state tensor * * @param tensor_data Pointer to the device memory for state tensor data. * @param tensor_data_size Size of the state tensor data. * @param wires Wires to get the state tensor for. * @param numHyperSamples Number of hyper samples to use in the calculation * and is default as 1. - * - * @return Full state tensor on the host memory */ void get_state_tensor(CFP_t *tensor_data, const std::size_t tensor_data_size, From aa75832b2c66093f75e0539acff12bb6c3a28ddb Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 6 Aug 2024 15:07:26 +0000 Subject: [PATCH 121/227] update py layer unit tests --- pennylane_lightning/lightning_tensor/_measurements.py | 4 ++-- tests/lightning_tensor/test_gates_and_expval.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 8229a36148..7a0a79de8f 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -114,7 +114,7 @@ def var(self, measurementprocess: MeasurementProcess): Variance of the observable """ if isinstance(measurementprocess.obs, qml.SparseHamiltonian): - raise NotImplementedError("Sparse Hamiltonian Observables are not supported.") + raise NotImplementedError("The var measurement does not support sparse Hamiltonian observables.") if isinstance(measurementprocess.obs, qml.Hermitian): if len(measurementprocess.obs.wires) > 1: @@ -146,7 +146,7 @@ def get_measurement_function( if measurementprocess.obs is None: return self.state_diagonalizing_gates - raise NotImplementedError("Not supported measurement.") + raise NotImplementedError("Unsupported measurement type.") def measurement(self, measurementprocess: MeasurementProcess) -> TensorLike: """Apply a measurement process to a tensor network. diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index 595e3d0439..46abf31c02 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -257,7 +257,7 @@ def test_var_sparseH_not_supported(self): m = LightningTensorMeasurements(tensornet) with pytest.raises( - NotImplementedError, match="Sparse Hamiltonian Observables are not supported." + NotImplementedError, match="The var measurement does not support sparse Hamiltonian observables." ): m.var(q.queue[0]) @@ -297,7 +297,7 @@ def test_measurement_shot_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs, shots=1000) m = LightningTensorMeasurements(tensornet) - with pytest.raises(NotImplementedError, match="Shots are not supported for tensor network"): + with pytest.raises(NotImplementedError, match="Shots are not supported for tensor network simulations."): m.measure_tensor_network(tape) def test_measurement_not_supported(self): @@ -308,7 +308,7 @@ def test_measurement_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs) m = LightningTensorMeasurements(tensornet) - with pytest.raises(NotImplementedError, match="Not supported measurement."): + with pytest.raises(NotImplementedError, match="Unsupported measurement type."): m.measure_tensor_network(tape) From 600e11bb02aafd1e8a4f0eedbc94dab1b830b91a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 6 Aug 2024 15:08:53 +0000 Subject: [PATCH 122/227] make format --- pennylane_lightning/lightning_tensor/_measurements.py | 4 +++- tests/lightning_tensor/test_gates_and_expval.py | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 7a0a79de8f..5d563866ed 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -114,7 +114,9 @@ def var(self, measurementprocess: MeasurementProcess): Variance of the observable """ if isinstance(measurementprocess.obs, qml.SparseHamiltonian): - raise NotImplementedError("The var measurement does not support sparse Hamiltonian observables.") + raise NotImplementedError( + "The var measurement does not support sparse Hamiltonian observables." + ) if isinstance(measurementprocess.obs, qml.Hermitian): if len(measurementprocess.obs.wires) > 1: diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index 46abf31c02..d1955dc2d2 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -257,7 +257,8 @@ def test_var_sparseH_not_supported(self): m = LightningTensorMeasurements(tensornet) with pytest.raises( - NotImplementedError, match="The var measurement does not support sparse Hamiltonian observables." + NotImplementedError, + match="The var measurement does not support sparse Hamiltonian observables.", ): m.var(q.queue[0]) @@ -297,7 +298,9 @@ def test_measurement_shot_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs, shots=1000) m = LightningTensorMeasurements(tensornet) - with pytest.raises(NotImplementedError, match="Shots are not supported for tensor network simulations."): + with pytest.raises( + NotImplementedError, match="Shots are not supported for tensor network simulations." + ): m.measure_tensor_network(tape) def test_measurement_not_supported(self): From e2cc361a8179af0c5ad2a2ff991361f3413b8a1d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 6 Aug 2024 15:45:31 +0000 Subject: [PATCH 123/227] Trigger CIs From 18b22c01512aed9ea14d316aa76b02c86063cd94 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 00:17:26 +0000 Subject: [PATCH 124/227] fix projectedModesvalue in C++ --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- .../measurements/MeasurementsTNCuda.hpp | 7 +- .../tests/Test_MPSTNCuda_Measure.cpp | 68 +++++++++++-------- .../lightning_tensor/_measurements.py | 11 ++- tests/new_api/test_device.py | 4 ++ tests/test_measurements.py | 4 +- 6 files changed, 64 insertions(+), 32 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 69f715f7fe..1701d94db0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -363,7 +363,7 @@ class TNCudaBase : public TensornetBase { } } - std::vector projectedModeValues(projected_modes.size(), 1); + std::vector projectedModeValues(projected_modes.size(), 0); cutensornetStateAccessor_t accessor; PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateAccessor( diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 265560c568..ce79ebcb16 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -95,7 +95,7 @@ template class MeasurementsTNCuda { const std::size_t length = std::size_t{1} << wires.size(); - std::vector h_res(length); + std::vector h_res(length, 0.0); DataBuffer d_output_tensor( length, tensor_network_.getDevTag(), true); @@ -120,6 +120,11 @@ template class MeasurementsTNCuda { tensor_network_.getDevTag().getStreamID(), *cublascaller, &sum); + // TODO : Check if sum is zero and return h_res + if (sum == 0.0) { + return h_res; + } + normalizeProbs_CUDA(d_output_probs.getData(), length, sum, static_cast(thread_per_block), tensor_network_.getDevTag().getStreamID()); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp index 61dcb732e2..5e89426d49 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Measure.cpp @@ -38,35 +38,37 @@ using namespace Pennylane::LightningTensor::TNCuda; TEMPLATE_TEST_CASE("Probabilities", "[Measures]", float, double) { using TensorNetT = MPSTNCuda; - // Probabilities calculated with Pennylane default.qubit: - std::vector, std::vector>> - input = {{{0, 1, 2}, - {0.65473791, 0.08501576, 0.02690407, 0.00349341, 0.19540418, - 0.02537265, 0.00802942, 0.0010426}}, - {{0, 1}, {0.73975367, 0.03039748, 0.22077683, 0.00907202}}, - {{0, 2}, {0.68164198, 0.08850918, 0.2034336, 0.02641525}}, - {{1, 2}, {0.85014208, 0.11038841, 0.03493349, 0.00453601}}, - {{0}, {0.77015115, 0.22984885}}, - {{1}, {0.9605305, 0.0394695}}, - {{2}, {0.88507558, 0.11492442}}}; // data from default.qubit - - // Defining the State Vector that will be measured. - std::size_t bondDim = GENERATE(2, 3, 4, 5); - std::size_t num_qubits = 3; - std::size_t maxBondDim = bondDim; - - TensorNetT mps_state{num_qubits, maxBondDim}; - - mps_state.applyOperations( - {{"RX"}, {"RX"}, {"RY"}, {"RY"}, {"RX"}, {"RY"}}, - {{0}, {0}, {1}, {1}, {2}, {2}}, - {{false}, {false}, {false}, {false}, {false}, {false}}, - {{0.5}, {0.5}, {0.2}, {0.2}, {0.5}, {0.5}}); - mps_state.append_mps_final_state(); - - auto measure = MeasurementsTNCuda(mps_state); SECTION("Looping over different wire configurations:") { + // Probabilities calculated with Pennylane default.qubit: + std::vector, std::vector>> + input = { + {{0, 1, 2}, + {0.65473791, 0.08501576, 0.02690407, 0.00349341, 0.19540418, + 0.02537265, 0.00802942, 0.0010426}}, + {{0, 1}, {0.73975367, 0.03039748, 0.22077683, 0.00907202}}, + {{0, 2}, {0.68164198, 0.08850918, 0.2034336, 0.02641525}}, + {{1, 2}, {0.85014208, 0.11038841, 0.03493349, 0.00453601}}, + {{0}, {0.77015115, 0.22984885}}, + {{1}, {0.9605305, 0.0394695}}, + {{2}, {0.88507558, 0.11492442}}}; // data from default.qubit + + // Defining the State Vector that will be measured. + std::size_t bondDim = GENERATE(2, 3, 4, 5); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations( + {{"RX"}, {"RX"}, {"RY"}, {"RY"}, {"RX"}, {"RY"}}, + {{0}, {0}, {1}, {1}, {2}, {2}}, + {{false}, {false}, {false}, {false}, {false}, {false}}, + {{0.5}, {0.5}, {0.2}, {0.2}, {0.5}, {0.5}}); + mps_state.append_mps_final_state(); + + auto measure = MeasurementsTNCuda(mps_state); + for (const auto &term : input) { auto probabilities = measure.probs(term.first); REQUIRE_THAT(term.second, @@ -75,6 +77,18 @@ TEMPLATE_TEST_CASE("Probabilities", "[Measures]", float, double) { } SECTION("Test TNCudaOperator ctor failures") { + // Defining the State Vector that will be measured. + std::size_t bondDim = GENERATE(2, 3, 4, 5); + std::size_t num_qubits = 3; + std::size_t maxBondDim = bondDim; + + TensorNetT mps_state{num_qubits, maxBondDim}; + + mps_state.applyOperations({{"RX"}, {"RY"}}, {{0}, {0}}, + {{false}, {false}}, {{0.5}, {0.5}}); + mps_state.append_mps_final_state(); + + auto measure = MeasurementsTNCuda(mps_state); REQUIRE_THROWS_AS(measure.probs({2, 1}), LightningException); } } diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index f32450e658..ad8b59eeb2 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -25,7 +25,13 @@ import numpy as np import pennylane as qml -from pennylane.measurements import ExpectationMP, MeasurementProcess, StateMeasurement, VarianceMP +from pennylane.measurements import ( + ExpectationMP, + MeasurementProcess, + ProbabilityMP, + StateMeasurement, + VarianceMP, +) from pennylane.tape import QuantumScript from pennylane.typing import Result, TensorLike from pennylane.wires import Wires @@ -162,6 +168,9 @@ def get_measurement_function( if isinstance(measurementprocess, VarianceMP): return self.var + if isinstance(measurementprocess, ProbabilityMP): + return self.probs + if measurementprocess.obs is None: return self.state_diagonalizing_gates diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index fb3d4fef45..d861849ca0 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -521,6 +521,10 @@ def test_custom_wires(self, phi, theta, wires): assert np.allclose(result[0], np.cos(phi)) assert np.allclose(result[1], np.cos(phi) * np.cos(theta)) + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor does not support out of order probs", + ) @pytest.mark.parametrize( "wires, wire_order", [(3, (0, 1, 2)), (("a", "b", "c"), ("a", "b", "c"))] ) diff --git a/tests/test_measurements.py b/tests/test_measurements.py index 1cce1f8616..34221dad9a 100644 --- a/tests/test_measurements.py +++ b/tests/test_measurements.py @@ -151,8 +151,8 @@ def circuit(): _ = circuit() @pytest.mark.skipif( - device_name == "lightning.gpu", - reason="lightning.gpu does not support out of order prob.", + device_name == "lightning.gpu" or device_name == "lightning.tensor", + reason="lightning.gpu/lightning.tensor does not support out of order prob.", ) @pytest.mark.parametrize( "cases", From b8331dc8b343fd9c98126b651bb8b66c27938f0e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 02:04:06 +0000 Subject: [PATCH 125/227] get prob by sum over all projected values --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 136 +++++++++++------- .../measurements/MeasurementsTNCuda.hpp | 2 + 2 files changed, 89 insertions(+), 49 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 1701d94db0..de22ca77b4 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -365,6 +365,93 @@ class TNCudaBase : public TensornetBase { std::vector projectedModeValues(projected_modes.size(), 0); + if (projected_modes.empty()) { + get_accessor_(tensor_data, tensor_data_size, projected_modes, + projectedModeValues, numHyperSamples); + } else { + + DataBuffer tmp(tensor_data_size, getDevTag(), true); + + for (std::size_t idx = 0; + idx < (size_t(1) << projected_modes.size()); idx++) { + // std::vector + // projectedModeValues(projected_modes.size(), 0); + + for (std::size_t j = 0; j < projected_modes.size(); j++) { + projectedModeValues[j] = (idx >> j) & 1; + } + + get_accessor_(tmp.getData(), tensor_data_size, projected_modes, + projectedModeValues, numHyperSamples); + + SharedCublasCaller cublascaller = make_shared_cublas_caller(); + // Copy the data to the output tensor + scaleAndAddC_CUDA(std::complex{1.0, 0.0}, + tmp.getData(), tensor_data, tmp.getLength(), + getDevTag().getDeviceID(), + getDevTag().getStreamID(), *cublascaller); + } + } + } + + protected: + /** + * @brief Save quantumState information to data provided by a user + * + * @param tensorPtr Pointer to tensors provided by a user + */ + void computeState(int64_t **extentsPtr, void **tensorPtr) { + cutensornetWorkspaceDescriptor_t workDesc; + PL_CUTENSORNET_IS_SUCCESS( + cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); + + // TODO we assign half (magic number is) of free memory size to the + // maximum memory usage. + const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStatePrepare( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* size_t maxWorkspaceSizeDevice */ scratchSize, + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* cudaStream_t unused as of v24.03*/ 0x0)); + + std::size_t worksize = + getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); + + PL_ABORT_IF(worksize > scratchSize, + "Insufficient workspace size on Device!"); + + const std::size_t d_scratch_length = worksize / sizeof(std::size_t); + DataBuffer d_scratch(d_scratch_length, getDevTag(), + true); + + setWorkSpaceMemory(getTNCudaHandle(), workDesc, + reinterpret_cast(d_scratch.getData()), + worksize); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateCompute( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* int64_t * */ extentsPtr, + /* int64_t *stridesOut */ nullptr, + /* void * */ tensorPtr, + /* cudaStream_t */ getDevTag().getStreamID())); + + PL_CUTENSORNET_IS_SUCCESS( + cutensornetDestroyWorkspaceDescriptor(workDesc)); + } + + private: + /** + * @brief Get accessor of a state tensor + */ + + void get_accessor_(CFP_t *tensor_data, const std::size_t tensor_data_size, + const std::vector &projected_modes, + const std::vector &projectedModeValues, + const int32_t numHyperSamples = 1) const { cutensornetStateAccessor_t accessor; PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateAccessor( /* const cutensornetHandle_t */ getTNCudaHandle(), @@ -443,54 +530,5 @@ class TNCudaBase : public TensornetBase { cutensornetDestroyWorkspaceDescriptor(workDesc)); PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); } - - protected: - /** - * @brief Save quantumState information to data provided by a user - * - * @param tensorPtr Pointer to tensors provided by a user - */ - void computeState(int64_t **extentsPtr, void **tensorPtr) { - cutensornetWorkspaceDescriptor_t workDesc; - PL_CUTENSORNET_IS_SUCCESS( - cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); - - // TODO we assign half (magic number is) of free memory size to the - // maximum memory usage. - const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStatePrepare( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* size_t maxWorkspaceSizeDevice */ scratchSize, - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* cudaStream_t unused as of v24.03*/ 0x0)); - - std::size_t worksize = - getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); - - PL_ABORT_IF(worksize > scratchSize, - "Insufficient workspace size on Device!"); - - const std::size_t d_scratch_length = worksize / sizeof(std::size_t); - DataBuffer d_scratch(d_scratch_length, getDevTag(), - true); - - setWorkSpaceMemory(getTNCudaHandle(), workDesc, - reinterpret_cast(d_scratch.getData()), - worksize); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateCompute( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* int64_t * */ extentsPtr, - /* int64_t *stridesOut */ nullptr, - /* void * */ tensorPtr, - /* cudaStream_t */ getDevTag().getStreamID())); - - PL_CUTENSORNET_IS_SUCCESS( - cutensornetDestroyWorkspaceDescriptor(workDesc)); - } }; } // namespace Pennylane::LightningTensor::TNCuda diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index ce79ebcb16..f59406ab40 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -100,6 +100,8 @@ template class MeasurementsTNCuda { DataBuffer d_output_tensor( length, tensor_network_.getDevTag(), true); + d_output_tensor.zeroInit(); + DataBuffer d_output_probs( length, tensor_network_.getDevTag(), true); From c551afe04e37d1ffd10028968e49a0056262c081 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 13:21:13 +0000 Subject: [PATCH 126/227] udpate py layer unit tests --- pennylane_lightning/lightning_tensor/_measurements.py | 10 ++-------- tests/lightning_tensor/test_gates_and_expval.py | 6 +++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index ad8b59eeb2..72e29ed7e5 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -118,13 +118,7 @@ def probs(self, measurementprocess: MeasurementProcess): Probabilities of the supplied observable or wires """ diagonalizing_gates = measurementprocess.diagonalizing_gates() - if diagonalizing_gates: - self._tensornet.apply_operations(diagonalizing_gates) results = self._measurement_lightning.probs(measurementprocess.wires.tolist()) - if diagonalizing_gates: - self._tensornet.apply_operations( - [qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)] - ) return results def var(self, measurementprocess: MeasurementProcess): @@ -139,7 +133,7 @@ def var(self, measurementprocess: MeasurementProcess): Variance of the observable """ if isinstance(measurementprocess.obs, qml.SparseHamiltonian): - raise NotImplementedError("Sparse Hamiltonian Observables are not supported.") + raise NotImplementedError("The var measurement does not support sparse Hamiltonian observables.") if isinstance(measurementprocess.obs, qml.Hermitian): if len(measurementprocess.obs.wires) > 1: @@ -174,7 +168,7 @@ def get_measurement_function( if measurementprocess.obs is None: return self.state_diagonalizing_gates - raise NotImplementedError("Not supported measurement.") + raise NotImplementedError("Unsupported measurement type.") def measurement(self, measurementprocess: MeasurementProcess) -> TensorLike: """Apply a measurement process to a tensor network. diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index af6fce534a..001f8e4003 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -257,7 +257,7 @@ def test_var_sparseH_not_supported(self): m = LightningTensorMeasurements(tensornet) with pytest.raises( - NotImplementedError, match="Sparse Hamiltonian Observables are not supported." + NotImplementedError, match="The var measurement does not support sparse Hamiltonian observables." ): m.var(q.queue[0]) @@ -297,7 +297,7 @@ def test_measurement_shot_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs, shots=1000) m = LightningTensorMeasurements(tensornet) - with pytest.raises(NotImplementedError, match="Shots are not supported for tensor network"): + with pytest.raises(NotImplementedError, match="Shots are not supported for tensor network simulations."): m.measure_tensor_network(tape) def test_measurement_not_supported(self): @@ -308,7 +308,7 @@ def test_measurement_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs) m = LightningTensorMeasurements(tensornet) - with pytest.raises(NotImplementedError, match="Not supported measurement."): + with pytest.raises(NotImplementedError, match="Unsupported measurement type."): m.measure_tensor_network(tape) From 2968201ed6657338b9da1653007e77da4e83ec88 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 13:21:23 +0000 Subject: [PATCH 127/227] tidy up c++ layer --- .../src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index de22ca77b4..3fb96a902c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -369,21 +369,17 @@ class TNCudaBase : public TensornetBase { get_accessor_(tensor_data, tensor_data_size, projected_modes, projectedModeValues, numHyperSamples); } else { - DataBuffer tmp(tensor_data_size, getDevTag(), true); for (std::size_t idx = 0; idx < (size_t(1) << projected_modes.size()); idx++) { - // std::vector - // projectedModeValues(projected_modes.size(), 0); - for (std::size_t j = 0; j < projected_modes.size(); j++) { projectedModeValues[j] = (idx >> j) & 1; } get_accessor_(tmp.getData(), tensor_data_size, projected_modes, projectedModeValues, numHyperSamples); - + //TODO move cublascaller to the class member data SharedCublasCaller cublascaller = make_shared_cublas_caller(); // Copy the data to the output tensor scaleAndAddC_CUDA(std::complex{1.0, 0.0}, From 1181d5f4837a2587b4d410ddd578ac0a80bda73b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 13:22:54 +0000 Subject: [PATCH 128/227] make format --- .../src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- pennylane_lightning/lightning_tensor/_measurements.py | 4 +++- tests/lightning_tensor/test_gates_and_expval.py | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 3fb96a902c..da65a3b43d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -379,7 +379,7 @@ class TNCudaBase : public TensornetBase { get_accessor_(tmp.getData(), tensor_data_size, projected_modes, projectedModeValues, numHyperSamples); - //TODO move cublascaller to the class member data + // TODO move cublascaller to the class member data SharedCublasCaller cublascaller = make_shared_cublas_caller(); // Copy the data to the output tensor scaleAndAddC_CUDA(std::complex{1.0, 0.0}, diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 72e29ed7e5..20149ccb11 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -133,7 +133,9 @@ def var(self, measurementprocess: MeasurementProcess): Variance of the observable """ if isinstance(measurementprocess.obs, qml.SparseHamiltonian): - raise NotImplementedError("The var measurement does not support sparse Hamiltonian observables.") + raise NotImplementedError( + "The var measurement does not support sparse Hamiltonian observables." + ) if isinstance(measurementprocess.obs, qml.Hermitian): if len(measurementprocess.obs.wires) > 1: diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index 001f8e4003..644185797b 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -257,7 +257,8 @@ def test_var_sparseH_not_supported(self): m = LightningTensorMeasurements(tensornet) with pytest.raises( - NotImplementedError, match="The var measurement does not support sparse Hamiltonian observables." + NotImplementedError, + match="The var measurement does not support sparse Hamiltonian observables.", ): m.var(q.queue[0]) @@ -297,7 +298,9 @@ def test_measurement_shot_not_supported(self): tape = qml.tape.QuantumScript(measurements=obs, shots=1000) m = LightningTensorMeasurements(tensornet) - with pytest.raises(NotImplementedError, match="Shots are not supported for tensor network simulations."): + with pytest.raises( + NotImplementedError, match="Shots are not supported for tensor network simulations." + ): m.measure_tensor_network(tape) def test_measurement_not_supported(self): From 41ff2626a744be47fe9c299460a70ebc907882f7 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 13:24:22 +0000 Subject: [PATCH 129/227] update python layer --- pennylane_lightning/lightning_tensor/_measurements.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 20149ccb11..193b9fb570 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -117,7 +117,6 @@ def probs(self, measurementprocess: MeasurementProcess): Returns: Probabilities of the supplied observable or wires """ - diagonalizing_gates = measurementprocess.diagonalizing_gates() results = self._measurement_lightning.probs(measurementprocess.wires.tolist()) return results From 48df242155dc0edc1473b9525bd2abf8ccc8197a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 13:37:54 +0000 Subject: [PATCH 130/227] move cublascaller to tncudabase class --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 21 ++++++++++++------- .../measurements/MeasurementsTNCuda.hpp | 6 ++---- .../observables/ObservablesTNCudaOperator.hpp | 12 +++++++---- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index da65a3b43d..8b7d7566d7 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -60,6 +60,7 @@ class TNCudaBase : public TensornetBase { using ComplexT = std::complex; using BaseType = TensornetBase; SharedTNCudaHandle handle_; + SharedCublasCaller cublascaller_; cudaDataType_t typeData_; DevTag dev_tag_; cutensornetComputeType_t typeCompute_; @@ -78,6 +79,7 @@ class TNCudaBase : public TensornetBase { explicit TNCudaBase(const std::size_t numQubits, int device_id = 0, cudaStream_t stream_id = 0) : BaseType(numQubits), handle_(make_shared_tncuda_handle()), + cublascaller_(make_shared_cublas_caller()), dev_tag_({device_id, stream_id}), gate_cache_(std::make_shared>(dev_tag_)) { // TODO this code block could be moved to base class and need to revisit @@ -105,7 +107,7 @@ class TNCudaBase : public TensornetBase { // runtime in the C++ layer explicit TNCudaBase(const std::size_t numQubits, DevTag dev_tag) : BaseType(numQubits), handle_(make_shared_tncuda_handle()), - dev_tag_(dev_tag), + cublascaller_(make_shared_cublas_caller()), dev_tag_(dev_tag), gate_cache_(std::make_shared>(dev_tag_)) { // TODO this code block could be moved to base class and need to revisit // when working on copy ctor @@ -150,6 +152,15 @@ class TNCudaBase : public TensornetBase { return handle_.get(); } + /** + * @brief Access the CublasCaller the object is using. + * + * @return a reference to the object's CublasCaller object. + */ + auto getCublasCaller() const -> const CublasCaller & { + return *cublascaller_; + } + /** * @brief Get the quantum state pointer. * @@ -379,13 +390,11 @@ class TNCudaBase : public TensornetBase { get_accessor_(tmp.getData(), tensor_data_size, projected_modes, projectedModeValues, numHyperSamples); - // TODO move cublascaller to the class member data - SharedCublasCaller cublascaller = make_shared_cublas_caller(); // Copy the data to the output tensor scaleAndAddC_CUDA(std::complex{1.0, 0.0}, tmp.getData(), tensor_data, tmp.getLength(), getDevTag().getDeviceID(), - getDevTag().getStreamID(), *cublascaller); + getDevTag().getStreamID(), getCublasCaller()); } } } @@ -516,11 +525,9 @@ class TNCudaBase : public TensornetBase { CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; - SharedCublasCaller cublascaller = make_shared_cublas_caller(); - scaleC_CUDA(scale_scalar_cu, tensor_data, tensor_data_size, getDevTag().getDeviceID(), - getDevTag().getStreamID(), *cublascaller); + getDevTag().getStreamID(), getCublasCaller()); PL_CUTENSORNET_IS_SUCCESS( cutensornetDestroyWorkspaceDescriptor(workDesc)); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index f59406ab40..849e329387 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -13,7 +13,7 @@ // limitations under the License. /** - * @file + * @file MeasurementsTNCuda.hpp * Defines a class for the measurement of observables in quantum states * represented by a Lightning Tensor class. */ @@ -113,14 +113,12 @@ template class MeasurementsTNCuda { length, static_cast(thread_per_block), tensor_network_.getDevTag().getStreamID()); - SharedCublasCaller cublascaller = make_shared_cublas_caller(); - PrecisionT sum; asum_CUDA_device(d_output_probs.getData(), length, tensor_network_.getDevTag().getDeviceID(), tensor_network_.getDevTag().getStreamID(), - *cublascaller, &sum); + tensor_network_.getCublasCaller(), &sum); // TODO : Check if sum is zero and return h_res if (sum == 0.0) { diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp index 62aabc360c..45018d41e3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/observables/ObservablesTNCudaOperator.hpp @@ -12,6 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +/** + * @file ObservablesTNCudaOperator.hpp + * Class for appending a ObservablesTNCuda object to a tensor network object. + */ + #pragma once #include @@ -380,8 +385,6 @@ template class ObservableTNCudaOperator { */ void initHelper_var_(const TensorNetT &tensor_network, ObservableTNCuda &obs) { - SharedCublasCaller cublascaller = make_shared_cublas_caller(); - // convert obs modes to cutensornet compatible format/order vector3D modes; for (std::size_t term_idx = 0; term_idx < numObsTerms_; term_idx++) { @@ -430,8 +433,9 @@ template class ObservableTNCudaOperator { if (metaDataArr.size() == 1) { obsKey = std::move(add_meta_data_(metaDataArr[0])); } else if (metaDataArr.size() == 2) { - obsKey = std::move(add_meta_data_( - metaDataArr[0], metaDataArr[1], *cublascaller)); + obsKey = std::move( + add_meta_data_(metaDataArr[0], metaDataArr[1], + tensor_network.getCublasCaller())); } else { PL_ABORT("Only one wire observables are supported " "for cutensornet v24.03"); From 75fa671cf56cf80d3a7b5339b0dd012dfc076e5e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 7 Aug 2024 21:26:00 +0000 Subject: [PATCH 131/227] add `qml.prob(obs)` support --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 22 +++++++++---------- .../lightning_tensor/tncuda/TNCudaBase.hpp | 16 ++++++++++++++ .../tncuda/gates/TNCudaGateCache.hpp | 9 ++++++++ .../gates/tests/Test_MPSTNCuda_NonParam.cpp | 7 ++++++ .../lightning_tensor/_measurements.py | 13 ++++++++++- .../lightning_tensor/_tensornet.py | 10 ++++++--- tests/new_api/test_device.py | 15 +++---------- 7 files changed, 64 insertions(+), 28 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index ff5542c473..1559ca0388 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -62,7 +62,6 @@ class MPSTNCuda final : public TNCudaBase> { using BaseType = TNCudaBase; MPSStatus MPSInitialized_ = MPSStatus::MPSInitNotSet; - MPSStatus MPSFinalized_ = MPSStatus::MPSFinalizedNotSet; const std::size_t maxBondDim_; @@ -215,17 +214,14 @@ class MPSTNCuda final : public TNCudaBase> { */ void append_mps_final_state(double cutoff = 0, std::string cutoff_mode = "abs") { - if (MPSFinalized_ == MPSStatus::MPSFinalizedNotSet) { - MPSFinalized_ = MPSStatus::MPSFinalizedSet; - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateFinalizeMPS( - /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), - /* cutensornetState_t */ BaseType::getQuantumState(), - /* cutensornetBoundaryCondition_t */ - CUTENSORNET_BOUNDARY_CONDITION_OPEN, - /* const int64_t *const extentsOut[] */ - getSitesExtentsPtr().data(), - /*strides=*/nullptr)); - } + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateFinalizeMPS( + /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), + /* cutensornetState_t */ BaseType::getQuantumState(), + /* cutensornetBoundaryCondition_t */ + CUTENSORNET_BOUNDARY_CONDITION_OPEN, + /* const int64_t *const extentsOut[] */ + getSitesExtentsPtr().data(), + /*strides=*/nullptr)); // Optional: SVD cutensornetTensorSVDAlgo_t algo = @@ -257,6 +253,8 @@ class MPSTNCuda final : public TNCudaBase> { BaseType::computeState( const_cast(getSitesExtentsPtr().data()), reinterpret_cast(getTensorsOutDataPtr().data())); + + BaseType::dummy_tensor_update(); } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index d41f1fd44f..c9b2224dc7 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -305,6 +305,22 @@ class TNCudaBase : public TensornetBase { /* int32_t unitary*/ 1)); } + void dummy_tensor_update() { + if (gate_cache_->get_cache_size() == 0) { + applyOperation("Identity", {0}, false); + } + int64_t id = gate_cache_->get_cache_head_idx(); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* int64_t tensorId*/ id, + /* void* */ + static_cast( + gate_cache_->get_gate_device_ptr(static_cast(id))), + /* int32_t unitary*/ 1)); + } + /** * @brief Get the full state tensor * diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp index ba15c458cf..7302cf3459 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp @@ -157,6 +157,15 @@ template class TNCudaGateCache { return device_gates_.at(gate_id).second.getDataBuffer().getData(); } + auto get_cache_head_idx() const -> std::size_t { + auto it = device_gates_.begin(); + std::size_t idx; + idx = it->first; + return idx; + } + + auto get_cache_size() const -> std::size_t { return device_gates_.size(); } + private: const DevTag device_tag_; std::size_t total_alloc_bytes_; diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp index 5044e5b8db..0bacdcbf9b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp @@ -75,6 +75,13 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, MPSTNCuda mps_state{num_qubits, maxExtent, dev_tag}; mps_state.applyOperation("Hadamard", {index}, inverse); + + mps_state.append_mps_final_state(); + + mps_state.applyOperation("Identity", {index}, inverse); + + mps_state.append_mps_final_state(); + cp_t expected(1.0 / std::sqrt(2), 0); auto results = mps_state.getDataVector(); diff --git a/pennylane_lightning/lightning_tensor/_measurements.py b/pennylane_lightning/lightning_tensor/_measurements.py index 193b9fb570..93ab53e506 100644 --- a/pennylane_lightning/lightning_tensor/_measurements.py +++ b/pennylane_lightning/lightning_tensor/_measurements.py @@ -80,10 +80,12 @@ def state_diagonalizing_gates(self, measurementprocess: StateMeasurement) -> Ten """ diagonalizing_gates = measurementprocess.diagonalizing_gates() self._tensornet.apply_operations(diagonalizing_gates) + self._tensornet.appendMPSFinalState() state_array = self._tensornet.state wires = Wires(range(self._tensornet.num_wires)) result = measurementprocess.process_state(state_array, wires) self._tensornet.apply_operations([qml.adjoint(g) for g in reversed(diagonalizing_gates)]) + self._tensornet.appendMPSFinalState() return result # pylint: disable=protected-access @@ -117,7 +119,16 @@ def probs(self, measurementprocess: MeasurementProcess): Returns: Probabilities of the supplied observable or wires """ + diagonalizing_gates = measurementprocess.diagonalizing_gates() + if diagonalizing_gates: + self._tensornet.apply_operations(diagonalizing_gates) + self._tensornet.appendMPSFinalState() results = self._measurement_lightning.probs(measurementprocess.wires.tolist()) + if diagonalizing_gates: + self._tensornet.apply_operations( + [qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)] + ) + self._tensornet.appendMPSFinalState() return results def var(self, measurementprocess: MeasurementProcess): @@ -166,7 +177,7 @@ def get_measurement_function( if isinstance(measurementprocess, ProbabilityMP): return self.probs - if measurementprocess.obs is None: + if measurementprocess.obs is None or measurementprocess.obs.has_diagonalizing_gates: return self.state_diagonalizing_gates raise NotImplementedError("Unsupported measurement type.") diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 88c414f4eb..14afbeac0a 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -191,10 +191,14 @@ def set_tensor_network(self, circuit: QuantumScript): Args: circuit (QuantumScript): The single circuit to simulate - - Returns: - LightningTensorNet: Lightning final state class. """ self.apply_operations(circuit.operations) + self.appendMPSFinalState() + + def appendMPSFinalState(self): + """ + Append the final state to the tensor network for the MPS backend. This is an function to be called + by once apply_operations is called. + """ if self._method == "mps": self._tensornet.appendMPSFinalState(self._cutoff, self._cutoff_mode) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index d861849ca0..06bf9bae1e 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -414,6 +414,8 @@ def test_preprocess_state_prep_middle_op_decomposition(self, op, decomp_depth): ] if device_name != "lightning.tensor" else [ + qml.probs(wires=[1, 2]), + qml.probs(op=qml.X(2)), qml.expval(qml.Z(2)), qml.var(qml.X(2)), qml.expval(qml.X(0) + qml.Z(0)), @@ -448,17 +450,12 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): "mp1", ( [ + qml.probs(op=qml.X(2)), qml.probs(wires=[1, 2]), qml.expval(qml.Z(2)), qml.var(qml.X(2)), qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), ] - if device_name != "lightning.tensor" - else [ - qml.expval(qml.Z(2)), - qml.var(qml.X(2)), - qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), - ] ), ) @pytest.mark.parametrize( @@ -470,12 +467,6 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): qml.var(qml.Y(2)), qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), ] - if device_name != "lightning.tensor" - else [ - qml.expval(qml.Y(2)), - qml.var(qml.Y(2)), - qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), - ] ), ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): From b8e1bb02e78fd78455e91e8ade86849e43ad4338 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 8 Aug 2024 15:09:03 +0000 Subject: [PATCH 132/227] initial commit --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 22 +++++++++---------- .../lightning_tensor/tncuda/TNCudaBase.hpp | 21 ++++++++++++++++++ .../tncuda/gates/TNCudaGateCache.hpp | 18 +++++++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index e6754f92f2..577401c403 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -62,7 +62,6 @@ class MPSTNCuda final : public TNCudaBase> { using BaseType = TNCudaBase; MPSStatus MPSInitialized_ = MPSStatus::MPSInitNotSet; - MPSStatus MPSFinalized_ = MPSStatus::MPSFinalizedNotSet; const std::size_t maxBondDim_; @@ -215,17 +214,14 @@ class MPSTNCuda final : public TNCudaBase> { */ void append_mps_final_state(double cutoff = 0, std::string cutoff_mode = "abs") { - if (MPSFinalized_ == MPSStatus::MPSFinalizedNotSet) { - MPSFinalized_ = MPSStatus::MPSFinalizedSet; - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateFinalizeMPS( - /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), - /* cutensornetState_t */ BaseType::getQuantumState(), - /* cutensornetBoundaryCondition_t */ - CUTENSORNET_BOUNDARY_CONDITION_OPEN, - /* const int64_t *const extentsOut[] */ - getSitesExtentsPtr().data(), - /*strides=*/nullptr)); - } + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateFinalizeMPS( + /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), + /* cutensornetState_t */ BaseType::getQuantumState(), + /* cutensornetBoundaryCondition_t */ + CUTENSORNET_BOUNDARY_CONDITION_OPEN, + /* const int64_t *const extentsOut[] */ + getSitesExtentsPtr().data(), + /*strides=*/nullptr)); // Optional: SVD cutensornetTensorSVDAlgo_t algo = @@ -257,6 +253,8 @@ class MPSTNCuda final : public TNCudaBase> { BaseType::computeState( const_cast(getSitesExtentsPtr().data()), reinterpret_cast(getTensorsOutDataPtr().data())); + + //this->apply_dummy_operator_update(); } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index ea21984a39..657a8e732a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -294,6 +294,27 @@ class TNCudaBase : public TensornetBase { } protected: + /** + * @brief Dummy update of the first tensor operators in the gate cache to + * enable applyOperation/applyOperations calls after calling MPSFinalize. + */ + void apply_dummy_operator_update() { + // If the cache is empty, add an identity gate + if (gate_cache_->get_cache_size() == 0) { + applyOperation("Identity", {0}, false); + } + int64_t id = gate_cache_->get_cache_head_idx(); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* int64_t tensorId*/ id, + /* void* */ + static_cast( + gate_cache_->get_gate_device_ptr(static_cast(id))), + /* int32_t unitary*/ 1)); + } + /** * @brief Save quantumState information to data provided by a user * diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp index ba15c458cf..f848cf446e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp @@ -157,6 +157,24 @@ template class TNCudaGateCache { return device_gates_.at(gate_id).second.getDataBuffer().getData(); } + /** + * @brief Returns the first element of gate cache. + * + * @return std::size_t The id of gate tensor operator in the computate + * graph. + */ + auto get_cache_head_idx() const -> std::size_t { + PL_ABORT_IF(device_gates_.empty(), "Gate cache is empty."); + return device_gates_.begin()->first; + } + + /** + * @brief Returns the size of gate cache. + * + * @return std::size_t The size of gate cache. + */ + auto get_cache_size() const -> std::size_t { return device_gates_.size(); } + private: const DevTag device_tag_; std::size_t total_alloc_bytes_; From 29c43c38e4e078a87f24256e58a645cb76568475 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 8 Aug 2024 15:11:13 +0000 Subject: [PATCH 133/227] Auto update version from '0.38.0-dev26' to '0.38.0-dev27' --- 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 444de99a58..974470cd4e 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.38.0-dev26" +__version__ = "0.38.0-dev27" From 1c69f8fc3c9eafbb669b594f8afe961e0df1a43b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 8 Aug 2024 15:19:23 +0000 Subject: [PATCH 134/227] revert some changes --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 22 ++++++++++--------- .../lightning_tensor/tncuda/TNCudaBase.hpp | 21 ------------------ .../tncuda/gates/TNCudaGateCache.hpp | 18 --------------- 3 files changed, 12 insertions(+), 49 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 3ae54fa1b1..ff5542c473 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -62,6 +62,7 @@ class MPSTNCuda final : public TNCudaBase> { using BaseType = TNCudaBase; MPSStatus MPSInitialized_ = MPSStatus::MPSInitNotSet; + MPSStatus MPSFinalized_ = MPSStatus::MPSFinalizedNotSet; const std::size_t maxBondDim_; @@ -214,14 +215,17 @@ class MPSTNCuda final : public TNCudaBase> { */ void append_mps_final_state(double cutoff = 0, std::string cutoff_mode = "abs") { - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateFinalizeMPS( - /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), - /* cutensornetState_t */ BaseType::getQuantumState(), - /* cutensornetBoundaryCondition_t */ - CUTENSORNET_BOUNDARY_CONDITION_OPEN, - /* const int64_t *const extentsOut[] */ - getSitesExtentsPtr().data(), - /*strides=*/nullptr)); + if (MPSFinalized_ == MPSStatus::MPSFinalizedNotSet) { + MPSFinalized_ = MPSStatus::MPSFinalizedSet; + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateFinalizeMPS( + /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), + /* cutensornetState_t */ BaseType::getQuantumState(), + /* cutensornetBoundaryCondition_t */ + CUTENSORNET_BOUNDARY_CONDITION_OPEN, + /* const int64_t *const extentsOut[] */ + getSitesExtentsPtr().data(), + /*strides=*/nullptr)); + } // Optional: SVD cutensornetTensorSVDAlgo_t algo = @@ -253,8 +257,6 @@ class MPSTNCuda final : public TNCudaBase> { BaseType::computeState( const_cast(getSitesExtentsPtr().data()), reinterpret_cast(getTensorsOutDataPtr().data())); - - //this->apply_dummy_operator_update(); } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 47f2a69501..07d2286e90 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -441,27 +441,6 @@ class TNCudaBase : public TensornetBase { } protected: - /** - * @brief Dummy update of the first tensor operators in the gate cache to - * enable applyOperation/applyOperations calls after calling MPSFinalize. - */ - void apply_dummy_operator_update() { - // If the cache is empty, add an identity gate - if (gate_cache_->get_cache_size() == 0) { - applyOperation("Identity", {0}, false); - } - int64_t id = gate_cache_->get_cache_head_idx(); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* int64_t tensorId*/ id, - /* void* */ - static_cast( - gate_cache_->get_gate_device_ptr(static_cast(id))), - /* int32_t unitary*/ 1)); - } - /** * @brief Save quantumState information to data provided by a user * diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp index f848cf446e..ba15c458cf 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp @@ -157,24 +157,6 @@ template class TNCudaGateCache { return device_gates_.at(gate_id).second.getDataBuffer().getData(); } - /** - * @brief Returns the first element of gate cache. - * - * @return std::size_t The id of gate tensor operator in the computate - * graph. - */ - auto get_cache_head_idx() const -> std::size_t { - PL_ABORT_IF(device_gates_.empty(), "Gate cache is empty."); - return device_gates_.begin()->first; - } - - /** - * @brief Returns the size of gate cache. - * - * @return std::size_t The size of gate cache. - */ - auto get_cache_size() const -> std::size_t { return device_gates_.size(); } - private: const DevTag device_tag_; std::size_t total_alloc_bytes_; From 486d5f2e691ff092be45eb99485fa09bd91ccc9b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 14:21:46 +0000 Subject: [PATCH 135/227] resolve python layer comments --- .../lightning_tensor/test_gates_and_expval.py | 2 +- tests/new_api/test_device.py | 33 +++++++------------ 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index d1955dc2d2..644185797b 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -305,7 +305,7 @@ def test_measurement_shot_not_supported(self): def test_measurement_not_supported(self): """Test error for measure_tensor_network.""" - obs = [qml.sample(wires=[0])] + obs = [qml.sample(wires=0)] tensornet = LightningTensorNet(4, 10) tape = qml.tape.QuantumScript(measurements=obs) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index fb3d4fef45..4eb3a9e0fb 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -22,6 +22,7 @@ from conftest import PHI, THETA, VARPHI, LightningDevice, device_name from pennylane.devices import DefaultExecutionConfig, DefaultQubit, ExecutionConfig, MCMConfig from pennylane.devices.default_qubit import adjoint_ops +from pennylane.measurements import ProbabilityMP from pennylane.tape import QuantumScript if device_name == "lightning.qubit": @@ -412,20 +413,16 @@ def test_preprocess_state_prep_middle_op_decomposition(self, op, decomp_depth): ), qml.expval(qml.Projector([1], wires=2)), ] - if device_name != "lightning.tensor" - else [ - qml.expval(qml.Z(2)), - qml.var(qml.X(2)), - qml.expval(qml.X(0) + qml.Z(0)), - qml.expval(qml.Hamiltonian([-0.5, 1.5], [qml.Y(1), qml.X(1)])), - qml.expval(2.5 * qml.Z(0)), - qml.expval(qml.Z(0) @ qml.X(1)), - qml.expval(qml.operation.Tensor(qml.Z(0), qml.X(1))), - ] ), ) def test_execute_single_measurement(self, theta, phi, mp, dev): """Test that execute returns the correct results with a single measurement.""" + if device_name == "lightning.tensor": + if isinstance(mp.obs, qml.SparseHamiltonian) or isinstance(mp.obs, qml.Projector): + pytest.skip("SparseHamiltonian/Projector obs not supported in lightning.tensor") + if isinstance(mp, ProbabilityMP): + pytest.skip("qml.probs() not supported in lightning.tensor") + if isinstance(mp.obs, qml.ops.LinearCombination) and not qml.operation.active_new_opmath(): mp.obs = qml.operation.convert_to_legacy_H(mp.obs) @@ -453,12 +450,6 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): qml.var(qml.X(2)), qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), ] - if device_name != "lightning.tensor" - else [ - qml.expval(qml.Z(2)), - qml.var(qml.X(2)), - qml.var(qml.Hermitian(qml.Hadamard.compute_matrix(), 0)), - ] ), ) @pytest.mark.parametrize( @@ -470,16 +461,14 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): qml.var(qml.Y(2)), qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), ] - if device_name != "lightning.tensor" - else [ - qml.expval(qml.Y(2)), - qml.var(qml.Y(2)), - qml.expval(qml.Hamiltonian([-0.5, 1.5, -1.1], [qml.Y(1), qml.X(1), qml.Z(0)])), - ] ), ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): """Test that execute returns the correct results with multiple measurements.""" + if device_name == "lightning.tensor": + if isinstance(mp1, ProbabilityMP) or isinstance(mp2, ProbabilityMP): + pytest.skip("qml.probs() not supported in lightning.tensor") + if isinstance(mp2.obs, qml.ops.LinearCombination) and not qml.operation.active_new_opmath(): mp2.obs = qml.operation.convert_to_legacy_H(mp2.obs) From c7a27c584c176707db6e05cc52e4585352ae0d60 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 14:27:20 +0000 Subject: [PATCH 136/227] update frontend --- .github/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 9b3997838b..785da3cf7c 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `qml.state()` support to `lightning.tensor`. +* Add `qml.state()` measurement support to `lightning.tensor`. [(#827)](https://github.com/PennyLaneAI/pennylane-lightning/pull/827) * Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs**2` and this implementation scales `O(num_obs**2)`. From 2ef61c1d0152b5d44984c37ef0d65844920d1ac5 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 15:36:08 +0000 Subject: [PATCH 137/227] add cudaStreamSynchronize() --- .../core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 07d2286e90..090493890c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -425,6 +425,8 @@ class TNCudaBase : public TensornetBase { /* void *stateNorm */ static_cast(&stateNorm2), /* cudaStream_t cudaStream */ 0x0)); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); + ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; From a84a5c85bf94dd20f24ef824f80f374abc32f890 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 15:56:09 +0000 Subject: [PATCH 138/227] add more unit tests for 0,1 qubit circuit --- .../simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 5 +++++ .../lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 090493890c..aded5d89a4 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -82,6 +82,9 @@ class TNCudaBase : public TensornetBase { gate_cache_(std::make_shared>(dev_tag_)) { // TODO this code block could be moved to base class and need to revisit // when working on copy ctor + PL_ABORT_IF(numQubits < 2, + "The number of qubits should be greater than 1."); + if constexpr (std::is_same_v) { typeData_ = CUDA_C_64F; typeCompute_ = CUTENSORNET_COMPUTE_64F; @@ -109,6 +112,8 @@ class TNCudaBase : public TensornetBase { gate_cache_(std::make_shared>(dev_tag_)) { // TODO this code block could be moved to base class and need to revisit // when working on copy ctor + PL_ABORT_IF(numQubits < 2, + "The number of qubits should be greater than 1."); if constexpr (std::is_same_v) { typeData_ = CUDA_C_64F; typeCompute_ = CUTENSORNET_COMPUTE_64F; diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index 2eb361f2cf..6071bb743c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -190,4 +190,15 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { Catch::Matchers::Contains( "State tensor size exceeds the available GPU memory!")); } + + SECTION("Throw error for 0 an 1 qubit circuit") { + std::size_t num_qubits = GENERATE(0, 1); + std::size_t maxBondDim = 2; + DevTag dev_tag{0, 0}; + + REQUIRE_THROWS_WITH( + MPSTNCuda(num_qubits, maxBondDim, dev_tag), + Catch::Matchers::Contains( + "The number of qubits should be greater than 1.")); + } } From 377b6deb7834bf731626f7f6f08194ade20b23c0 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 16:01:01 +0000 Subject: [PATCH 139/227] update docstring --- .../src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index aded5d89a4..ba8a12b8d2 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -300,7 +300,7 @@ class TNCudaBase : public TensornetBase { } /** - * @brief Get the full state tensor + * @brief Get the state vector representation of a tensor network. * * @param numHyperSamples Number of hyper samples to use in the calculation * and is default as 1. @@ -315,7 +315,7 @@ class TNCudaBase : public TensornetBase { } /** - * @brief Get a slice of the state tensor + * @brief Get the state vector representation of a tensor network. * * @param wires Wires to get the state tensor for. * @param numHyperSamples Number of hyper samples to use in the calculation From 4938835a2371cb8525052543af397dd623fb5b9f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 16:26:37 +0000 Subject: [PATCH 140/227] add more py unit tests and avoid data copy in the pybind layer --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 25 +++++++++++++++++++ .../tncuda/bindings/LTensorTNCudaBindings.hpp | 7 ++---- .../lightning_tensor/_tensornet.py | 3 +++ .../lightning_tensor/test_tensornet_class.py | 13 +++++++--- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index ba8a12b8d2..000af642dd 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -343,6 +343,31 @@ class TNCudaBase : public TensornetBase { return h_res; } + /** + * @brief Get the state vector representation of a tensor network. + * + * @param host_data Pointer to the host memory for state tensor data. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is default as 1. + */ + void get_state_tensor(ComplexT *host_data, + const int32_t numHyperSamples = 1) { + std::vector wires(BaseType::getNumQubits()); + std::iota(wires.begin(), wires.end(), 0); + + const std::size_t length = std::size_t{1} << wires.size(); + + PL_ABORT_IF(length * sizeof(CFP_t) >= getFreeMemorySize(), + "State tensor size exceeds the available GPU memory!"); + + DataBuffer d_output_tensor(length, getDevTag(), true); + + get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), + wires, numHyperSamples); + + d_output_tensor.CopyGpuDataToHost(host_data, length); + } + /** * @brief Get a slice of the state tensor * diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index aedca37728..ea5c27192e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -70,11 +70,8 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { py::buffer_info numpyArrayInfo = state.request(); auto *data_ptr = static_cast *>(numpyArrayInfo.ptr); - if (state.size()) { - auto &&state_tensor = tensor_network.getDataVector(); - std::copy(state_tensor.begin(), state_tensor.end(), - data_ptr); - } + + tensor_network.get_state_tensor(data_ptr); }, "Copy StateVector data into a Numpy array.") .def( diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 88c414f4eb..1b3ddb8034 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -67,6 +67,9 @@ def __init__( if device_name != "lightning.tensor": raise DeviceError(f'The device name "{device_name}" is not a valid option.') + if num_wires < 2: + raise ValueError("Number of wires must be greater than 1.") + self._device_name = device_name self._tensornet = self._tensornet_dtype()(self._num_wires, self._max_bond_dim) diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index 9e2113fb2d..e25e5336b1 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -39,10 +39,15 @@ @pytest.mark.parametrize("device_name", ["lightning.tensor"]) def test_device_name_and_init(num_wires, bondDims, dtype, device_name): """Test the class initialization and returned properties.""" - tensornet = LightningTensorNet(num_wires, bondDims, c_dtype=dtype, device_name=device_name) - assert tensornet.dtype == dtype - assert tensornet.device_name == device_name - assert tensornet.num_wires == num_wires + if num_wires < 2: + with pytest.raises(ValueError, match="Number of wires must be greater than 1."): + LightningTensorNet(num_wires, bondDims, c_dtype=dtype, device_name=device_name) + return + else: + tensornet = LightningTensorNet(num_wires, bondDims, c_dtype=dtype, device_name=device_name) + assert tensornet.dtype == dtype + assert tensornet.device_name == device_name + assert tensornet.num_wires == num_wires def test_wrong_device_name(): From 4ab9999d5180e59887f0320df6bac754e03e9694 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 17:00:52 +0000 Subject: [PATCH 141/227] remove cudaStreamSync --- .../core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 000af642dd..ceca059ebf 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -455,7 +455,7 @@ class TNCudaBase : public TensornetBase { /* void *stateNorm */ static_cast(&stateNorm2), /* cudaStream_t cudaStream */ 0x0)); - PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); + //PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; From e95456b83dd1d466d0acd5597eb2716e5d61bdda Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 18:44:55 +0000 Subject: [PATCH 142/227] decprecate `getDataVector()` --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 19 ++- .../lightning_tensor/tncuda/TNCudaBase.hpp | 51 +----- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 2 +- .../gates/tests/Test_MPSTNCuda_NonParam.cpp | 77 +++++++-- .../gates/tests/Test_MPSTNCuda_Param.cpp | 149 +++++++++++++----- .../tncuda/tests/Tests_MPSTNCuda.cpp | 43 +++-- 6 files changed, 219 insertions(+), 122 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index ff5542c473..ded75dc230 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -261,13 +261,22 @@ class MPSTNCuda final : public TNCudaBase> { /** * @brief Get the full state vector representation of a MPS quantum state. + * Note that users/developers should be responsible to ensure that there is + * sufficient memory on the host to store the full state vector. * - * - * @return std::vector Full state vector representation of MPS - * quantum state on host + * @param res Pointer to the host memory to store the full state vector + * @param res_length Length of the result vector */ - auto getDataVector() -> std::vector { - return BaseType::get_state_tensor(); + void getData(ComplexT *res, const std::size_t res_length) { + PL_ABORT_IF(log2(res_length) != BaseType::getNumQubits(), + "The size of the result vector should be equal to the " + "dimension of the quantum state."); + + std::size_t avail_gpu_memory = getFreeMemorySize(); + + PL_ABORT_IF(log2(avail_gpu_memory) < BaseType::getNumQubits(), + "State tensor size exceeds the available GPU memory!"); + this->get_state_tensor(res); } private: diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index ceca059ebf..5139db25ee 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -299,50 +299,7 @@ class TNCudaBase : public TensornetBase { /* int32_t unitary*/ 1)); } - /** - * @brief Get the state vector representation of a tensor network. - * - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. - * - * @return Full the state tensor on the host memory - */ - auto get_state_tensor(const int32_t numHyperSamples = 1) - -> std::vector { - std::vector wires(BaseType::getNumQubits()); - std::iota(wires.begin(), wires.end(), 0); - return get_state_tensor(wires, numHyperSamples); - } - - /** - * @brief Get the state vector representation of a tensor network. - * - * @param wires Wires to get the state tensor for. - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. - * - * @return A slice of the state tensor on the host memory - */ - auto get_state_tensor(const std::vector &wires, - const int32_t numHyperSamples = 1) - -> std::vector { - const std::size_t length = std::size_t{1} << wires.size(); - - PL_ABORT_IF(length * sizeof(CFP_t) >= getFreeMemorySize(), - "State tensor size exceeds the available GPU memory!"); - - DataBuffer d_output_tensor(length, getDevTag(), true); - - std::vector h_res(length); - - get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), - wires, numHyperSamples); - - d_output_tensor.CopyGpuDataToHost(h_res.data(), h_res.size()); - - return h_res; - } - + protected: /** * @brief Get the state vector representation of a tensor network. * @@ -357,9 +314,6 @@ class TNCudaBase : public TensornetBase { const std::size_t length = std::size_t{1} << wires.size(); - PL_ABORT_IF(length * sizeof(CFP_t) >= getFreeMemorySize(), - "State tensor size exceeds the available GPU memory!"); - DataBuffer d_output_tensor(length, getDevTag(), true); get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), @@ -455,7 +409,7 @@ class TNCudaBase : public TensornetBase { /* void *stateNorm */ static_cast(&stateNorm2), /* cudaStream_t cudaStream */ 0x0)); - //PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; @@ -472,7 +426,6 @@ class TNCudaBase : public TensornetBase { PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); } - protected: /** * @brief Save quantumState information to data provided by a user * diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index ea5c27192e..5dd6efe701 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -71,7 +71,7 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { auto *data_ptr = static_cast *>(numpyArrayInfo.ptr); - tensor_network.get_state_tensor(data_ptr); + tensor_network.getData(data_ptr, state.size()); }, "Copy StateVector data into a Numpy array.") .def( diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp index 5044e5b8db..9758e6ab4f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp @@ -51,7 +51,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Identity", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Identity", {index}, inverse); cp_t expected(1.0 / std::sqrt(2), 0); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(expected.real() == Approx(results[0b1 << ((num_qubits - 1 - index))].real())); @@ -77,7 +80,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Hadamard", {index}, inverse); cp_t expected(1.0 / std::sqrt(2), 0); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(expected.real() == Approx(results[0b1 << ((num_qubits - 1 - index))].real())); @@ -89,6 +95,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliX", "[MPSTNCuda_Nonparam]", float, double) { + using cp_t = std::complex; const bool inverse = GENERATE(false, true); { std::size_t num_qubits = 3; @@ -101,7 +108,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliX", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("PauliX", {index}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results[0] == cuUtil::ZERO>()); CHECK(results[0b1 << (num_qubits - index - 1)] == @@ -139,7 +149,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("PauliY", {index}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -173,7 +186,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliZ", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("PauliZ", {index}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -211,7 +227,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::S", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("S", {index}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -248,7 +267,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::T", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("T", {index}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -259,6 +281,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CNOT", "[MPSTNCuda_Nonparam]", float, double) { const bool inverse = GENERATE(false, true); { + using cp_t = std::complex; std::size_t num_qubits = 3; std::size_t maxExtent = 2; DevTag dev_tag{0, 0}; @@ -270,7 +293,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CNOT", "[MPSTNCuda_Nonparam]", float, {{0}, {0, 1}, {1, 2}}, {false, inverse, inverse}); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results.front() == cuUtil::INVSQRT2>()); @@ -283,7 +309,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CNOT", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Hadamard", {0}, false); mps_state.applyOperation("CNOT", {0, 2}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results[0] == cuUtil::INVSQRT2>()); CHECK(results[5] == cuUtil::INVSQRT2>()); @@ -317,7 +346,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SWAP", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("SWAP", {0, 1}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected)); } @@ -339,7 +371,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SWAP", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("SWAP", {0, 2}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected)); } @@ -373,7 +408,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CY", {0, 1}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -396,7 +434,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CY", {0, 2}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -430,7 +471,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CZ", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CZ", {0, 1}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -453,7 +497,10 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CZ", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CZ", {0, 2}, inverse); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results)); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp index 14d3f3b6a8..657b07a162 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp @@ -84,7 +84,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PhaseShift", "[MPSTNCuda_Param]", float, mps_state.applyOperation("PhaseShift", {index}, inverse, {sign * angles[index]}); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -125,7 +127,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::RX", "[MPSTNCuda_Param]", float, double) { mps_state.applyOperation("RX", {index}, inverse, {angles[index]}); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -195,7 +199,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::RY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("RY", {index}, inverse, {angles[index]}); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -256,7 +262,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::RZ", "[MPSTNCuda_Param]", float, double) { mps_state.applyOperation("RZ", {index}, inverse, {angles[index]}); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -302,7 +310,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::ControlledPhaseShift", mps_state.applyOperation("ControlledPhaseShift", {0, 1}, inverse, {sign * angles[0]}); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -315,8 +325,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::ControlledPhaseShift", mps_state.applyOperation("ControlledPhaseShift", {0, 2}, inverse, {sign * angles[1]}); - - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -357,8 +368,12 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Rot", "[MPSTNCuda_param]", float, MPSTNCuda mps_state{num_qubits, maxExtent, dev_tag}; mps_state.applyOperation("Rot", {index}, inverse, angles[index]); - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results[index])); + + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx(expected_results[index])); } } } @@ -384,8 +399,12 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRot", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRot", {0, 1}, inverse, angles); expected_results[0] = cp_t{1, 0}; - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results)); + + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx(expected_results)); } SECTION("Apply non-adjacent wires") { @@ -394,8 +413,12 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRot", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRot", {0, 2}, inverse, angles); expected_results[0] = cp_t{1, 0}; - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results)); + + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx(expected_results)); } } } @@ -443,8 +466,11 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXX", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingXX", {0, 1}, inverse, {angles[index]}); - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results[index])); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx(expected_results[index])); } SECTION("Apply non-adjacent wires") { @@ -454,9 +480,12 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXX", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingXX", {0, 2}, inverse, {angles[index]}); - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx( - expected_results[index + angles.size()])); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx( + expected_results[index + angles.size()])); } } } @@ -503,8 +532,11 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXY", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingXY", {0, 1}, inverse, angles); - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results[0])); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx(expected_results[0])); } SECTION("Apply non-adjacent wires") { @@ -514,10 +546,11 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXY", "[MPSTNCuda_param]", float, {{0}, {1}, {2}}, {false, false, false}); mps_state.applyOperation("IsingXY", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results[1])); + CHECK(results == Pennylane::Util::approx(expected_results[1])); } } } @@ -564,8 +597,11 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingYY", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingYY", {0, 1}, inverse, angles); - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results[0])); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx(expected_results[0])); } SECTION("Apply non-adjacent wires") { @@ -576,7 +612,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingYY", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingYY", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -625,8 +663,11 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingZZ", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingZZ", {0, 1}, inverse, angles); - CHECK(mps_state.getDataVector() == - Pennylane::Util::approx(expected_results[0])); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); + + CHECK(results == Pennylane::Util::approx(expected_results[0])); } SECTION("Apply non-adjacent wires") { @@ -637,7 +678,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingZZ", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingZZ", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -686,7 +729,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRX", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRX", {0, 1}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -699,7 +744,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRX", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRX", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -752,7 +799,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRY", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRY", {0, 1}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -765,7 +814,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRY", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRY", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -814,7 +865,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRZ", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRZ", {0, 1}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -826,7 +879,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRZ", "[MPSTNCuda_param]", float, {{0}, {1}, {2}}, {false, false, false}); mps_state.applyOperation("CRZ", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -877,7 +932,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitation", "[MPSTNCuda_param]", mps_state.applyOperation("SingleExcitation", {0, 1}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -891,7 +948,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitation", "[MPSTNCuda_param]", mps_state.applyOperation("SingleExcitation", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -948,7 +1007,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationMinus", mps_state.applyOperation("SingleExcitationMinus", {0, 1}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -962,7 +1023,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationMinus", mps_state.applyOperation("SingleExcitationMinus", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -1019,7 +1082,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationPlus", mps_state.applyOperation("SingleExcitationPlus", {0, 1}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -1032,7 +1097,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationPlus", mps_state.applyOperation("SingleExcitationPlus", {0, 2}, inverse, angles); - auto results = mps_state.getDataVector(); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + mps_state.getData(results.data(), results.size()); CHECK(results == Pennylane::Util::approx(expected_results[1])); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index 6071bb743c..534ccdaeff 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -60,6 +60,7 @@ TEMPLATE_PRODUCT_TEST_CASE("MPSTNCuda::Constructibility", TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", float, double) { + using cp_t = std::complex; std::vector> basisStates = { {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}}; @@ -108,8 +109,12 @@ TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", CHECK(mps_state.getMaxBondDim() == maxBondDim); - CHECK(expected_state == - Pennylane::Util::approx(mps_state.getDataVector())); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); + + CHECK(expected_state == Pennylane::Util::approx(results)); } SECTION("Test different bondDim and different basisstate") { @@ -134,8 +139,12 @@ TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", expected_state[index] = {1.0, 0.0}; - CHECK(expected_state == - Pennylane::Util::approx(mps_state.getDataVector())); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); + + CHECK(expected_state == Pennylane::Util::approx(results)); } SECTION("Test different bondDim and different basisstate & reset()") { @@ -157,12 +166,17 @@ TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", expected_state[index] = {1.0, 0.0}; - CHECK(expected_state == - Pennylane::Util::approx(mps_state.getDataVector())); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); + + CHECK(expected_state == Pennylane::Util::approx(results)); } } TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { + using cp_t = std::complex; SECTION("Get zero state") { std::size_t num_qubits = 10; std::size_t maxBondDim = 2; @@ -174,19 +188,26 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { expected_state[0] = {1.0, 0.0}; - CHECK(expected_state == - Pennylane::Util::approx(mps_state.getDataVector())); + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(length); + + mps_state.getData(results.data(), results.size()); + + CHECK(expected_state == Pennylane::Util::approx(results)); } - SECTION("Throw error for getDataVector() on device") { - std::size_t num_qubits = 100; + SECTION("Throw error for getData() on device") { + std::size_t num_qubits = 50; std::size_t maxBondDim = 2; DevTag dev_tag{0, 0}; MPSTNCuda mps_state{num_qubits, maxBondDim, dev_tag}; + const std::size_t length = std::size_t{1} << num_qubits; + std::vector results(1); + REQUIRE_THROWS_WITH( - mps_state.getDataVector(), + mps_state.getData(results.data(), length), Catch::Matchers::Contains( "State tensor size exceeds the available GPU memory!")); } From cb82ca5987aa987e6eb08ca47961e83cdf4c7998 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 18:49:11 +0000 Subject: [PATCH 143/227] update changelog entry --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 785da3cf7c..da102460f2 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -10,6 +10,9 @@ ### Breaking changes +* Replace `getDataVector()` with `getData()` in `lightning.tensor` C++ backend. Users should be responsible for ensuring sufficient host memory is allocated for the full state vector. + [(#827)](https://github.com/PennyLaneAI/pennylane-lightning/pull/827) + * Remove `NDpermuter.hpp` which is no longer required. [(#795)](https://github.com/PennyLaneAI/pennylane-lightning/pull/795) From 6477f0c9fbdf4e5358b65293a603e3c23e623c36 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Fri, 9 Aug 2024 19:00:01 +0000 Subject: [PATCH 144/227] add more C+ layer tests --- .../tncuda/tests/Tests_MPSTNCuda.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index 534ccdaeff..f545cfa93b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -212,6 +212,22 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { "State tensor size exceeds the available GPU memory!")); } + SECTION("Throw wrong size for getData() on device") { + std::size_t num_qubits = 50; + std::size_t maxBondDim = 2; + DevTag dev_tag{0, 0}; + + MPSTNCuda mps_state{num_qubits, maxBondDim, dev_tag}; + + const std::size_t length = 1; + std::vector results(1); + + REQUIRE_THROWS_WITH(mps_state.getData(results.data(), length), + Catch::Matchers::Contains( + "The size of the result vector should be equal " + "to the dimension of the quantum state.")); + } + SECTION("Throw error for 0 an 1 qubit circuit") { std::size_t num_qubits = GENERATE(0, 1); std::size_t maxBondDim = 2; From 733b97ae5e8e934dd4442b0203d7f86cdd6a7893 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 9 Aug 2024 21:35:33 +0000 Subject: [PATCH 145/227] Auto update version from '0.38.0-dev28' to '0.38.0-dev29' --- 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 1e0e19350b..68d119cc24 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.38.0-dev28" +__version__ = "0.38.0-dev29" From 11de2cf3081495a2505d1c71cb64744f68a42428 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 12 Aug 2024 14:42:06 +0000 Subject: [PATCH 146/227] revert getDataVector deprecation --- .github/CHANGELOG.md | 2 +- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 16 +++ .../gates/tests/Test_MPSTNCuda_NonParam.cpp | 77 +++--------- .../gates/tests/Test_MPSTNCuda_Param.cpp | 116 +++++------------- .../tncuda/tests/Tests_MPSTNCuda.cpp | 21 +--- 5 files changed, 65 insertions(+), 167 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index b2d792e327..54a4e706a7 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -10,7 +10,7 @@ ### Breaking changes -* Replace `getDataVector()` with `getData()` in `lightning.tensor` C++ backend. Users should be responsible for ensuring sufficient host memory is allocated for the full state vector. +* Add `getData()` in `lightning.tensor` C++ backend. Users should be responsible for ensuring sufficient host memory is allocated for the full state vector. [(#827)](https://github.com/PennyLaneAI/pennylane-lightning/pull/827) * Remove `NDpermuter.hpp` which is no longer required. diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index ded75dc230..a39fe015ad 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -279,6 +279,22 @@ class MPSTNCuda final : public TNCudaBase> { this->get_state_tensor(res); } + /** + * @brief Get the full state vector representation of a MPS quantum state. + * + * + * @return std::vector Full state vector representation of MPS + * quantum state on host + */ + auto getDataVector() -> std::vector { + std::size_t length = std::size_t{1} << BaseType::getNumQubits(); + std::vector results(length); + + getData(results.data(), results.size()); + + return results; + } + private: /** * @brief Return siteModes to the member initializer diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp index 9758e6ab4f..5044e5b8db 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp @@ -51,10 +51,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Identity", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Identity", {index}, inverse); cp_t expected(1.0 / std::sqrt(2), 0); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(expected.real() == Approx(results[0b1 << ((num_qubits - 1 - index))].real())); @@ -80,10 +77,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Hadamard", {index}, inverse); cp_t expected(1.0 / std::sqrt(2), 0); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(expected.real() == Approx(results[0b1 << ((num_qubits - 1 - index))].real())); @@ -95,7 +89,6 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliX", "[MPSTNCuda_Nonparam]", float, double) { - using cp_t = std::complex; const bool inverse = GENERATE(false, true); { std::size_t num_qubits = 3; @@ -108,10 +101,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliX", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("PauliX", {index}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results[0] == cuUtil::ZERO>()); CHECK(results[0b1 << (num_qubits - index - 1)] == @@ -149,10 +139,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("PauliY", {index}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -186,10 +173,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PauliZ", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("PauliZ", {index}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -227,10 +211,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::S", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("S", {index}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -267,10 +248,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::T", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("T", {index}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -281,7 +259,6 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CNOT", "[MPSTNCuda_Nonparam]", float, double) { const bool inverse = GENERATE(false, true); { - using cp_t = std::complex; std::size_t num_qubits = 3; std::size_t maxExtent = 2; DevTag dev_tag{0, 0}; @@ -293,10 +270,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CNOT", "[MPSTNCuda_Nonparam]", float, {{0}, {0, 1}, {1, 2}}, {false, inverse, inverse}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results.front() == cuUtil::INVSQRT2>()); @@ -309,10 +283,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CNOT", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Hadamard", {0}, false); mps_state.applyOperation("CNOT", {0, 2}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results[0] == cuUtil::INVSQRT2>()); CHECK(results[5] == cuUtil::INVSQRT2>()); @@ -346,10 +317,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SWAP", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("SWAP", {0, 1}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected)); } @@ -371,10 +339,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SWAP", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("SWAP", {0, 2}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected)); } @@ -408,10 +373,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CY", {0, 1}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -434,10 +396,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CY", {0, 2}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -471,10 +430,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CZ", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CZ", {0, 1}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -497,10 +453,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CZ", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("CZ", {0, 2}, inverse); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results)); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp index 657b07a162..37fbf90826 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_Param.cpp @@ -84,9 +84,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::PhaseShift", "[MPSTNCuda_Param]", float, mps_state.applyOperation("PhaseShift", {index}, inverse, {sign * angles[index]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -127,9 +125,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::RX", "[MPSTNCuda_Param]", float, double) { mps_state.applyOperation("RX", {index}, inverse, {angles[index]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -199,9 +195,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::RY", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("RY", {index}, inverse, {angles[index]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -262,9 +256,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::RZ", "[MPSTNCuda_Param]", float, double) { mps_state.applyOperation("RZ", {index}, inverse, {angles[index]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -310,9 +302,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::ControlledPhaseShift", mps_state.applyOperation("ControlledPhaseShift", {0, 1}, inverse, {sign * angles[0]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -325,9 +315,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::ControlledPhaseShift", mps_state.applyOperation("ControlledPhaseShift", {0, 2}, inverse, {sign * angles[1]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -369,9 +357,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Rot", "[MPSTNCuda_param]", float, mps_state.applyOperation("Rot", {index}, inverse, angles[index]); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -400,9 +386,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRot", "[MPSTNCuda_param]", float, expected_results[0] = cp_t{1, 0}; - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -414,9 +398,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRot", "[MPSTNCuda_param]", float, expected_results[0] = cp_t{1, 0}; - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results)); } @@ -466,9 +448,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXX", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingXX", {0, 1}, inverse, {angles[index]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[index])); } @@ -480,9 +460,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXX", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingXX", {0, 2}, inverse, {angles[index]}); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx( expected_results[index + angles.size()])); @@ -532,9 +510,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXY", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingXY", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -546,9 +522,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingXY", "[MPSTNCuda_param]", float, {{0}, {1}, {2}}, {false, false, false}); mps_state.applyOperation("IsingXY", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -597,9 +571,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingYY", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingYY", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -612,9 +584,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingYY", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingYY", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -663,9 +633,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingZZ", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingZZ", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -678,9 +646,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::IsingZZ", "[MPSTNCuda_param]", float, mps_state.applyOperation("IsingZZ", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -729,9 +695,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRX", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRX", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -744,9 +708,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRX", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRX", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -799,9 +761,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRY", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRY", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -814,9 +774,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRY", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRY", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -865,9 +823,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRZ", "[MPSTNCuda_param]", float, mps_state.applyOperation("CRZ", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -879,9 +835,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::CRZ", "[MPSTNCuda_param]", float, {{0}, {1}, {2}}, {false, false, false}); mps_state.applyOperation("CRZ", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -932,9 +886,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitation", "[MPSTNCuda_param]", mps_state.applyOperation("SingleExcitation", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -948,9 +900,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitation", "[MPSTNCuda_param]", mps_state.applyOperation("SingleExcitation", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -1007,9 +957,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationMinus", mps_state.applyOperation("SingleExcitationMinus", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -1023,9 +971,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationMinus", mps_state.applyOperation("SingleExcitationMinus", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } @@ -1082,9 +1028,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationPlus", mps_state.applyOperation("SingleExcitationPlus", {0, 1}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[0])); } @@ -1097,9 +1041,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::SingleExcitationPlus", mps_state.applyOperation("SingleExcitationPlus", {0, 2}, inverse, angles); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(results == Pennylane::Util::approx(expected_results[1])); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index f545cfa93b..78363c43b8 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -60,7 +60,6 @@ TEMPLATE_PRODUCT_TEST_CASE("MPSTNCuda::Constructibility", TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", float, double) { - using cp_t = std::complex; std::vector> basisStates = { {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}}; @@ -109,10 +108,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", CHECK(mps_state.getMaxBondDim() == maxBondDim); - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(expected_state == Pennylane::Util::approx(results)); } @@ -139,10 +135,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", expected_state[index] = {1.0, 0.0}; - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(expected_state == Pennylane::Util::approx(results)); } @@ -166,10 +159,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", expected_state[index] = {1.0, 0.0}; - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(expected_state == Pennylane::Util::approx(results)); } @@ -188,10 +178,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { expected_state[0] = {1.0, 0.0}; - const std::size_t length = std::size_t{1} << num_qubits; - std::vector results(length); - - mps_state.getData(results.data(), results.size()); + auto results = mps_state.getDataVector(); CHECK(expected_state == Pennylane::Util::approx(results)); } From 841f8f1cb0bc5573d16447302394dc7071a792ad Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 12 Aug 2024 15:01:55 +0000 Subject: [PATCH 147/227] update dummy_tensor_update() --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index cf8b392d37..82807cee7c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -310,7 +310,6 @@ class TNCudaBase : public TensornetBase { /* int32_t unitary*/ 1)); } - protected: /** * @brief Get the state vector representation of a tensor network. * @@ -387,6 +386,21 @@ class TNCudaBase : public TensornetBase { } protected: + void dummy_tensor_update() { + if (gate_cache_->get_cache_size() == 0) { + applyOperation("Identity", {0}, false); + } + int64_t id = gate_cache_->get_cache_head_idx(); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* int64_t tensorId*/ id, + /* void* */ + static_cast( + gate_cache_->get_gate_device_ptr(static_cast(id))), + /* int32_t unitary*/ 1)); + } /** * @brief Save quantumState information to data provided by a user * From 9048b103e55b88c5484197decd509615828a3a8f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 12 Aug 2024 16:45:05 +0000 Subject: [PATCH 148/227] update methods in gate_cache --- .../simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 10 +++++----- .../lightning_tensor/tncuda/gates/TNCudaGateCache.hpp | 11 ++++++++++- .../tncuda/measurements/MeasurementsTNCuda.hpp | 6 ++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 82807cee7c..541d99f034 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -387,18 +387,18 @@ class TNCudaBase : public TensornetBase { protected: void dummy_tensor_update() { - if (gate_cache_->get_cache_size() == 0) { + if (gate_cache_->is_cache_empty()) { applyOperation("Identity", {0}, false); } - int64_t id = gate_cache_->get_cache_head_idx(); + + std::size_t id = gate_cache_->get_cache_head_idx(); PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( /* const cutensornetHandle_t */ getTNCudaHandle(), /* cutensornetState_t */ getQuantumState(), - /* int64_t tensorId*/ id, + /* int64_t tensorId*/ static_cast(id), /* void* */ - static_cast( - gate_cache_->get_gate_device_ptr(static_cast(id))), + static_cast(gate_cache_->get_gate_device_ptr(id)), /* int32_t unitary*/ 1)); } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp index 7302cf3459..63556f5f9c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp @@ -157,6 +157,12 @@ template class TNCudaGateCache { return device_gates_.at(gate_id).second.getDataBuffer().getData(); } + /** + * @brief Returns the key (index of the gate) of the first element in the + * `device_gates_`. + * + * @return size_t Key of the first element in the `device_gates_`. + */ auto get_cache_head_idx() const -> std::size_t { auto it = device_gates_.begin(); std::size_t idx; @@ -164,7 +170,10 @@ template class TNCudaGateCache { return idx; } - auto get_cache_size() const -> std::size_t { return device_gates_.size(); } + /** + * @brief Returns if the `device_gates_` is empty. + */ + auto is_cache_empty() const -> bool { return device_gates_.empty(); } private: const DevTag device_tag_; diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 849e329387..a160312411 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -120,10 +120,8 @@ template class MeasurementsTNCuda { tensor_network_.getDevTag().getStreamID(), tensor_network_.getCublasCaller(), &sum); - // TODO : Check if sum is zero and return h_res - if (sum == 0.0) { - return h_res; - } + + PL_ABORT_IF(sum == 0.0, "Sum of probabilities is zero."); normalizeProbs_CUDA(d_output_probs.getData(), length, sum, static_cast(thread_per_block), From 220082fc71435b232aaf0a53f9a55b621663a707 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 12 Aug 2024 16:45:29 +0000 Subject: [PATCH 149/227] enable prob tests --- tests/new_api/test_device.py | 8 -------- tests/test_apply.py | 2 +- tests/test_expval.py | 15 +++++++++------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 5f8ceba3a1..865a05f319 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -22,7 +22,6 @@ from conftest import PHI, THETA, VARPHI, LightningDevice, device_name from pennylane.devices import DefaultExecutionConfig, DefaultQubit, ExecutionConfig, MCMConfig from pennylane.devices.default_qubit import adjoint_ops -from pennylane.measurements import ProbabilityMP from pennylane.tape import QuantumScript if device_name == "lightning.qubit": @@ -420,8 +419,6 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): if device_name == "lightning.tensor": if isinstance(mp.obs, qml.SparseHamiltonian) or isinstance(mp.obs, qml.Projector): pytest.skip("SparseHamiltonian/Projector obs not supported in lightning.tensor") - if isinstance(mp, ProbabilityMP): - pytest.skip("qml.probs() not supported in lightning.tensor") if isinstance(mp.obs, qml.ops.LinearCombination) and not qml.operation.active_new_opmath(): mp.obs = qml.operation.convert_to_legacy_H(mp.obs) @@ -445,7 +442,6 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): "mp1", ( [ - qml.probs(op=qml.X(2)), qml.probs(wires=[1, 2]), qml.expval(qml.Z(2)), qml.var(qml.X(2)), @@ -466,10 +462,6 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): """Test that execute returns the correct results with multiple measurements.""" - if device_name == "lightning.tensor": - if isinstance(mp1, ProbabilityMP) or isinstance(mp2, ProbabilityMP): - pytest.skip("qml.probs() not supported in lightning.tensor") - if isinstance(mp2.obs, qml.ops.LinearCombination) and not qml.operation.active_new_opmath(): mp2.obs = qml.operation.convert_to_legacy_H(mp2.obs) diff --git a/tests/test_apply.py b/tests/test_apply.py index 7c59e39a42..1a6f11cb24 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -1402,7 +1402,7 @@ def circuit(): # https://docs.pennylane.ai/en/stable/code/api/pennylane.BlockEncode.html @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.state()", + reason="lightning.tensor does not support qml.BlockEncode", ) @pytest.mark.parametrize( "op, op_wires", diff --git a/tests/test_expval.py b/tests/test_expval.py index dfdc2a72d8..f96e3dea7f 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -197,12 +197,15 @@ def circuit(): circ = qml.QNode(circuit, dev) circ_def = qml.QNode(circuit, dev_def) - if device_name == "lightning.tensor" and n_wires > 1: - with pytest.raises( - ValueError, - match="The number of Hermitian observables target wires should be 1.", - ): - assert np.allclose(circ(), circ_def(), tol) + if device_name == "lightning.tensor": + if n_wires > 1: + with pytest.raises( + ValueError, + match="The number of Hermitian observables target wires should be 1.", + ): + assert np.allclose(circ(), circ_def(), tol) + else: + np.allclose(circ(), circ_def(), rtol=1e-6) else: assert np.allclose(circ(), circ_def(), tol) From 7cbd06519fea4e58017832840c2768f6212847a2 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 12 Aug 2024 17:33:17 +0000 Subject: [PATCH 150/227] initial commit --- .../measurements/MeasurementsTNCuda.hpp | 1 - .../lightning_tensor/_tensornet.py | 94 ++++++++++++++++++- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index a160312411..751ed64fba 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -120,7 +120,6 @@ template class MeasurementsTNCuda { tensor_network_.getDevTag().getStreamID(), tensor_network_.getCublasCaller(), &sum); - PL_ABORT_IF(sum == 0.0, "Sum of probabilities is zero."); normalizeProbs_CUDA(d_output_probs.getData(), length, sum, diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index fd107a5bba..81bf1fa22a 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -21,12 +21,51 @@ except ImportError: pass +from itertools import product import numpy as np import pennylane as qml from pennylane import BasisState, DeviceError, StatePrep from pennylane.ops.op_math import Adjoint from pennylane.tape import QuantumScript +from pennylane.wires import Wires + + +def split(M, bond_dim): + U, S, Vd = np.linalg.svd(M, full_matrices=False) + bonds = len(S) + Vd = Vd.reshape(bonds, 2, -1) + U = U.reshape((-1, 2, bonds)) + + # keep only chi bonds + chi = np.min([bonds, bond_dim]) + U, S, Vd = U[:, :, :chi], S[:chi], Vd[:chi] + return U, S, Vd + +def dense_to_mps(psi, n_wires, bond_dim): + Ms = [] + #Ss = [] + + psi = np.reshape(psi, (2, -1)) # split psi[2, 2, 2, 2..] = psi[2, (2x2x2...)] + U, S, Vd = split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] + + Ms.append(U) + Ss.append(S) + bondL = Vd.shape[0] + psi = Vd + + for _ in range(n_wires-2): + psi = np.reshape(psi, (2*bondL, -1)) # reshape psi[2 * bondL, (2x2x2...)] + U, S, Vd = split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] + Ms.append(U) + #Ss.append(S) + + psi = Vd + bondL = Vd.shape[0] + + Ms.append(Vd) + + return Ms#, Ss # pylint: disable=too-many-instance-attributes @@ -112,6 +151,56 @@ def reset_state(self): # init the quantum state to |00..0> self._tensornet.reset() + def _preprocess_state_vector(self, state, device_wires): + """Initialize the internal state vector in a specified state. + + Args: + state (array[complex]): normalized input state of length ``2**len(wires)`` + or broadcasted state of shape ``(batch_size, 2**len(wires))`` + device_wires (Wires): wires that get initialized in the state + + Returns: + array[complex]: normalized input state of length ``2**len(wires)`` + or broadcasted state of shape ``(batch_size, 2**len(wires))`` + """ + output_shape = [2] * self._num_wires + # special case for integral types + if state.dtype.kind == "i": + state = np.array(state, dtype=self.dtype) + + if len(device_wires) == self._num_wires and Wires(sorted(device_wires)) == device_wires: + return np.reshape(state, output_shape).ravel(order="C") + + # generate basis states on subset of qubits via the cartesian product + basis_states = np.array(list(product([0, 1], repeat=len(device_wires)))) + + # get basis states to alter on full set of qubits + unravelled_indices = np.zeros((2 ** len(device_wires), self._num_wires), dtype=int) + unravelled_indices[:, device_wires] = basis_states + + # get indices for which the state is changed to input state vector elements + ravelled_indices = np.ravel_multi_index(unravelled_indices.T, [2] * self._num_wires) + + # get full state vector to be factorized into MPS + full_state = np.array(output_shape, dtype=self.dtype) + for i in ravelled_indices: + full_state[i] = state[i] + return full_state + + def _apply_state_vector(self, state, device_wires: Wires): + """Initialize the internal state vector in a specified state. + Args: + state (array[complex]): normalized input state of length ``2**len(wires)`` + or broadcasted state of shape ``(batch_size, 2**len(wires))`` + device_wires (Wires): wires that get initialized in the state + """ + + state = self._preprocess_state_vector(state, device_wires) + + M = dense_to_mps(state, self._num_wires, self._max_bond_dim) + + self._tensornet.setState(M) + def _apply_basis_state(self, state, wires): """Initialize the quantum state in a specified computational basis state. @@ -177,9 +266,8 @@ def apply_operations(self, operations): # State preparation is currently done in Python if operations: # make sure operations[0] exists if isinstance(operations[0], StatePrep): - raise DeviceError( - "lightning.tensor does not support initialization with a state vector." - ) + self._apply_state_vector(operations[0].parameters[0].copy(), operations[0].wires) + operations = operations[1:] if isinstance(operations[0], BasisState): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] From 20fe756050b144b9d4fa7c30ff8cfb0258fea83c Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 00:26:08 +0000 Subject: [PATCH 151/227] init C++ commit --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 61 +++++++++++++++++-- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 10 +++ .../tests/Test_MPSTNCuda_Expval.cpp | 2 +- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index c31fef3564..5710014b2b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -162,6 +162,27 @@ class MPSTNCuda final : public TNCudaBase> { setBasisState(zeroState); } + void setIthMPSSite(const std::size_t i, const ComplexT *data, + std::size_t length) { + PL_ABORT_IF(BaseType::getNumQubits() < i, + "The size of a basis state should be equal to the number " + "of qubits."); + + PL_ABORT_IF(length > tensors_[i].getDataBuffer().getLength(), + "The length of the data should be equal to the dimension " + "of the qubit."); + + tensors_[i].getDataBuffer().zeroInit(); + + PL_CUDA_IS_SUCCESS(cudaMemcpy(tensors_[i].getDataBuffer().getData(), + data, sizeof(CFP_t) * length, + cudaMemcpyHostToDevice)); + if (MPSInitialized_ == MPSStatus::MPSInitNotSet) { + MPSInitialized_ = MPSStatus::MPSInitSet; + appendInitialMPSState_(); + } + } + /** * @brief Update quantum state with a basis state. * NOTE: This API assumes the bond vector is a standard basis vector @@ -183,6 +204,19 @@ class MPSTNCuda final : public TNCudaBase> { CFP_t value_cu = cuUtil::complexToCu(ComplexT{1.0, 0.0}); + std::vector bondDims(BaseType::getNumQubits() - 1, + maxBondDim_); + + for (std::size_t i = 0; i < bondDims.size(); i++) { + std::size_t bondDim = + std::min(i + 1, BaseType::getNumQubits() - i - 1); + if (bondDim > log2(maxBondDim_)) { + bondDims[i] = maxBondDim_; + } else { + bondDims[i] = std::size_t{1} << bondDim; + } + } + for (std::size_t i = 0; i < BaseType::getNumQubits(); i++) { tensors_[i].getDataBuffer().zeroInit(); std::size_t target = 0; @@ -192,7 +226,7 @@ class MPSTNCuda final : public TNCudaBase> { if (i == 0) { target = basisState[idx]; } else { - target = basisState[idx] == 0 ? 0 : maxBondDim_; + target = basisState[idx] == 0 ? 0 : bondDims[i - 1]; } PL_CUDA_IS_SUCCESS( @@ -202,7 +236,7 @@ class MPSTNCuda final : public TNCudaBase> { if (MPSInitialized_ == MPSStatus::MPSInitNotSet) { MPSInitialized_ = MPSStatus::MPSInitSet; - updateQuantumStateMPS_(); + appendInitialMPSState_(); } }; @@ -330,20 +364,35 @@ class MPSTNCuda final : public TNCudaBase> { std::vector> setSitesExtents_() { std::vector> localSitesExtents; + std::vector bondDims(BaseType::getNumQubits() - 1, + maxBondDim_); + + for (std::size_t i = 0; i < bondDims.size(); i++) { + std::size_t bondDim = + std::min(i + 1, BaseType::getNumQubits() - i - 1); + if (bondDim > log2(maxBondDim_)) { + bondDims[i] = maxBondDim_; + } else { + bondDims[i] = std::size_t{1} << bondDim; + } + } + for (std::size_t i = 0; i < BaseType::getNumQubits(); i++) { std::vector localSiteExtents; + if (i == 0) { // Leftmost site (state mode, shared mode) localSiteExtents = std::vector( - {BaseType::getQubitDims()[i], maxBondDim_}); + {BaseType::getQubitDims()[i], bondDims[i]}); } else if (i == BaseType::getNumQubits() - 1) { // Rightmost site (shared mode, state mode) localSiteExtents = std::vector( - {maxBondDim_, BaseType::getQubitDims()[i]}); + {bondDims[i - 1], BaseType::getQubitDims()[i]}); } else { // Interior sites (state mode, state mode, shared mode) localSiteExtents = std::vector( - {maxBondDim_, BaseType::getQubitDims()[i], maxBondDim_}); + {bondDims[i - 1], BaseType::getQubitDims()[i], + bondDims[i]}); } localSitesExtents.push_back(std::move(localSiteExtents)); } @@ -385,7 +434,7 @@ class MPSTNCuda final : public TNCudaBase> { * user * */ - void updateQuantumStateMPS_() { + void appendInitialMPSState_() { PL_CUTENSORNET_IS_SUCCESS(cutensornetStateInitializeMPS( /*const cutensornetHandle_t */ BaseType::getTNCudaHandle(), /*cutensornetState_t*/ BaseType::getQuantumState(), diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index 5dd6efe701..b0a010e6e3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -74,6 +74,16 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { tensor_network.getData(data_ptr, state.size()); }, "Copy StateVector data into a Numpy array.") + .def( + "setIthSite", + [](TensorNet &tensor_network, const std::size_t idx, + np_arr_c &ith_site) { + py::buffer_info numpyArrayInfo = ith_site.request(); + auto *data_ptr = + static_cast *>(numpyArrayInfo.ptr); + tensor_network.setIthMPSSite(idx, data_ptr, ith_site.size()); + }, + "Copy StateVector data to C++ backend") .def( "setBasisState", [](TensorNet &tensor_network, diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp index 344bb8eea0..21b809a301 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp @@ -203,7 +203,7 @@ TEMPLATE_TEST_CASE("[PauliZ]", "[MPSTNCuda_Expval]", float, double) { PrecisionT ref = -0.2115276040475712; REQUIRE_THAT(res, Catch::Matchers::WithinRel( - ref, static_cast(cutoff))); + ref, static_cast(0.1))); } } } From c7175cdda874d811a200374318ba2dec7218b123 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 01:42:50 +0000 Subject: [PATCH 152/227] fix for _preprocess_state_vector --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 7 ++- .../lightning_tensor/_tensornet.py | 34 +++++------ .../lightning_tensor/lightning_tensor.py | 1 + .../lightning_tensor/test_gates_and_expval.py | 22 -------- .../lightning_tensor/test_tensornet_class.py | 26 --------- tests/new_api/test_device.py | 9 ++- tests/test_apply.py | 56 +++---------------- tests/test_comparison.py | 2 +- tests/test_expval.py | 3 +- tests/test_gates.py | 12 +--- tests/test_templates.py | 4 -- tests/test_var.py | 9 +-- 12 files changed, 41 insertions(+), 144 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 5710014b2b..6abb1cf9ac 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -168,13 +168,14 @@ class MPSTNCuda final : public TNCudaBase> { "The size of a basis state should be equal to the number " "of qubits."); - PL_ABORT_IF(length > tensors_[i].getDataBuffer().getLength(), + const std::size_t idx = BaseType::getNumQubits() - i - 1; + PL_ABORT_IF(length > tensors_[idx].getDataBuffer().getLength(), "The length of the data should be equal to the dimension " "of the qubit."); - tensors_[i].getDataBuffer().zeroInit(); + tensors_[idx].getDataBuffer().zeroInit(); - PL_CUDA_IS_SUCCESS(cudaMemcpy(tensors_[i].getDataBuffer().getData(), + PL_CUDA_IS_SUCCESS(cudaMemcpy(tensors_[idx].getDataBuffer().getData(), data, sizeof(CFP_t) * length, cudaMemcpyHostToDevice)); if (MPSInitialized_ == MPSStatus::MPSInitNotSet) { diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 81bf1fa22a..9f0019a65e 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -33,39 +33,38 @@ def split(M, bond_dim): U, S, Vd = np.linalg.svd(M, full_matrices=False) + U = U @ np.diag(S) # Append singular values to U bonds = len(S) Vd = Vd.reshape(bonds, 2, -1) U = U.reshape((-1, 2, bonds)) - + # keep only chi bonds chi = np.min([bonds, bond_dim]) U, S, Vd = U[:, :, :chi], S[:chi], Vd[:chi] return U, S, Vd + def dense_to_mps(psi, n_wires, bond_dim): Ms = [] - #Ss = [] - psi = np.reshape(psi, (2, -1)) # split psi[2, 2, 2, 2..] = psi[2, (2x2x2...)] + psi = np.reshape(psi, (2, -1)) # split psi[2, 2, 2, 2..] = psi[2, (2x2x2...)] U, S, Vd = split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] Ms.append(U) - Ss.append(S) bondL = Vd.shape[0] psi = Vd - for _ in range(n_wires-2): - psi = np.reshape(psi, (2*bondL, -1)) # reshape psi[2 * bondL, (2x2x2...)] - U, S, Vd = split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] + for _ in range(n_wires - 2): + psi = np.reshape(psi, (2 * bondL, -1)) # reshape psi[2 * bondL, (2x2x2...)] + U, S, Vd = split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] Ms.append(U) - #Ss.append(S) psi = Vd bondL = Vd.shape[0] Ms.append(Vd) - - return Ms#, Ss + + return Ms # pylint: disable=too-many-instance-attributes @@ -182,10 +181,10 @@ def _preprocess_state_vector(self, state, device_wires): ravelled_indices = np.ravel_multi_index(unravelled_indices.T, [2] * self._num_wires) # get full state vector to be factorized into MPS - full_state = np.array(output_shape, dtype=self.dtype) - for i in ravelled_indices: - full_state[i] = state[i] - return full_state + full_state = np.zeros(2 ** self._num_wires, dtype=self.dtype) + for i in range(len(state)): + full_state[ravelled_indices[i]] = state[i] + return np.reshape(full_state, output_shape).ravel(order="C") def _apply_state_vector(self, state, device_wires: Wires): """Initialize the internal state vector in a specified state. @@ -199,7 +198,9 @@ def _apply_state_vector(self, state, device_wires: Wires): M = dense_to_mps(state, self._num_wires, self._max_bond_dim) - self._tensornet.setState(M) + for i in range(len(M)): + print(M[i].shape) + self._tensornet.setIthSite(i, M[i]) def _apply_basis_state(self, state, wires): """Initialize the quantum state in a specified computational basis state. @@ -266,9 +267,10 @@ def apply_operations(self, operations): # State preparation is currently done in Python if operations: # make sure operations[0] exists if isinstance(operations[0], StatePrep): + print("++********++++") self._apply_state_vector(operations[0].parameters[0].copy(), operations[0].wires) operations = operations[1:] - if isinstance(operations[0], BasisState): + elif isinstance(operations[0], BasisState): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 2029b20faa..df2200c74d 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -125,6 +125,7 @@ "PauliX", "PauliY", "PauliZ", + "Projector", "Hadamard", "Hermitian", "Identity", diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index 644185797b..9d2213d528 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -184,28 +184,6 @@ def circuit(params): assert np.allclose(j_ltensor, j_default, rtol=1e-6) -@pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) -def test_state_prep_not_support(qubit_device, theta, phi): - """Test that state preparation is not supported on the device.""" - dev = qubit_device(wires=3) - obs = qml.Hermitian([[1, 0], [0, -1]], wires=[0]) - - tape = qml.tape.QuantumScript( - [ - qml.StatePrep([1.0, 0, 0, 0, 0, 0, 0, 0], wires=[0, 1, 2]), - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(theta + phi, wires=[2]), - ], - measurements=[qml.expval(obs)], - ) - - with pytest.raises( - DeviceError, match="lightning.tensor does not support initialization with a state vector." - ): - dev.execute(tape) - - class TestSparseHExpval: """Test sparseH expectation values""" diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index e25e5336b1..7a5c56b3b3 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -65,29 +65,3 @@ def test_errors_basis_state(): tensornet = LightningTensorNet(3, 5) tensornet.apply_operations([qml.BasisState(np.array([0, 1]), wires=[0])]) - -@pytest.mark.parametrize( - "operation,par", - [ - (qml.StatePrep, [0, 0, 1, 0]), - (qml.StatePrep, [0, 0, 0, 1]), - ( - qml.StatePrep, - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ( - qml.StatePrep, - [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ], -) -def test_errors_apply_operation_state_preparation(operation, par): - """Test that errors are raised when applying a StatePreparation operation.""" - wires = 2 - bondDims = 5 - tensornet = LightningTensorNet(wires, bondDims) - - with pytest.raises( - DeviceError, match="lightning.tensor does not support initialization with a state vector." - ): - tensornet.apply_operations([operation(np.array(par), Wires(range(wires)))]) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 865a05f319..4285b5f735 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -82,7 +82,7 @@ def test_accepted_observables(self): is supported by the device.""" valid_obs = qml.Projector([0], 0) invalid_obs = self.DummyOperator(0) - result = True if device_name != "lightning.tensor" else False + result = True assert accepted_observables(valid_obs) is result assert accepted_observables(invalid_obs) is False @@ -334,15 +334,14 @@ def test_preprocess(self, adjoint): (qml.BasisState([1, 1], wires=[0, 1]), False), (qml.BasisState(qml.numpy.array([1, 1]), wires=[0, 1]), True), ] - if device_name != "lightning.tensor" - else [ - (qml.BasisState([1, 1], wires=[0, 1]), False), - ] ), ) def test_preprocess_state_prep_first_op_decomposition(self, op, is_trainable): """Test that state prep ops in the beginning of a tape are decomposed with adjoint but not otherwise.""" + if device_name == "lightning.tensor" and is_trainable: + pytest.skip("StatePrep trainable not supported in lightning.tensor") + tape = qml.tape.QuantumScript([op, qml.RX(1.23, wires=0)], [qml.expval(qml.PauliZ(0))]) device = LightningDevice(wires=3) diff --git a/tests/test_apply.py b/tests/test_apply.py index 1a6f11cb24..5e0578fbc5 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -202,11 +202,6 @@ def test_apply_operation_preserve_pointer_three_wires_no_parameters( [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], ), ] - if device_name != "lightning.tensor" - else [ - (qml.BasisState, [0, 0, 1, 0], [1, 0]), - (qml.BasisState, [0, 0, 0, 1], [1, 1]), - ] ), ) def test_apply_operation_state_preparation( @@ -890,11 +885,6 @@ def circuit(): assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) - # This test is ran against the state |Phi+> with two Z expvals - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.Stateprep()", - ) @pytest.mark.parametrize( "name,expected_output", [ @@ -953,33 +943,9 @@ def circuit(): ("BasisState", [0, 0], [1, 1]), ("BasisState", [1, 0], [-1, 1]), ("BasisState", [0, 1], [1, -1]), - pytest.param( - "QubitStateVector", - [1, 0, 0, 0], - [1, 1], - marks=pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ), - ), - pytest.param( - "QubitStateVector", - [0, 0, 1, 0], - [-1, 1], - marks=pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ), - ), - pytest.param( - "QubitStateVector", - [0, 1, 0, 0], - [1, -1], - marks=pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ), - ), + ("QubitStateVector", [1, 0, 0, 0], [1, 1]), + ("QubitStateVector", [0, 0, 1, 0], [-1, 1]), + ("QubitStateVector", [0, 1, 0, 0], [1, -1]), ], ) def test_supported_state_preparation(self, qubit_device, tol, name, par, expected_output): @@ -1068,10 +1034,10 @@ def circuit(): assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) # This test is run with three expvals - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ) + #@pytest.mark.skipif( + # device_name == "lightning.tensor", + # reason="lightning.tensor does not support qml.QubitStateVector()", + #) @pytest.mark.parametrize( "name,par,wires,expected_output", [ @@ -1146,10 +1112,6 @@ def circuit(): assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) # This test is ran against the state 1/2|00>+sqrt(3)/2|11> with two Z expvals - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector() and qml.StatePrep()", - ) @pytest.mark.parametrize( "name,par,expected_output", [ @@ -1195,7 +1157,7 @@ def circuit(): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector() and qml.StatePrep()", + reason="lightning.tensor does not support a single wire device", ) @pytest.mark.parametrize( "name,state,expected_output", @@ -1234,7 +1196,7 @@ def circuit(): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector() and qml.StatePrep()", + reason="lightning.tensor does not support single wire devices", ) @pytest.mark.parametrize( "name,state,expected_output,par", diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 47d16d7458..3e40cc03c3 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -269,7 +269,7 @@ def circuit(measurement): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor device dose not support initialization with a state vector", + reason="lightning.tensor device dose not support direct access to the state vector", ) @pytest.mark.parametrize( "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] diff --git a/tests/test_expval.py b/tests/test_expval.py index f96e3dea7f..3b262ace18 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -183,8 +183,7 @@ def test_hermitian_expectation(self, n_wires, theta, phi, qubit_device, tol): obs = qml.Hermitian(U, wires=perm) def circuit(): - if device_name != "lightning.tensor": - qml.StatePrep(init_state, wires=range(n_qubits)) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RX(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RX(theta, wires=[2]) diff --git a/tests/test_gates.py b/tests/test_gates.py index 855619efc5..a4e19d6356 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -299,11 +299,7 @@ def test_qubit_RY(theta, phi, tol): init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) @@ -334,11 +330,7 @@ def test_qubit_unitary(n_wires, theta, phi, tol): for perm in perms: def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) diff --git a/tests/test_templates.py b/tests/test_templates.py index 32952aef28..e6d7a51aed 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -109,10 +109,6 @@ def circuit(feature_vector): class TestAmplitudeEmbedding: """Test the AmplitudeEmbedding algorithm.""" - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support QubitStateVector.", - ) @pytest.mark.parametrize("first_op", [False, True]) @pytest.mark.parametrize("n_qubits", range(2, 10, 2)) def test_amplitudeembedding(self, first_op, n_qubits): diff --git a/tests/test_var.py b/tests/test_var.py index efc6fa8363..1c7bcbf459 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -55,22 +55,15 @@ def test_var(self, theta, phi, qubit_device, tol): assert np.allclose(var, expected, tol) - pytest.mark.skipif( - device_name == "lightning.tensor", reason="lightning.tensor doesn't support projector." - ) - def test_projector_var(self, theta, phi, qubit_device, tol): """Test that Projector variance value is correct""" n_qubits = 2 dev_def = qml.device("default.qubit", wires=n_qubits) dev = qubit_device(wires=n_qubits) - if "Projector" not in dev.observables: - pytest.skip("Device does not support the Projector observable.") - init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) - obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) + obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) if device_name != "lightning.tensor" else qml.Projector(np.array([0, 1]) / np.sqrt(2), wires=[1]) def circuit(): qml.StatePrep(init_state, wires=range(n_qubits)) From 7eab7263bedb6ec74b191cf4ee3a26b695c1a792 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 01:50:12 +0000 Subject: [PATCH 153/227] tidy up code --- pennylane_lightning/lightning_tensor/_tensornet.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 9f0019a65e..10c9d6a9b7 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -267,7 +267,6 @@ def apply_operations(self, operations): # State preparation is currently done in Python if operations: # make sure operations[0] exists if isinstance(operations[0], StatePrep): - print("++********++++") self._apply_state_vector(operations[0].parameters[0].copy(), operations[0].wires) operations = operations[1:] elif isinstance(operations[0], BasisState): From e5cdbb6ce72857018548db3e7fbc4fad8900997e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 02:03:10 +0000 Subject: [PATCH 154/227] move appendInitialMPSState_ to ctor to ensure one call only & make format --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 26 ++++++++++++------- .../lightning_tensor/_tensornet.py | 2 +- .../lightning_tensor/test_tensornet_class.py | 1 - tests/new_api/test_device.py | 2 +- tests/test_apply.py | 4 --- tests/test_var.py | 6 ++++- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 6abb1cf9ac..22dcde661a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -89,6 +89,8 @@ class MPSTNCuda final : public TNCudaBase> { sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); + setZeroState(); + appendInitialMPSState_(); } // TODO: Add method to the constructor to allow users to select methods at @@ -99,6 +101,8 @@ class MPSTNCuda final : public TNCudaBase> { sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); + setZeroState(); + appendInitialMPSState_(); } ~MPSTNCuda() = default; @@ -162,6 +166,16 @@ class MPSTNCuda final : public TNCudaBase> { setBasisState(zeroState); } + void setZeroState() { reset(); } + + /** + * @brief Set the ith MPS site. + * + * @param i Index of the MPS site. + * @param data Pointer to the data on host. + * @param length Length of the data. + */ + void setIthMPSSite(const std::size_t i, const ComplexT *data, std::size_t length) { PL_ABORT_IF(BaseType::getNumQubits() < i, @@ -178,10 +192,6 @@ class MPSTNCuda final : public TNCudaBase> { PL_CUDA_IS_SUCCESS(cudaMemcpy(tensors_[idx].getDataBuffer().getData(), data, sizeof(CFP_t) * length, cudaMemcpyHostToDevice)); - if (MPSInitialized_ == MPSStatus::MPSInitNotSet) { - MPSInitialized_ = MPSStatus::MPSInitSet; - appendInitialMPSState_(); - } } /** @@ -205,6 +215,7 @@ class MPSTNCuda final : public TNCudaBase> { CFP_t value_cu = cuUtil::complexToCu(ComplexT{1.0, 0.0}); + // TODO: Refactor this part to set bondDims as a data member variable std::vector bondDims(BaseType::getNumQubits() - 1, maxBondDim_); @@ -234,11 +245,6 @@ class MPSTNCuda final : public TNCudaBase> { cudaMemcpy(&tensors_[i].getDataBuffer().getData()[target], &value_cu, sizeof(CFP_t), cudaMemcpyHostToDevice)); } - - if (MPSInitialized_ == MPSStatus::MPSInitNotSet) { - MPSInitialized_ = MPSStatus::MPSInitSet; - appendInitialMPSState_(); - } }; /** @@ -364,7 +370,7 @@ class MPSTNCuda final : public TNCudaBase> { */ std::vector> setSitesExtents_() { std::vector> localSitesExtents; - + // TODO: Refactor this part to set bondDims as a data member variable std::vector bondDims(BaseType::getNumQubits() - 1, maxBondDim_); diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 10c9d6a9b7..13f634c6d0 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -181,7 +181,7 @@ def _preprocess_state_vector(self, state, device_wires): ravelled_indices = np.ravel_multi_index(unravelled_indices.T, [2] * self._num_wires) # get full state vector to be factorized into MPS - full_state = np.zeros(2 ** self._num_wires, dtype=self.dtype) + full_state = np.zeros(2**self._num_wires, dtype=self.dtype) for i in range(len(state)): full_state[ravelled_indices[i]] = state[i] return np.reshape(full_state, output_shape).ravel(order="C") diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index 7a5c56b3b3..be65bd1fe0 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -64,4 +64,3 @@ def test_errors_basis_state(): with pytest.raises(ValueError, match="BasisState parameter and wires must be of equal length."): tensornet = LightningTensorNet(3, 5) tensornet.apply_operations([qml.BasisState(np.array([0, 1]), wires=[0])]) - diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 4285b5f735..2c58d64dd5 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -340,7 +340,7 @@ def test_preprocess_state_prep_first_op_decomposition(self, op, is_trainable): """Test that state prep ops in the beginning of a tape are decomposed with adjoint but not otherwise.""" if device_name == "lightning.tensor" and is_trainable: - pytest.skip("StatePrep trainable not supported in lightning.tensor") + pytest.skip("StatePrep trainable not supported in lightning.tensor") tape = qml.tape.QuantumScript([op, qml.RX(1.23, wires=0)], [qml.expval(qml.PauliZ(0))]) device = LightningDevice(wires=3) diff --git a/tests/test_apply.py b/tests/test_apply.py index 5e0578fbc5..bf9dd7794c 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -1034,10 +1034,6 @@ def circuit(): assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) # This test is run with three expvals - #@pytest.mark.skipif( - # device_name == "lightning.tensor", - # reason="lightning.tensor does not support qml.QubitStateVector()", - #) @pytest.mark.parametrize( "name,par,wires,expected_output", [ diff --git a/tests/test_var.py b/tests/test_var.py index 1c7bcbf459..c5b700c58c 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -63,7 +63,11 @@ def test_projector_var(self, theta, phi, qubit_device, tol): init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) - obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) if device_name != "lightning.tensor" else qml.Projector(np.array([0, 1]) / np.sqrt(2), wires=[1]) + obs = ( + qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) + if device_name != "lightning.tensor" + else qml.Projector(np.array([0, 1]) / np.sqrt(2), wires=[1]) + ) def circuit(): qml.StatePrep(init_state, wires=range(n_qubits)) From 9e4d005053d10670c26d165de38cafa10299f4c5 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 11:38:31 +0000 Subject: [PATCH 155/227] Trigger CI From 14061f783b129e5047f82e30118e2d9e6468e567 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Tue, 13 Aug 2024 11:39:25 +0000 Subject: [PATCH 156/227] Auto update version from '0.38.0-dev29' to '0.38.0-dev31' --- 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 68d119cc24..955e962322 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.38.0-dev29" +__version__ = "0.38.0-dev31" From 59fe1b04e20722742afb8db94689d22bc65ddb38 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 13:24:01 +0000 Subject: [PATCH 157/227] tidy up code --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 22 +-- .../lightning_tensor/tncuda/TNCudaBase.hpp | 125 ------------------ .../measurements/MeasurementsTNCuda.hpp | 1 - 3 files changed, 1 insertion(+), 147 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 7244db3987..4c65e09c01 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -274,27 +274,7 @@ class MPSTNCuda final : public TNCudaBase> { PL_ABORT_IF(log2(avail_gpu_memory) < BaseType::getNumQubits(), "State tensor size exceeds the available GPU memory!"); - this->get_state_tensor(res); - } - - /** - * @brief Get the full state vector representation of a MPS quantum state. - * Note that users/developers should be responsible to ensure that there is - * sufficient memory on the host to store the full state vector. - * - * @param res Pointer to the host memory to store the full state vector - * @param res_length Length of the result vector - */ - void getData(ComplexT *res, const std::size_t res_length) { - PL_ABORT_IF(log2(res_length) != BaseType::getNumQubits(), - "The size of the result vector should be equal to the " - "dimension of the quantum state."); - - std::size_t avail_gpu_memory = getFreeMemorySize(); - - PL_ABORT_IF(log2(avail_gpu_memory) < BaseType::getNumQubits(), - "State tensor size exceeds the available GPU memory!"); - this->get_state_tensor(res); + BaseType::get_state_tensor(res); } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index dcaa95aceb..31f1f5a361 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -401,131 +401,6 @@ class TNCudaBase : public TensornetBase { static_cast(gate_cache_->get_gate_device_ptr(id)), /* int32_t unitary*/ 1)); } - /** - * @brief Get the state vector representation of a tensor network. - * - * @param host_data Pointer to the host memory for state tensor data. - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is set to 1 by default. - */ - void get_state_tensor(ComplexT *host_data, - const int32_t numHyperSamples = 1) { - std::vector wires(BaseType::getNumQubits()); - std::iota(wires.begin(), wires.end(), 0); - - const std::size_t length = std::size_t{1} << wires.size(); - - DataBuffer d_output_tensor(length, getDevTag(), true); - - get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), - wires, numHyperSamples); - - d_output_tensor.CopyGpuDataToHost(host_data, length); - } - - /** - * @brief Get a slice of the state tensor - * - * @param tensor_data Pointer to the device memory for state tensor data. - * @param tensor_data_size Size of the state tensor data. - * @param wires Wires to get the state tensor for. - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is set to 1 by default. - */ - void get_state_tensor(CFP_t *tensor_data, - const std::size_t tensor_data_size, - const std::vector &wires, - const int32_t numHyperSamples = 1) { - // NOTE: this is a solution to get the full state tensor - // TODO: projected_modes and projectedModeValues are to be updated for - // prob() support. - auto stateModes = cuUtil::NormalizeCastIndices( - wires, BaseType::getNumQubits()); - - std::vector projected_modes{}; - - std::vector projectedModeValues{}; - - cutensornetStateAccessor_t accessor; - PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateAccessor( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* int32_t numProjectedModes */ - static_cast(projected_modes.size()), - /* const int32_t *projectedModes */ projected_modes.data(), - /* const int64_t *amplitudesTensorStrides */ nullptr, - /* cutensornetStateAccessor_t *tensorNetworkAccessor*/ &accessor)); - - // Configure the computation - const cutensornetAccessorAttributes_t accessor_attribute = - CUTENSORNET_ACCESSOR_CONFIG_NUM_HYPER_SAMPLES; - PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorConfigure( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetStateAccessor_t */ accessor, - /* cutensornetAccessorAttributes_t */ accessor_attribute, - /* const void * */ &numHyperSamples, - /* size_t */ sizeof(numHyperSamples))); - - // prepare the computation - cutensornetWorkspaceDescriptor_t workDesc; - PL_CUTENSORNET_IS_SUCCESS( - cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); - - // TODO we assign half (magic number is) of free memory size to the - // maximum memory usage. - const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; - - PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorPrepare( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetStateAccessor_t*/ accessor, - /* size_t */ scratchSize, - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* cudaStream_t unused as of v24.03 */ 0x0)); - - // Allocate workspace buffer - std::size_t worksize = - getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); - - PL_ABORT_IF(worksize > scratchSize, - "Insufficient workspace size on Device!"); - - const std::size_t d_scratch_length = worksize / sizeof(std::size_t); - DataBuffer d_scratch(d_scratch_length, getDevTag(), - true); - - setWorkSpaceMemory(getTNCudaHandle(), workDesc, - reinterpret_cast(d_scratch.getData()), - worksize); - - // compute the specified slice of the quantum circuit amplitudes tensor - ComplexT stateNorm2{0.0, 0.0}; - PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorCompute( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetStateAccessor_t */ accessor, - /* const int64_t * projectedModeValues */ - projectedModeValues.data(), - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* void *amplitudesTensor*/ - static_cast(tensor_data), - /* void *stateNorm */ static_cast(&stateNorm2), - /* cudaStream_t cudaStream */ 0x0)); - - PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); - - const ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; - - CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; - - SharedCublasCaller cublascaller = make_shared_cublas_caller(); - - scaleC_CUDA(scale_scalar_cu, tensor_data, - tensor_data_size, getDevTag().getDeviceID(), - getDevTag().getStreamID(), *cublascaller); - - PL_CUTENSORNET_IS_SUCCESS( - cutensornetDestroyWorkspaceDescriptor(workDesc)); - PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); - } /** * @brief Save quantumState information to data provided by a user diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index a160312411..751ed64fba 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -120,7 +120,6 @@ template class MeasurementsTNCuda { tensor_network_.getDevTag().getStreamID(), tensor_network_.getCublasCaller(), &sum); - PL_ABORT_IF(sum == 0.0, "Sum of probabilities is zero."); normalizeProbs_CUDA(d_output_probs.getData(), length, sum, From bced445b1d697d80010b4e61faa67304dc847be7 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Tue, 13 Aug 2024 13:24:26 +0000 Subject: [PATCH 158/227] Auto update version from '0.38.0-dev31' to '0.38.0-dev32' --- 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 955e962322..1e786a92cd 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.38.0-dev31" +__version__ = "0.38.0-dev32" From 87ac938c2a05dc646b4b35da92bb6c293015933b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 13:47:20 +0000 Subject: [PATCH 159/227] tidy up python layer --- tests/new_api/test_device.py | 4 ---- tests/test_comparison.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 866e2bebe7..3a9dc07ddb 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -463,10 +463,6 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): """Test that execute returns the correct results with multiple measurements.""" - if device_name == "lightning.tensor": - if isinstance(mp1, ProbabilityMP) or isinstance(mp2, ProbabilityMP): - pytest.skip("qml.probs() not supported in lightning.tensor") - if isinstance(mp2.obs, qml.ops.LinearCombination) and not qml.operation.active_new_opmath(): mp2.obs = qml.operation.convert_to_legacy_H(mp2.obs) diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 887ccff8a3..4967b72bd0 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -269,7 +269,7 @@ def circuit(measurement): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor device dose not support initialization with a state vector", + reason="lightning.tensor device does not support initialization with a state vector", ) @pytest.mark.parametrize( "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] From f8e5f48cb97036c9a7cf0ff897b39dac1700fa85 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:02:09 +0000 Subject: [PATCH 160/227] add docstring --- .../src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 4c65e09c01..624a7389dc 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -225,7 +225,7 @@ class MPSTNCuda final : public TNCudaBase> { // Optional: SVD cutensornetTensorSVDAlgo_t algo = - CUTENSORNET_TENSOR_SVD_ALGO_GESVDJ; // default + CUTENSORNET_TENSOR_SVD_ALGO_GESVDJ; // default option PL_CUTENSORNET_IS_SUCCESS(cutensornetStateConfigure( /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), @@ -254,6 +254,11 @@ class MPSTNCuda final : public TNCudaBase> { const_cast(getSitesExtentsPtr().data()), reinterpret_cast(getTensorsOutDataPtr().data())); + // TODO: This is a dummy tensor update to allow multiple calls to the + // `append_mps_final_state` method as well as appending additional + // operations to the graph. This line can be removed in the future when + // the `cutensornet` backend allows multiple calls to the + // `cutensornetStateFinalizeMPS` method. BaseType::dummy_tensor_update(); } From 48db9a0ac5e7c5b5652c619c40a256bc212c8d37 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:05:48 +0000 Subject: [PATCH 161/227] add changelog --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 27c0442c8a..1343185407 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add `qml.prob()` measurement support to `lightning.tensor`. + [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) + * Add `qml.state()` measurement support to `lightning.tensor`. [(#827)](https://github.com/PennyLaneAI/pennylane-lightning/pull/827) From 5b4810ba8e05560a291488cc99b6a146e06aea38 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:10:58 +0000 Subject: [PATCH 162/227] fix typo --- .github/CHANGELOG.md | 2 +- .../tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 1343185407..ac4a627e75 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `qml.prob()` measurement support to `lightning.tensor`. +* Add `qml.probs()` measurement support to `lightning.tensor`. [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) * Add `qml.state()` measurement support to `lightning.tensor`. diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp index 0bacdcbf9b..3000e80054 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp @@ -80,6 +80,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Identity", {index}, inverse); + // Test for multiple final states appendings mps_state.append_mps_final_state(); cp_t expected(1.0 / std::sqrt(2), 0); From 20859314629b2248de6dd117e90617682741645a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:37:48 +0000 Subject: [PATCH 163/227] further tidy up the code --- .github/CHANGELOG.md | 3 + .../lightning_tensor/tncuda/TNCudaBase.hpp | 158 ++++++++++-------- 2 files changed, 88 insertions(+), 73 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index ac4a627e75..70b97ac82c 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -30,6 +30,9 @@ ### Improvements +* Multiple calls to the `append_mps_final_state()` API is allowed. + [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) + * `ENABLE_LAPACK` is off by default for all Lightning backends. [(#825)](https://github.com/PennyLaneAI/pennylane-lightning/pull/825) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 31f1f5a361..0d69fcc61c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -315,7 +315,7 @@ class TNCudaBase : public TensornetBase { * * @param host_data Pointer to the host memory for state tensor data. * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. + * and is set to 1 by default. */ void get_state_tensor(ComplexT *host_data, const int32_t numHyperSamples = 1) { @@ -335,13 +335,11 @@ class TNCudaBase : public TensornetBase { /** * @brief Get a slice of the full state tensor * - * @param tensor_data Pointer to the tensor data on the device memory. + * @param tensor_data Pointer to the device memory for state tensor data. * @param tensor_data_size Size of the tensor data. * @param wires Wires to get the state tensor for. * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. - * - * @return Full state tensor on the host memory + * and is set to 1 by default. */ void get_state_tensor(CFP_t *tensor_data, const std::size_t tensor_data_size, @@ -385,76 +383,17 @@ class TNCudaBase : public TensornetBase { } } - protected: - void dummy_tensor_update() { - if (gate_cache_->is_cache_empty()) { - applyOperation("Identity", {0}, false); - } - - std::size_t id = gate_cache_->get_cache_head_idx(); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* int64_t tensorId*/ static_cast(id), - /* void* */ - static_cast(gate_cache_->get_gate_device_ptr(id)), - /* int32_t unitary*/ 1)); - } - - /** - * @brief Save quantumState information to data provided by a user - * - * @param tensorPtr Pointer to tensors provided by a user - */ - void computeState(int64_t **extentsPtr, void **tensorPtr) { - cutensornetWorkspaceDescriptor_t workDesc; - PL_CUTENSORNET_IS_SUCCESS( - cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); - - // TODO we assign half (magic number is) of free memory size to the - // maximum memory usage. - const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStatePrepare( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* size_t maxWorkspaceSizeDevice */ scratchSize, - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* cudaStream_t unused as of v24.03*/ 0x0)); - - std::size_t worksize = - getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); - - PL_ABORT_IF(worksize > scratchSize, - "Insufficient workspace size on Device!"); - - const std::size_t d_scratch_length = worksize / sizeof(std::size_t); - DataBuffer d_scratch(d_scratch_length, getDevTag(), - true); - - setWorkSpaceMemory(getTNCudaHandle(), workDesc, - reinterpret_cast(d_scratch.getData()), - worksize); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateCompute( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* int64_t * */ extentsPtr, - /* int64_t *stridesOut */ nullptr, - /* void * */ tensorPtr, - /* cudaStream_t */ getDevTag().getStreamID())); - - PL_CUTENSORNET_IS_SUCCESS( - cutensornetDestroyWorkspaceDescriptor(workDesc)); - } - private: /** * @brief Get accessor of a state tensor + * + * @param tensor_data Pointer to the device memory for state tensor data. + * @param tensor_data_size Size of the tensor data. + * @param projected_modes Projected modes to get the state tensor for. + * @param projectedModeValues Values of the projected modes. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is set to 1 by default. */ - void get_accessor_(CFP_t *tensor_data, const std::size_t tensor_data_size, const std::vector &projected_modes, const std::vector &projectedModeValues, @@ -470,7 +409,7 @@ class TNCudaBase : public TensornetBase { /* cutensornetStateAccessor_t *tensorNetworkAccessor*/ &accessor)); // Configure the computation - cutensornetAccessorAttributes_t accessor_attribute = + const cutensornetAccessorAttributes_t accessor_attribute = CUTENSORNET_ACCESSOR_CONFIG_NUM_HYPER_SAMPLES; PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorConfigure( /* const cutensornetHandle_t */ getTNCudaHandle(), @@ -525,7 +464,7 @@ class TNCudaBase : public TensornetBase { PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); - ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; + const ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; @@ -537,5 +476,78 @@ class TNCudaBase : public TensornetBase { cutensornetDestroyWorkspaceDescriptor(workDesc)); PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); } + + protected: + /** + * @brief Dummy tensor operator update to allow multiple calls of + * appendMPSFinalize. This is a workaround to avoid the issue of the + * cutensornet library not allowing multiple calls of appendMPSFinalize. + * + * This function either appends a new `Identity` gate to the graph when the + * gate cache is empty or update the exisisting gate operator by itself. + */ + void dummy_tensor_update() { + if (gate_cache_->is_cache_empty()) { + applyOperation("Identity", {0}, false); + } + + std::size_t id = gate_cache_->get_cache_head_idx(); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* int64_t tensorId*/ static_cast(id), + /* void* */ + static_cast(gate_cache_->get_gate_device_ptr(id)), + /* int32_t unitary*/ 1)); + } + + /** + * @brief Save quantumState information to data provided by a user + * + * @param tensorPtr Pointer to tensors provided by a user + */ + void computeState(int64_t **extentsPtr, void **tensorPtr) { + cutensornetWorkspaceDescriptor_t workDesc; + PL_CUTENSORNET_IS_SUCCESS( + cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); + + // TODO we assign half (magic number is) of free memory size to the + // maximum memory usage. + const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStatePrepare( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* size_t maxWorkspaceSizeDevice */ scratchSize, + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* cudaStream_t unused as of v24.03*/ 0x0)); + + std::size_t worksize = + getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); + + PL_ABORT_IF(worksize > scratchSize, + "Insufficient workspace size on Device!"); + + const std::size_t d_scratch_length = worksize / sizeof(std::size_t); + DataBuffer d_scratch(d_scratch_length, getDevTag(), + true); + + setWorkSpaceMemory(getTNCudaHandle(), workDesc, + reinterpret_cast(d_scratch.getData()), + worksize); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateCompute( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* int64_t * */ extentsPtr, + /* int64_t *stridesOut */ nullptr, + /* void * */ tensorPtr, + /* cudaStream_t */ getDevTag().getStreamID())); + + PL_CUTENSORNET_IS_SUCCESS( + cutensornetDestroyWorkspaceDescriptor(workDesc)); + } }; } // namespace Pennylane::LightningTensor::TNCuda From bcc41a1ec47de8b46d232a278d53723bc9a251ec Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:42:04 +0000 Subject: [PATCH 164/227] fix typo --- .../core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 0d69fcc61c..3fcc88bcc3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -336,7 +336,7 @@ class TNCudaBase : public TensornetBase { * @brief Get a slice of the full state tensor * * @param tensor_data Pointer to the device memory for state tensor data. - * @param tensor_data_size Size of the tensor data. + * @param tensor_data_size Size of the state tensor data. * @param wires Wires to get the state tensor for. * @param numHyperSamples Number of hyper samples to use in the calculation * and is set to 1 by default. From e104919251b5be36b76cb376b81f218ba9f4733a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:49:16 +0000 Subject: [PATCH 165/227] update docstring --- .../src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 624a7389dc..26d4d27d6e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -256,9 +256,9 @@ class MPSTNCuda final : public TNCudaBase> { // TODO: This is a dummy tensor update to allow multiple calls to the // `append_mps_final_state` method as well as appending additional - // operations to the graph. This line can be removed in the future when - // the `cutensornet` backend allows multiple calls to the - // `cutensornetStateFinalizeMPS` method. + // operations to the graph. This is a temporary solution and this line + // can be removed in the future when the `cutensornet` backend allows + // multiple calls to the `cutensornetStateFinalizeMPS` method. BaseType::dummy_tensor_update(); } From f99b94e123b704df2b69fdeaf390efb8c7bd8859 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 13:01:12 +0000 Subject: [PATCH 166/227] add todo --- pennylane_lightning/lightning_tensor/lightning_tensor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index df2200c74d..6fb6b798c0 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -278,6 +278,7 @@ def __init__( self._method = method self._c_dtype = c_dtype + # Set default values aligned with default.tensor self._max_bond_dim = kwargs.get("max_bond_dim", 128) self._cutoff = kwargs.get("cutoff", 0) self._cutoff_mode = kwargs.get("cutoff_mode", "abs") From d9fb3a33ca1bdc647b41dd433e1008a819c33d91 Mon Sep 17 00:00:00 2001 From: Astral Cai Date: Mon, 12 Aug 2024 15:12:00 -0400 Subject: [PATCH 167/227] Use `decomposition` instead of `Operator.expand` (#846) `Operator.expand` is deprecated (https://github.com/PennyLaneAI/pennylane/pull/5994). `Operator.decomposition` should be used instead. --------- Co-authored-by: ringo-but-quantum Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- .github/CHANGELOG.md | 5 ++++- pennylane_lightning/core/_serialize.py | 2 +- tests/test_serialize.py | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 54a4e706a7..002ffa651e 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -76,6 +76,9 @@ * Move `setBasisState`, `setStateVector` and `resetStateVector` from `StateVectorLQubitManaged` to `StateVectorLQubit`. [(#841)](https://github.com/PennyLaneAI/pennylane-lightning/pull/841) +* Remove use of the deprecated `Operator.expand` in favour of `Operator.decomposition`. + [(#846)](https://github.com/PennyLaneAI/pennylane-lightning/pull/846) + ### Documentation * Updated the README and added citation format for Lightning arxiv preprint. @@ -111,7 +114,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Amintor Dusko, Vincent Michaud-Rioux, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang +Ali Asadi, Astral Cai, Amintor Dusko, Vincent Michaud-Rioux, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Paul Haochen Wang --- diff --git a/pennylane_lightning/core/_serialize.py b/pennylane_lightning/core/_serialize.py index 4f8a9ab567..1ec5e5ddd1 100644 --- a/pennylane_lightning/core/_serialize.py +++ b/pennylane_lightning/core/_serialize.py @@ -404,7 +404,7 @@ def get_wires(operation, single_op): uses_stateprep = True continue if isinstance(operation, Rot): - op_list = operation.expand().operations + op_list = operation.decomposition() else: op_list = [operation] diff --git a/tests/test_serialize.py b/tests/test_serialize.py index 5de35aa659..6860c19410 100644 --- a/tests/test_serialize.py +++ b/tests/test_serialize.py @@ -740,6 +740,29 @@ def test_basic_circuit(self, wires_map): ) assert s == s_expected + @pytest.mark.parametrize("wires_map", [wires_dict, None]) + def test_Rot_in_circuit(self, wires_map): + """Test expected serialization for a circuit with Rot which should be decomposed""" + + with qml.queuing.AnnotatedQueue() as q: + qml.Rot(0.1, 0.2, 0.3, wires=0) + + tape = qml.tape.QuantumScript.from_queue(q) + s = QuantumScriptSerializer(device_name).serialize_ops(tape, wires_map) + s_expected = ( + ( + ["RZ", "RY", "RZ"], + [np.array([0.1]), np.array([0.2]), np.array([0.3])], + [[0], [0], [0]], + [False, False, False], + [[], [], []], + [[], [], []], + [[], [], []], + ), + False, + ) + assert s == s_expected + @pytest.mark.parametrize("wires_map", [wires_dict, None]) def test_basic_circuit_not_implemented_ctrl_ops(self, wires_map): """Test expected serialization for a simple circuit""" From 36550e39bda24c396d3524fc35bc7d23945b8b64 Mon Sep 17 00:00:00 2001 From: Amintor Dusko <87949283+AmintorDusko@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:41:25 -0400 Subject: [PATCH 168/227] Update Lightning packaging to follow the PEP 517/518/621/660 standards (#832) **Context:** This PR updates the Lightning Python packaging to the latest standard. This allows us to eliminate pip~=22.0 from requirements*.txt, comply with up-to-date build practices, and fix the inability to build Lightning in place on newer Python environments. **Description of the Change:** Most of the building configuration was moved to the ``pyproject.toml`` file. We kept the ``setup.py`` file working with setuptools in part of the configuration pre-processing. A script with some pre-pre-processing was added to configure the ``pyproject.toml`` file for each backend. **Benefits:** Follow the new standard. Allows the use of more up-to-date pip versions. There will be no impact on the final user, as the installation of the wheels is unaffected by the change in packaging. **Possible Drawbacks:** When building and installing Lightning backends from scratch, we need to run the configuration script. If not the installation will default to ``lightning.qubit``, or the last configuration. **Related GitHub Issues:** [sc-65227] --------- Co-authored-by: ringo-but-quantum Co-authored-by: Lee James O'Riordan Co-authored-by: Vincent Michaud-Rioux --- .github/CHANGELOG.md | 5 +- .github/workflows/format.yml | 2 +- .github/workflows/tests_lgpu_python.yml | 11 +- .github/workflows/tests_lgpumpi_python.yml | 6 +- .github/workflows/tests_lkcpu_python.yml | 8 +- .github/workflows/tests_lkcuda_python.yml | 17 ++- .../workflows/tests_lmps_tncuda_python.yml | 38 +++---- .github/workflows/tests_lqcpu_python.yml | 5 +- .github/workflows/tests_windows_cpp.yml | 2 +- .github/workflows/tests_without_binary.yml | 29 ++--- .github/workflows/wheel_linux_aarch64.yml | 15 ++- .github/workflows/wheel_linux_ppc64le.yml | 9 +- .github/workflows/wheel_linux_x86_64.yml | 23 ++-- .github/workflows/wheel_linux_x86_64_cuda.yml | 18 ++-- .github/workflows/wheel_macos_arm64.yml | 17 +-- .github/workflows/wheel_macos_x86_64.yml | 13 ++- .github/workflows/wheel_noarch.yml | 43 ++++---- .github/workflows/wheel_win_x86_64.yml | 13 ++- .gitignore | 1 + .readthedocs.yml | 10 +- CMakeLists.txt | 8 +- MANIFEST.in | 4 + Makefile | 15 ++- README.rst | 44 ++++---- docker/Dockerfile | 21 ++-- pennylane_lightning/core/__init__.py | 2 +- pennylane_lightning/lightning_gpu/__init__.py | 2 +- .../lightning_kokkos/__init__.py | 2 +- .../lightning_qubit/__init__.py | 2 +- pyproject.toml | 28 +++++ requirements-dev.txt | 2 +- scripts/backend_support.py | 56 ++++++++++ scripts/configure_pyproject_toml.py | 99 +++++++++++++++++ scripts/gen_pyver_matrix.py | 4 +- setup.py | 101 ++---------------- 35 files changed, 401 insertions(+), 274 deletions(-) create mode 100644 pyproject.toml create mode 100755 scripts/backend_support.py create mode 100755 scripts/configure_pyproject_toml.py mode change 100644 => 100755 scripts/gen_pyver_matrix.py diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 002ffa651e..27c0442c8a 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -6,7 +6,7 @@ [(#827)](https://github.com/PennyLaneAI/pennylane-lightning/pull/827) * Add `var` support to `lightning.tensor`. Note that `var` support is added via `obs**2` and this implementation scales `O(num_obs**2)`. - [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) + [(#804)](https://github.com/PennyLaneAI/pennylane-lightning/pull/804) ### Breaking changes @@ -22,6 +22,9 @@ * Do not run GPU tests and Docker workflows on release. [(#788)](https://github.com/PennyLaneAI/pennylane-lightning/pull/788) +* Update python packaging to follow PEP 517/518/621/660 standards. + [(#832)](https://github.com/PennyLaneAI/pennylane-lightning/pull/832) + ### Improvements * `ENABLE_LAPACK` is off by default for all Lightning backends. diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index bc29a7dfb3..2fd60dda5c 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -38,7 +38,7 @@ jobs: uses: actions/checkout@v4 - name: Install dependencies - run: sudo apt update && sudo apt -y install python3 python3-pip && python -m pip install pip~=22.0 && python3 -m pip install -r requirements-dev.txt + run: sudo apt update && sudo apt -y install python3 python3-pip python-is-python3 && python -m pip install -r requirements-dev.txt - name: Run formatter run: PATH=$PATH:/home/ubuntu/.local/bin/:$(dirname $(which python3))/ ./bin/format --check ./pennylane_lightning/core/src diff --git a/.github/workflows/tests_lgpu_python.yml b/.github/workflows/tests_lgpu_python.yml index 51f02859ba..12b61392a3 100644 --- a/.github/workflows/tests_lgpu_python.yml +++ b/.github/workflows/tests_lgpu_python.yml @@ -64,7 +64,6 @@ jobs: strategy: matrix: pl_backend: ["lightning_gpu"] - default_backend: ["lightning_qubit"] cuda_version: ["12"] name: Python Tests (${{ matrix.pl_backend }}, cuda-${{ matrix.cuda_version }}) @@ -129,8 +128,7 @@ jobs: echo "venv_name=${{ env.VENV_NAME }}" >> $GITHUB_OUTPUT echo "Python_ROOT_DIR=${{ env.VENV_NAME }}" >> $GITHUB_ENV echo "Python3_ROOT_DIR=${{ env.VENV_NAME }}" >> $GITHUB_ENV - - + # Adding venv site-packages to output for subsequent step to referecen if needed echo "site_packages_dir=$(${{ env.VENV_NAME }}/bin/python -c 'import sysconfig; print(sysconfig.get_path("platlib"))')" >> $GITHUB_OUTPUT @@ -179,12 +177,13 @@ jobs: run: | cd main rm -rf build - CMAKE_ARGS="-DPL_BACKEND=${{ matrix.default_backend }} -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ + PL_BACKEND=lightning_qubit python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ python -m pip install . -vv - rm -rf build rm -rf build - CMAKE_ARGS="-DPL_BACKEND=${{ matrix.pl_backend }} -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) -DPython_EXECUTABLE=${{ steps.python_path.outputs.python }}" \ + PL_BACKEND=${{ matrix.pl_backend }} python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) -DPython_EXECUTABLE=${{ steps.python_path.outputs.python }}" \ python -m pip install . -vv - name: Run PennyLane-Lightning-GPU unit tests diff --git a/.github/workflows/tests_lgpumpi_python.yml b/.github/workflows/tests_lgpumpi_python.yml index 9a27030a07..ab2eda478c 100644 --- a/.github/workflows/tests_lgpumpi_python.yml +++ b/.github/workflows/tests_lgpumpi_python.yml @@ -110,7 +110,8 @@ jobs: python -m pip install -r requirements-dev.txt python -m pip install custatevec-cu${{ matrix.cuda_version_maj }} mpi4py openfermionpyscf - PL_BACKEND=lightning_qubit python -m pip install . -vv + PL_BACKEND=lightning_qubit python scripts/configure_pyproject_toml.py + python -m pip install . -vv - name: Checkout PennyLane for release build if: inputs.pennylane-version == 'release' @@ -132,8 +133,9 @@ jobs: CUQUANTUM_SDK: $(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") run: | source /etc/profile.d/modules.sh && module use /opt/modules/ && module load ${{ matrix.mpilib }}/cuda-${{ matrix.cuda_version_maj }}.${{ matrix.cuda_version_min }} + PL_BACKEND=lightning_gpu python scripts/configure_pyproject_toml.py CMAKE_ARGS="-DCMAKE_C_COMPILER=mpicc -DCMAKE_CXX_COMPILER=mpicxx -DENABLE_MPI=ON -DCMAKE_CUDA_COMPILER=$(which nvcc) -DCMAKE_CUDA_ARCHITECTURES=${{ env.CI_CUDA_ARCH }} -DPython_EXECUTABLE=${{ steps.python_path.outputs.python }}" \ - PL_BACKEND=lightning_gpu python -m pip install . --verbose + python -m pip install . -vv # There are issues running py-cov with MPI. A solution is to use coverage as reported # [here](https://github.com/pytest-dev/pytest-cov/issues/237#issuecomment-544824228) diff --git a/.github/workflows/tests_lkcpu_python.yml b/.github/workflows/tests_lkcpu_python.yml index 1dbad00706..b7d6743114 100644 --- a/.github/workflows/tests_lkcpu_python.yml +++ b/.github/workflows/tests_lkcpu_python.yml @@ -117,13 +117,14 @@ jobs: cd main python -m pip install -r requirements-dev.txt - - name: Create device wheel + - name: Configure and build device wheel env: PL_BACKEND: ${{ matrix.pl_backend }} run: | cd main - python setup.py build_ext -i --define="PL_BACKEND=${{ matrix.pl_backend }};CMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos;ENABLE_PYTHON=ON;CMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" - python setup.py bdist_wheel + python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ + python -m build cd dist WHEEL_NAME=$(ls *.whl) cp $WHEEL_NAME ${{ github.workspace }}/wheel_${{ matrix.pl_backend }}-${{ matrix.exec_model }}.whl @@ -211,6 +212,7 @@ jobs: python -m pip install -r requirements-dev.txt python -m pip install openfermionpyscf if [ '${{ inputs.lightning-version }}' != 'stable' ]; then + python scripts/configure_pyproject_toml.py SKIP_COMPILATION=True python -m pip install . -vv fi python -m pip install ${{ github.workspace }}/$WHEEL_NAME --no-deps diff --git a/.github/workflows/tests_lkcuda_python.yml b/.github/workflows/tests_lkcuda_python.yml index 45b012175d..ac06468988 100644 --- a/.github/workflows/tests_lkcuda_python.yml +++ b/.github/workflows/tests_lkcuda_python.yml @@ -241,8 +241,12 @@ jobs: run: | ls -l ${{ github.workspace }}/Kokkos cd main - SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" python -m pip install . -vv - CMAKE_ARGS="-DPL_BACKEND=${{ matrix.pl_backend }} -DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ + + PL_BACKEND=lightning_qubit python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True python -m pip install . -vv + + PL_BACKEND=${{ matrix.pl_backend }} python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ python -m pip install . -vv - name: Run PennyLane-Lightning unit tests @@ -262,10 +266,13 @@ jobs: if: ${{ matrix.pl_backend == 'all' }} run: | cd main - CMAKE_ARGS="-DPL_BACKEND="lightning_qubit" -DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ + + PL_BACKEND=lightning_qubit python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ python -m pip install . -vv - rm -rf build - CMAKE_ARGS="-DPL_BACKEND="lightning_kokkos" -DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ + + PL_BACKEND="lightning_kokkos" python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ python -m pip install . -vv - name: Run PennyLane-Lightning unit tests for lightning.qubit with all devices installed diff --git a/.github/workflows/tests_lmps_tncuda_python.yml b/.github/workflows/tests_lmps_tncuda_python.yml index 1bfec32e0b..d10eb0254f 100644 --- a/.github/workflows/tests_lmps_tncuda_python.yml +++ b/.github/workflows/tests_lmps_tncuda_python.yml @@ -60,7 +60,7 @@ jobs: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> $GITHUB_ENV nvcc --version nvidia-smi - + pythontestswithMPSTNCuda: if: ${{ !contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} needs: [builddeps] @@ -68,12 +68,11 @@ jobs: matrix: os: [ubuntu-22.04] pl_backend: ["lightning_tensor"] - default_backend: ["lightning_qubit"] pl_tensor_method: ["mps"] pl_tensor_backend: ["cutensornet"] cuda_version: ["12"] - name: Python Tests (${{ matrix.pl_backend }}, method-${{ matrix.pl_tensor_method }}, backend-${{ matrix.pl_tensor_backend }}, cuda-${{ matrix.cuda_version }}) + name: Python Tests (${{ matrix.pl_backend }}, method-${{ matrix.pl_tensor_method }}, backend-${{ matrix.pl_tensor_backend }}, cuda-${{ matrix.cuda_version }}) runs-on: - ${{ matrix.os }} - self-hosted @@ -92,14 +91,12 @@ jobs: - name: Checkout PennyLane-Lightning-Tensor-MPS-TNCuda uses: actions/checkout@v4 - with: - path: main - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.9' - + # Since the self-hosted runner can be re-used. It is best to set up all package # installations in a virtual environment that gets cleaned at the end of each workflow run - name: Setup Python virtual environment @@ -116,13 +113,13 @@ jobs: # Add the venv to PATH for subsequent steps echo ${{ env.VENV_NAME }}/bin >> $GITHUB_PATH - + # Adding venv name as an output for subsequent steps to reference if needed source ${{ env.VENV_NAME }}/bin/activate echo "venv_name=${{ env.VENV_NAME }}" >> $GITHUB_OUTPUT echo "Python_ROOT_DIR=${{ env.VENV_NAME }}" >> $GITHUB_ENV echo "Python3_ROOT_DIR=${{ env.VENV_NAME }}" >> $GITHUB_ENV - + # Adding venv site-packages to output for subsequent step to referecen if needed echo "site_packages_dir=$(${{ env.VENV_NAME }}/bin/python -c 'import sysconfig; print(sysconfig.get_path("platlib"))')" >> $GITHUB_OUTPUT @@ -139,7 +136,6 @@ jobs: - name: Install required packages run: | - cd main python -m pip install -r requirements-dev.txt python -m pip install ninja cmake scipy custatevec-cu${{ matrix.cuda_version }} cutensornet-cu${{ matrix.cuda_version }} openfermionpyscf @@ -157,29 +153,25 @@ jobs: git fetch --all git checkout $(git branch -a --list "origin/v0.*rc*" | sort | tail -1) python -m pip uninstall -y pennylane && python -m pip install . -vv --no-deps - + - name: Install Stable PennyLane if: inputs.pennylane-version == 'stable' run: | - cd main python -m pip uninstall -y pennylane && python -m pip install -U pennylane - - - name: Build and install package + + - name: Configure and install required backends run: | - cd main - rm -rf build - CMAKE_ARGS="-DPL_BACKEND=${{ matrix.default_backend }} -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ - python -m pip install . -vv rm -rf build - + PL_BACKEND=lightning_qubit python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" python -m pip install . -vv + rm -rf build - CMAKE_ARGS="-DPL_BACKEND=${{ matrix.pl_backend }} -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ - python -m pip install . -vv - + PL_BACKEND="${{ matrix.pl_backend }}" python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" python -m pip install . -vv + - name: Run PennyLane-Lightning-Tensor unit tests if: ${{ matrix.pl_backend != 'all'}} run: | - cd main/ DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"` PL_DEVICE=${DEVICENAME} python -m pytest tests $COVERAGE_FLAGS mv coverage.xml coverage-${{ github.job }}-${{ matrix.pl_backend }}.xml @@ -188,7 +180,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: ubuntu-codecov-results-python - path: ./main/coverage-${{ github.job }}-${{ matrix.pl_backend }}.xml + path: coverage-${{ github.job }}-${{ matrix.pl_backend }}.xml if-no-files-found: error diff --git a/.github/workflows/tests_lqcpu_python.yml b/.github/workflows/tests_lqcpu_python.yml index 80a9827f74..84307cbaa0 100644 --- a/.github/workflows/tests_lqcpu_python.yml +++ b/.github/workflows/tests_lqcpu_python.yml @@ -86,8 +86,9 @@ jobs: id: create_lq_wheel run: | cd main - python setup.py build_ext -i --define="PL_BACKEND=${{ matrix.pl_backend }};ENABLE_BLAS=${{ matrix.blas }};LQ_ENABLE_KERNEL_OMP=ON;ENABLE_PYTHON=ON;CMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" - PL_BACKEND=${{ matrix.pl_backend }} python setup.py bdist_wheel + PL_BACKEND=${{ matrix.pl_backend }} python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DENABLE_BLAS=${{ matrix.blas }} -DLQ_ENABLE_KERNEL_OMP=ON -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ + python -m build cd dist WHEEL_NAME=$(ls *.whl) cp $WHEEL_NAME ${{ github.workspace }}/wheel_${{ matrix.pl_backend }}-${{ matrix.blas }}.whl diff --git a/.github/workflows/tests_windows_cpp.yml b/.github/workflows/tests_windows_cpp.yml index 1b2e7522a6..a35d2f0a46 100644 --- a/.github/workflows/tests_windows_cpp.yml +++ b/.github/workflows/tests_windows_cpp.yml @@ -114,7 +114,7 @@ jobs: python-version: '3.9' - name: Checkout PennyLane-Lightning - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install dependencies run: | diff --git a/.github/workflows/tests_without_binary.yml b/.github/workflows/tests_without_binary.yml index eb2745e6ce..64c059bc27 100644 --- a/.github/workflows/tests_without_binary.yml +++ b/.github/workflows/tests_without_binary.yml @@ -46,19 +46,16 @@ jobs: uses: actions/checkout@v4 with: fetch-tags: true - path: main - name: Switch to release build of Lightning if: inputs.lightning-version == 'release' run: | - cd main git fetch --all git checkout $(git branch -a --list "origin/v0.*rc*" | sort | tail -1) - name: Switch to stable build of Lightning if: inputs.lightning-version == 'stable' run: | - cd main git fetch --tags --force git checkout latest_release git log -1 --format='%H' @@ -72,7 +69,6 @@ jobs: - name: Get required Python packages run: | rm -fr $(python -m pip cache dir)/selfcheck/ - cd main python -m pip install -r requirements-dev.txt - name: Checkout PennyLane for release build @@ -93,39 +89,34 @@ jobs: - name: Install Stable PennyLane if: inputs.pennylane-version == 'stable' run: | - cd main python -m pip uninstall -y pennylane && python -m pip install -U pennylane - - name: Install the pennylane_lightning package - if: ${{ contains(fromJson('["lightning_kokkos", "lightning_gpu", "lightning_tensor"]'), matrix.pl_backend) }} + - name: Install the pennylane_lightning core package (lightning_qubit) + env: + SKIP_COMPILATION: True + PL_BACKEND: "lightning_qubit" run: | - cd main - SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" python -m pip install . -vv + python scripts/configure_pyproject_toml.py + python -m pip install . -vv - - name: Install backend device - # FIXME: Remove this condition with v0.37.0 release - if: matrix.pl_backend != 'lightning_tensor' || inputs.lightning-version != 'stable' + - name: Install extra backend device + if: matrix.pl_backend != 'lightning_qubit' env: SKIP_COMPILATION: True PL_BACKEND: ${{ matrix.pl_backend }} run: | - cd main + python scripts/configure_pyproject_toml.py python -m pip install . -vv - name: Run PennyLane-Lightning unit tests for all backends - # FIXME: Remove this condition with v0.37.0 release - if: matrix.pl_backend != 'lightning_tensor' || inputs.lightning-version != 'stable' run: | - cd main/ DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"` PL_DEVICE=${DEVICENAME} python -m pytest tests/ $COVERAGE_FLAGS - name: Upload coverage to Codecov - # FIXME: Remove this condition with v0.37.0 release - if: matrix.pl_backend != 'lightning_tensor' || inputs.lightning-version != 'stable' uses: codecov/codecov-action@v4 with: - files: ./main/coverage.xml + files: coverage.xml fail_ci_if_error: true verbose: true token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/wheel_linux_aarch64.yml b/.github/workflows/wheel_linux_aarch64.yml index ec090d9f7c..906e1ffc4d 100644 --- a/.github/workflows/wheel_linux_aarch64.yml +++ b/.github/workflows/wheel_linux_aarch64.yml @@ -119,8 +119,11 @@ jobs: mkdir Kokkos cp -rf ${{ github.workspace }}/Kokkos_install/${{ matrix.exec_model }}/* Kokkos/ - - name: Install cibuildwheel - run: python -m pip install cibuildwheel~=2.16.0 + - name: Install dependencies + run: python -m pip install cibuildwheel~=2.16.0 toml + + - name: Configure pyproject.toml file + run: PL_BACKEND="${{ matrix.pl_backend }}" python scripts/configure_pyproject_toml.py - uses: docker/setup-qemu-action@v2 name: Set up QEMU @@ -138,7 +141,7 @@ jobs: cat /etc/yum.conf | sed "s/\[main\]/\[main\]\ntimeout=5/g" > /etc/yum.conf python -m pip install ninja cmake~=3.24.0 - CIBW_ENVIRONMENT: PL_BACKEND="${{ matrix.pl_backend }}" CMAKE_ARGS="-DENABLE_LAPACK=OFF" + CIBW_ENVIRONMENT: CMAKE_ARGS="-DENABLE_LAPACK=OFF" CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 @@ -146,7 +149,11 @@ jobs: CIBW_BEFORE_TEST: | python -m pip install -r requirements-tests.txt - if ${{ matrix.pl_backend == 'lightning_kokkos'}}; then SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" python -m pip install . -vv; fi + if ${{ matrix.pl_backend == 'lightning_kokkos'}} + then + PL_BACKEND="lightning_qubit" python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True python -m pip install . -vv + fi CIBW_TEST_COMMAND: | DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"` diff --git a/.github/workflows/wheel_linux_ppc64le.yml b/.github/workflows/wheel_linux_ppc64le.yml index d305e53342..4fd172b225 100644 --- a/.github/workflows/wheel_linux_ppc64le.yml +++ b/.github/workflows/wheel_linux_ppc64le.yml @@ -118,12 +118,15 @@ jobs: mkdir Kokkos cp -rf ${{ github.workspace }}/Kokkos_install/${{ matrix.exec_model }}/* Kokkos/ - - name: Install cibuildwheel - run: python -m pip install cibuildwheel~=2.16.0 + - name: Install dependencies + run: python -m pip install cibuildwheel~=2.16.0 toml - uses: docker/setup-qemu-action@v2 name: Set up QEMU + - name: Configure pyproject.toml file + run: PL_BACKEND="${{ matrix.pl_backend }}" python scripts/configure_pyproject_toml.py + - name: Build wheels env: CIBW_ARCHS_LINUX: ${{matrix.arch}} @@ -137,7 +140,7 @@ jobs: cat /etc/yum.conf | sed "s/\[main\]/\[main\]\ntimeout=5/g" > /etc/yum.conf python -m pip install ninja cmake~=3.24.0 - CIBW_ENVIRONMENT: PL_BACKEND="${{ matrix.pl_backend }}" CMAKE_ARGS="-DENABLE_LAPACK=OFF" + CIBW_ENVIRONMENT: CMAKE_ARGS="-DENABLE_LAPACK=OFF" CIBW_MANYLINUX_PPC64LE_IMAGE: manylinux_2_28 diff --git a/.github/workflows/wheel_linux_x86_64.yml b/.github/workflows/wheel_linux_x86_64.yml index f91ff34e88..1d078a3fa8 100644 --- a/.github/workflows/wheel_linux_x86_64.yml +++ b/.github/workflows/wheel_linux_x86_64.yml @@ -53,7 +53,7 @@ jobs: steps: - name: Cache installation directories id: kokkos-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /root/Kokkos_install/${{ matrix.exec_model }} key: ${{ matrix.container_img }}-kokkos${{ matrix.kokkos_version }}-${{ matrix.exec_model }} @@ -115,13 +115,13 @@ jobs: steps: - name: Restoring cached dependencies id: kokkos-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /root/Kokkos_install/${{ matrix.exec_model }} key: ${{ matrix.container_img }}-kokkos${{ matrix.kokkos_version }}-${{ matrix.exec_model }} - name: Checkout PennyLane-Lightning - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Copy cached libraries if: steps.kokkos-cache.outputs.cache-hit == 'true' @@ -134,8 +134,11 @@ jobs: run: | dnf update -y && dnf install -y podman - - name: Install cibuildwheel - run: python3.9 -m pip install cibuildwheel~=2.16.0 + - name: Install dependencies + run: python3.9 -m pip install cibuildwheel~=2.16.0 toml + + - name: Configure pyproject.toml file + run: PL_BACKEND="${{ matrix.pl_backend }}" python3.9 scripts/configure_pyproject_toml.py - name: Build wheels env: @@ -156,13 +159,15 @@ jobs: source /opt/rh/gcc-toolset-13/enable -y PATH="/opt/rh/gcc-toolset-13/root/usr/bin:$PATH" - CIBW_ENVIRONMENT: | - PATH="/opt/rh/gcc-toolset-13/root/usr/bin:$PATH" \ - PL_BACKEND="${{ matrix.pl_backend }}" + CIBW_ENVIRONMENT: PATH="/opt/rh/gcc-toolset-13/root/usr/bin:$PATH" CIBW_BEFORE_TEST: | python -m pip install -r requirements-tests.txt - if ${{ matrix.pl_backend == 'lightning_kokkos'}}; then SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" python -m pip install . -vv; fi + if ${{ matrix.pl_backend == 'lightning_kokkos'}} + then + PL_BACKEND="lightning_qubit" python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True python -m pip install . -vv + fi CIBW_TEST_COMMAND: | DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"` diff --git a/.github/workflows/wheel_linux_x86_64_cuda.yml b/.github/workflows/wheel_linux_x86_64_cuda.yml index 6a5a7a42c2..bdad1afa0d 100644 --- a/.github/workflows/wheel_linux_x86_64_cuda.yml +++ b/.github/workflows/wheel_linux_x86_64_cuda.yml @@ -4,10 +4,6 @@ name: Wheel::Linux::x86_64::CUDA # Python versions: 3.9, 3.10, 3.11, 3.12. # **Why we have it**: To build wheels for pennylane-lightning-gpu installation. # **Who does it impact**: Wheels to be uploaded to PyPI. - -env: - GCC_VERSION: 12 - on: pull_request: push: @@ -58,15 +54,18 @@ jobs: steps: - name: Checkout PennyLane-Lightning - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install dependencies (AlmaLinux) if: ${{ (matrix.container_img == 'quay.io/pypa/manylinux_2_28_x86_64') }} run: | dnf update -y && dnf install -y podman - - name: Install cibuildwheel - run: python3.9 -m pip install cibuildwheel~=2.16.0 + - name: Install dependencies + run: python3.9 -m pip install cibuildwheel~=2.16.0 toml + + - name: Configure pyproject.toml file + run: PL_BACKEND="${{ matrix.pl_backend }}" python3.9 scripts/configure_pyproject_toml.py - name: Build wheels env: @@ -78,7 +77,7 @@ jobs: CIBW_SKIP: "*-musllinux*" - CIBW_CONFIG_SETTINGS: --global-option=build_ext --global-option=--define="CMAKE_CXX_COMPILER=$(which g++);CMAKE_C_COMPILER=$(which gcc);LIGHTNING_RELEASE_TAG=master" + CIBW_CONFIG_SETTINGS: --global-option=build_ext --global-option=--define="LIGHTNING_RELEASE_TAG=master" # Python build settings CIBW_BEFORE_BUILD: | @@ -93,7 +92,6 @@ jobs: CIBW_ENVIRONMENT: | PATH=/opt/rh/gcc-toolset-12/root/usr/bin:$PATH:/usr/local/cuda-${{ matrix.cuda_version }}/bin \ LD_LIBRARY_PATH=/opt/rh/gcc-toolset-12/root/usr/lib64:/opt/rh/gcc-toolset-12/root/usr/lib:/opt/rh/gcc-toolset-12/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-12/root/usr/lib/dyninst:$LD_LIBRARY_PATH:/usr/local/cuda-${{ matrix.cuda_version }}/lib64 \ - PL_BACKEND="${{ matrix.pl_backend }}" \ PKG_CONFIG_PATH=/opt/rh/gcc-toolset-12/root/usr/lib64/pkgconfig:$PKG_CONFIG_PATH CIBW_REPAIR_WHEEL_COMMAND_LINUX: "./bin/auditwheel repair -w {dest_dir} {wheel}" @@ -148,4 +146,4 @@ jobs: with: user: __token__ password: ${{ secrets.TEST_PYPI_LGPU_TOKEN }} - repository_url: https://test.pypi.org/legacy/ + repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/wheel_macos_arm64.yml b/.github/workflows/wheel_macos_arm64.yml index 5b1b20d3d0..6ea238abf1 100644 --- a/.github/workflows/wheel_macos_arm64.yml +++ b/.github/workflows/wheel_macos_arm64.yml @@ -75,8 +75,11 @@ jobs: with: python-version: '3.9' - - name: Install cibuildwheel - run: python -m pip install cibuildwheel~=2.16.0 + - name: Install dependencies + run: python -m pip install cibuildwheel~=2.16.0 toml + + - name: Configure pyproject.toml file + run: PL_BACKEND="${{ matrix.pl_backend }}" python scripts/configure_pyproject_toml.py - name: Build wheels env: @@ -91,13 +94,15 @@ jobs: python -m pip install pybind11 ninja cmake~=3.24.0 setuptools scipy CIBW_ENVIRONMENT: | - CMAKE_ARGS="-DCMAKE_CXX_COMPILER_TARGET=arm64-apple-macos11 -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_SYSTEM_PROCESSOR=ARM64 -DENABLE_OPENMP=OFF" \ - PL_BACKEND="${{ matrix.pl_backend }}" + CMAKE_ARGS="-DCMAKE_CXX_COMPILER_TARGET=arm64-apple-macos11 -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_SYSTEM_PROCESSOR=ARM64 -DENABLE_OPENMP=OFF" CIBW_BEFORE_TEST: | python -m pip install -r requirements-tests.txt - if ${{ matrix.pl_backend == 'lightning_kokkos'}}; then SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" python -m pip install . -vv; fi - + if ${{ matrix.pl_backend == 'lightning_kokkos'}} + then + PL_BACKEND="lightning_qubit" python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True python -m pip install . -vv + fi CIBW_TEST_COMMAND: | DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"` pl-device-test --device=${DEVICENAME} --skip-ops -x --tb=short --no-flaky-report diff --git a/.github/workflows/wheel_macos_x86_64.yml b/.github/workflows/wheel_macos_x86_64.yml index f3aa0d9008..58c318b79a 100644 --- a/.github/workflows/wheel_macos_x86_64.yml +++ b/.github/workflows/wheel_macos_x86_64.yml @@ -124,8 +124,11 @@ jobs: with: python-version: '3.9' - - name: Install cibuildwheel - run: python -m pip install cibuildwheel~=2.16.0 + - name: Install dependencies + run: python -m pip install cibuildwheel~=2.16.0 toml + + - name: Configure pyproject.toml file + run: PL_BACKEND="${{ matrix.pl_backend }}" python scripts/configure_pyproject_toml.py - name: Build wheels env: @@ -144,7 +147,11 @@ jobs: CIBW_BEFORE_TEST: | python -m pip install -r requirements-tests.txt - if ${{ matrix.pl_backend == 'lightning_kokkos'}}; then SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" python -m pip install . -vv; fi + if ${{ matrix.pl_backend == 'lightning_kokkos'}} + then + PL_BACKEND="lightning_qubit" python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True python -m pip install . -vv + fi CIBW_TEST_COMMAND: | DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"` diff --git a/.github/workflows/wheel_noarch.yml b/.github/workflows/wheel_noarch.yml index 55c62b0287..d25cc78ff6 100644 --- a/.github/workflows/wheel_noarch.yml +++ b/.github/workflows/wheel_noarch.yml @@ -41,36 +41,42 @@ jobs: steps: - name: Checkout PennyLane-Lightning + if: ${{ matrix.pl_backend == 'lightning_qubit'}} uses: actions/checkout@v4 - with: - path: main + - uses: actions/setup-python@v5 + if: ${{ matrix.pl_backend == 'lightning_qubit'}} with: python-version: '3.9' - name: Upgrade pip + if: ${{ matrix.pl_backend == 'lightning_qubit'}} run: | python -m pip install --upgrade pip - - name: Install CMake and ninja + - name: Install dependencies + if: ${{ matrix.pl_backend == 'lightning_qubit'}} run: | - python -m pip install --upgrade cmake ninja + python -m pip install toml - - name: Build wheels + - name: Configure pyproject.toml file + if: ${{ matrix.pl_backend == 'lightning_qubit'}} + run: PL_BACKEND="${{ matrix.pl_backend }}" python scripts/configure_pyproject_toml.py + + - name: Build wheels and source dist if: ${{ matrix.pl_backend == 'lightning_qubit'}} - run: | - python -m pip install --upgrade pip wheel - cd main - PL_BACKEND="${{ matrix.pl_backend }}" python setup.py bdist_wheel env: SKIP_COMPILATION: True + run: | + python -m pip install --upgrade pip wheel build + python -m build - name: Validate wheels if: ${{ matrix.pl_backend == 'lightning_qubit'}} run: | python -m pip install twine - python -m twine check main/dist/*.whl + python -m twine check dist/*.whl - uses: actions/upload-artifact@v3 if: | @@ -78,22 +84,13 @@ jobs: (github.event_name == 'release' || github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/master') with: name: pure-python-wheels-${{ matrix.pl_backend }}.zip - path: main/dist/*.whl - - - name: Build source dist - if: ${{ matrix.pl_backend != 'lightning_qubit'}} - run: | - python -m pip install --upgrade pip wheel - cd main - PL_BACKEND="${{ matrix.pl_backend }}" python setup.py sdist - env: - SKIP_COMPILATION: True + path: dist/*.whl - uses: actions/upload-artifact@v3 if: ${{ matrix.pl_backend != 'lightning_qubit' && (github.event_name == 'release' || github.ref == 'refs/heads/master') }} with: name: pure-source-dist-${{ matrix.pl_backend }}.tar.gz - path: main/dist/*.tar.gz + path: dist/*.tar.gz upload-pypi: needs: build-pure-python-wheel @@ -101,12 +98,10 @@ jobs: matrix: pl_backend: ["lightning_gpu", "lightning_kokkos", "lightning_qubit"] runs-on: ubuntu-latest - if: | - matrix.pl_backend == 'lightning_qubit' && - github.event_name == 'release' steps: - uses: actions/download-artifact@v3 + if: ${{ matrix.pl_backend == 'lightning_qubit' && github.event_name == 'release' }} with: name: pure-python-wheels-${{ matrix.pl_backend }}.zip path: dist diff --git a/.github/workflows/wheel_win_x86_64.yml b/.github/workflows/wheel_win_x86_64.yml index ca5b6a3b76..16c44b409c 100644 --- a/.github/workflows/wheel_win_x86_64.yml +++ b/.github/workflows/wheel_win_x86_64.yml @@ -113,8 +113,13 @@ jobs: Copy-Item -Path "D:\a\install_dir\${{ matrix.exec_model }}\" ` -Destination "D:\a\pennylane-lightning\pennylane-lightning\Kokkos" -Recurse -Force - - name: Install cibuildwheel - run: python -m pip install cibuildwheel~=2.16.0 wheel + - name: Install dependencies + run: python -m pip install cibuildwheel~=2.16.0 wheel toml + + - name: Configure pyproject.toml file + env: + PL_BACKEND: "${{ matrix.pl_backend }}" + run: python scripts/configure_pyproject_toml.py - name: Build wheels env: @@ -128,7 +133,6 @@ jobs: CIBW_ENVIRONMENT: | CMAKE_ARGS="-DENABLE_LAPACK=OFF" - PL_BACKEND="${{ matrix.pl_backend }}" CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 @@ -173,7 +177,8 @@ jobs: python -m pip install setuptools python -m pip install -r requirements-tests.txt if (${{ matrix.pl_backend == 'lightning_kokkos'}}) { - SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" python -m pip install . -vv + PL_BACKEND="lightning_qubit" python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True python -m pip install . -vv } pushd wheelhouse $wheels = Get-ChildItem "./" -Filter *.whl diff --git a/.gitignore b/.gitignore index 0f80526ee0..8e422d276c 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ PennyLane_Lightning.egg-info/ prototypes/ tests/__pycache__/ venv/ +wheelhouse/ \ No newline at end of file diff --git a/.readthedocs.yml b/.readthedocs.yml index fd7c32576b..af5eb2cd24 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -26,9 +26,9 @@ build: pre_install: - wget https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda_12.3.2_545.23.08_linux.run - sh cuda_12.3.2_545.23.08_linux.run --silent --toolkit --toolkitpath=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3 || cat /tmp/cuda-installer.log - - echo "setuptools~=66.0\npip~=22.0" >> ci_build_requirements.txt - post_install: - - rm -rf ./build && export PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/bin${PATH:+:${PATH}} && export LD_LIBRARY_PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} && PL_BACKEND="lightning_gpu" python setup.py build_ext --define="PL_DISABLE_CUDA_SAFETY=1" && PL_BACKEND="lightning_gpu" python setup.py bdist_wheel - - rm -rf ./build && PL_BACKEND="lightning_kokkos" python setup.py bdist_wheel - - rm -rf ./build && export PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/bin${PATH:+:${PATH}} && export LD_LIBRARY_PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} && PL_BACKEND="lightning_tensor" python setup.py build_ext --define="PL_DISABLE_CUDA_SAFETY=1" && PL_BACKEND="lightning_tensor" python setup.py bdist_wheel + - echo "setuptools~=66.0" >> ci_build_requirements.txt + post_install: + - rm -rf ./build && export PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/bin${PATH:+:${PATH}} && export LD_LIBRARY_PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} && PL_BACKEND="lightning_gpu" python scripts/configure_pyproject_toml.py && CMAKE_ARGS="-DPL_DISABLE_CUDA_SAFETY=1" python -m build + - rm -rf ./build && PL_BACKEND="lightning_kokkos" python scripts/configure_pyproject_toml.py && python -m build + - rm -rf ./build && export PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/bin${PATH:+:${PATH}} && export LD_LIBRARY_PATH=${READTHEDOCS_VIRTUALENV_PATH}/cuda-12.3/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} && PL_BACKEND="lightning_tensor" python scripts/configure_pyproject_toml.py && CMAKE_ARGS="-DPL_DISABLE_CUDA_SAFETY=1" python -m build - python -m pip install ./dist/*.whl diff --git a/CMakeLists.txt b/CMakeLists.txt index a7e50f9004..d53f2d75c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,16 +20,16 @@ project(pennylane_lightning function(set_pennylane_lightning_version VERSION_FILE_PATH) file(STRINGS ${VERSION_FILE_PATH} VERSION_FILE_STR) foreach (LINE IN LISTS VERSION_FILE_STR) - if("${LINE}" MATCHES "__version__.*") + if("${LINE}" MATCHES "version.*") set(VERSION_LINE_STR "${LINE}") endif() endforeach() - string(REGEX REPLACE "__version__ = \"(.*)\"" "\\1" VERSION_STRING ${VERSION_LINE_STR}) + string(REGEX REPLACE "version = \"(.*)\"" "\\1" VERSION_STRING ${VERSION_LINE_STR}) set(VERSION_STRING ${VERSION_STRING} PARENT_SCOPE) endfunction() -set_pennylane_lightning_version(${PROJECT_SOURCE_DIR}/pennylane_lightning/core/_version.py) +set_pennylane_lightning_version(${PROJECT_SOURCE_DIR}/pyproject.toml) message(STATUS "pennylane_lightning version ${VERSION_STRING}") set(PROJECT_VERSION ${VERSION_STRING}) @@ -146,7 +146,7 @@ foreach(BACKEND ${PL_BACKEND}) "${BACKEND}_measurements" ) endforeach() - + target_include_directories(pennylane_lightning INTERFACE "$") ##################################################### diff --git a/MANIFEST.in b/MANIFEST.in index db5d3a35bb..4c1a79b51d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,9 @@ +include CMakeLists.txt +include cmake/* include requirements.txt include .github/CHANGELOG.md include pennylane_lightning/lightning_qubit/lightning_qubit.toml include pennylane_lightning/lightning_qpu/lightning_gpu.toml include pennylane_lightning/lightning_kokkos/lightning_kokkos.toml +include pennylane_lightning/core/_version.py +graft pennylane_lightning/core/src/ diff --git a/Makefile b/Makefile index 0456de8341..8b673ed71d 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,8 @@ help: @echo " test-cpp [target=?] to run a specific C++ test target (requires CMake)." @echo " test-python [device=?] to run the Python test suite" @echo " Default: lightning.qubit" + @echo " wheel [backend=?] to configure and build Python wheels + @echo " Default: lightning_qubit" @echo " coverage [device=?] to generate a coverage report for python interface" @echo " Default: lightning.qubit" @echo " coverage-cpp [backend=?] to generate a coverage report for C++ interface" @@ -61,6 +63,11 @@ clean: rm -rf pennylane_lightning/*_ops* rm -rf *.egg-info +.PHONY: wheel +wheel: + PL_BACKEND=$(PL_BACKEND) python scripts/configure_pyproject_toml.py + python -m build + .PHONY: coverage coverage-cpp coverage: @echo "Generating coverage report for $(if $(device:-=),$(device),lightning.qubit) device:" @@ -77,9 +84,9 @@ coverage-cpp: -DENABLE_COVERAGE=ON \ -DPL_BACKEND=$(PL_BACKEND) \ $(OPTIONS) - cmake --build ./BuildCov + cmake --build ./BuildCov $(VERBOSE) --target $(target) cd ./BuildCov; for file in *runner ; do ./$file; done; \ - lcov --directory . -b ../pennylane_lightning/core/src --capture --output-file coverage.info; \ + lcov --directory . -b ../pennylane_lightning/core/src/ --capture --output-file coverage.info; \ genhtml coverage.info --output-directory out .PHONY: test-python test-builtin test-suite test-cpp @@ -115,8 +122,8 @@ format-cpp: ./bin/format $(CHECK) ./pennylane_lightning format-python: - isort --py 311 --profile black -l 100 -p pennylane_lightning ./pennylane_lightning/ ./mpitests ./tests $(ICHECK) $(VERBOSE) - black -l 100 ./pennylane_lightning/ ./mpitests ./tests $(CHECK) $(VERBOSE) + isort --py 311 --profile black -l 100 -p pennylane_lightning ./pennylane_lightning ./mpitests ./tests ./scripts $(ICHECK) $(VERBOSE) + black -l 100 ./pennylane_lightning ./mpitests ./tests ./scripts $(CHECK) $(VERBOSE) .PHONY: check-tidy check-tidy: diff --git a/README.rst b/README.rst index 3f9b6b19f6..518bd94195 100644 --- a/README.rst +++ b/README.rst @@ -135,10 +135,11 @@ For development and testing, you can install by cloning the repository: $ git clone https://github.com/PennyLaneAI/pennylane-lightning.git $ cd pennylane-lightning $ pip install -r requirements.txt - $ PL_BACKEND=${PL_BACKEND} pip install -e . -vv + $ PL_BACKEND=${PL_BACKEND} python scripts/configure_pyproject_toml.py + $ pip install -e . -vv Note that subsequent calls to ``pip install -e .`` will use cached binaries stored in the -``build`` folder. Run ``make clean`` if you would like to recompile from scratch. +``build`` folder, and the ``pyproject.toml`` file defined by the configuration script. Run ``make clean`` if you would like to recompile from scratch. You can also pass ``cmake`` options with ``CMAKE_ARGS`` as follows: @@ -146,15 +147,6 @@ You can also pass ``cmake`` options with ``CMAKE_ARGS`` as follows: $ CMAKE_ARGS="-DENABLE_OPENMP=OFF -DENABLE_BLAS=OFF" pip install -e . -vv -or with ``build_ext`` and the ``--define`` flag as follows: - -.. code-block:: console - - $ python3 setup.py build_ext -i --define="ENABLE_OPENMP=OFF;ENABLE_BLAS=OFF" - $ python3 setup.py develop - -where ``-D`` must not be included before ``;``-separated options. - Compile MSVC (Windows) ====================== @@ -235,27 +227,28 @@ Please see the `cuQuantum SDK`_ install guide for more information. Install Lightning-GPU from source ================================= -To install Lightning-GPU from the package sources using the direct SDK path, Lightning-Qubit should be install before Lightning-GPU: +To install Lightning-GPU from the package sources using the direct SDK path, Lightning-Qubit should be installed (compilation is not necessary): .. code-block:: console git clone https://github.com/PennyLaneAI/pennylane-lightning.git cd pennylane-lightning pip install -r requirements.txt - PL_BACKEND="lightning_qubit" pip install -e . -vv + PL_BACKEND="lightning_qubit" python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True pip install -e . -vv Then the `cuStateVec`_ library can be installed and set a ``CUQUANTUM_SDK`` environment variable. .. code-block:: console - python -m pip install wheel custatevec-cu12 export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") The Lightning-GPU can then be installed with ``pip``: .. code-block:: console - PL_BACKEND="lightning_gpu" python -m pip install -e . + PL_BACKEND="lightning_gpu" python scripts/configure_pyproject_toml.py + python -m pip install -e . To simplify the build, we recommend using the containerized build process described in Docker support section. @@ -275,7 +268,8 @@ Then Lightning-GPU with MPI support can then be installed with ``pip``: .. code-block:: console - CMAKE_ARGS="-DENABLE_MPI=ON" PL_BACKEND="lightning_gpu" python -m pip install -e . + PL_BACKEND="lightning_gpu" python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DENABLE_MPI=ON" python -m pip install -e . Test Lightning-GPU with MPI @@ -343,7 +337,8 @@ The simplest way to install Lightning-Kokkos (OpenMP backend) through ``pip``. .. code-block:: console - CMAKE_ARGS="-DKokkos_ENABLE_OPENMP=ON" PL_BACKEND="lightning_kokkos" python -m pip install . + PL_BACKEND="lightning_kokkos" python scripts/configure_pyproject_toml.py + CMAKE_ARGS="-DKokkos_ENABLE_OPENMP=ON" python -m pip install . To build the plugin directly with CMake as above: @@ -372,27 +367,28 @@ Please see the `cuQuantum SDK `_ ins Install Lightning-Tensor from source ==================================== -Lightning-Qubit should be installed before Lightning-Tensor: +Lightning-Qubit should be installed before Lightning-Tensor (compilation is not necessary): .. code-block:: console git clone https://github.com/PennyLaneAI/pennylane-lightning.git cd pennylane-lightning pip install -r requirements.txt - PL_BACKEND="lightning_qubit" pip install . + PL_BACKEND="lightning_qubit" python scripts/configure_pyproject_toml.py + SKIP_COMPILATION=True pip install . -Then the `cutensornet`_ library can be installed and set a ``CUQUANTUM_SDK`` environment variable. +Then the `cutensornet`_ library can be installed and set a ``CUQUANTUM_SDK`` environment variable. .. code-block:: console - pip install cutensornet-cu12 export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')") The Lightning-Tensor can then be installed with ``pip``: .. code-block:: console - PL_BACKEND="lightning_tensor" pip install -e . + PL_BACKEND="lightning_tensor" python scripts/configure_pyproject_toml.py + pip install -e . .. installation_LTensor-end-inclusion-marker-do-not-remove @@ -458,13 +454,13 @@ If you are using Lightning for research, please cite: @misc{ asadi2024, - title={{Hybrid quantum programming with PennyLane Lightning on HPC platforms}}, + title={{Hybrid quantum programming with PennyLane Lightning on HPC platforms}}, author={Ali Asadi and Amintor Dusko and Chae-Yeun Park and Vincent Michaud-Rioux and Isidor Schoch and Shuli Shu and Trevor Vincent and Lee James O'Riordan}, year={2024}, eprint={2403.02512}, archivePrefix={arXiv}, primaryClass={quant-ph}, - url={https://arxiv.org/abs/2403.02512}, + url={https://arxiv.org/abs/2403.02512}, } .. citation-end-inclusion-marker-do-not-remove diff --git a/docker/Dockerfile b/docker/Dockerfile index cff4ffdf50..cc38d8506d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -79,8 +79,8 @@ RUN pip install --no-cache-dir cmake ninja pybind11 wheel FROM base-build-python AS build-wheel-lightning-qubit WORKDIR /opt/pennylane-lightning RUN pip uninstall -y pennylane-lightning -RUN python setup.py build_ext -RUN python setup.py bdist_wheel +RUN python scripts/configure_pyproject_toml.py +RUN python -m build # Install lightning-qubit backend FROM base-runtime AS wheel-lightning-qubit @@ -93,8 +93,8 @@ FROM base-build-python AS build-wheel-lightning-kokkos-openmp WORKDIR /opt/pennylane-lightning ENV PL_BACKEND=lightning_kokkos RUN pip uninstall -y pennylane-lightning -RUN python setup.py build_ext -i --define="Kokkos_ENABLE_SERIAL:BOOL=ON;Kokkos_ENABLE_OPENMP:BOOL=ON" -RUN python setup.py bdist_wheel +RUN python scripts/configure_pyproject_toml.py +RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON" python -m build # Install lightning-kokkos OpenMP backend FROM base-runtime AS wheel-lightning-kokkos-openmp @@ -118,8 +118,8 @@ WORKDIR /opt/pennylane-lightning ENV PL_BACKEND=lightning_kokkos RUN pip uninstall -y pennylane-lightning RUN echo >> cmake/support_kokkos.cmake && echo "find_package(CUDAToolkit REQUIRED)" >> cmake/support_kokkos.cmake -RUN python setup.py build_ext -i --define="Kokkos_ENABLE_SERIAL:BOOL=ON;Kokkos_ENABLE_OPENMP:BOOL=ON;Kokkos_ENABLE_CUDA:BOOL=ON;Kokkos_ARCH_${CUDA_ARCH}=ON" -RUN python setup.py bdist_wheel +RUN python scripts/configure_pyproject_toml.py +RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON -DKokkos_ENABLE_CUDA:BOOL=ON -DKokkos_ARCH_${CUDA_ARCH}=ON" python -m build # Install python3 and setup runtime virtual env in CUDA-12-runtime image (includes CUDA runtime and math libraries) # Install lightning-kokkos CUDA backend @@ -148,8 +148,9 @@ WORKDIR /opt/pennylane-lightning ENV PL_BACKEND=lightning_gpu RUN pip install --no-cache-dir wheel custatevec-cu12 RUN pip uninstall -y pennylane-lightning -RUN CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") python setup.py build_ext -RUN python setup.py bdist_wheel +RUN python scripts/configure_pyproject_toml.py +RUN CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") python -m build + # Install python3 and setup runtime virtual env in CUDA-12-runtime image (includes CUDA runtime and math libraries) # Install lightning-kokkos CUDA backend @@ -192,8 +193,8 @@ ENV CMAKE_PREFIX_PATH=/opt/rocm:$CMAKE_PREFIX_PATH ENV CXX=hipcc ENV PL_BACKEND=lightning_kokkos RUN pip uninstall -y pennylane-lightning -RUN python setup.py build_ext -i --define="Kokkos_ENABLE_SERIAL:BOOL=ON;Kokkos_ENABLE_OPENMP:BOOL=ON;Kokkos_ENABLE_HIP:BOOL=ON;Kokkos_ARCH_${AMD_ARCH}=ON" -RUN python setup.py bdist_wheel +RUN python scripts/configure_pyproject_toml.py +RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON -DKokkos_ENABLE_HIP:BOOL=ON -DKokkos_ARCH_${AMD_ARCH}=ON" python -m build # Install lightning-kokkos HIP backend FROM rocm/dev-ubuntu-22.04:5.7 AS wheel-lightning-kokkos-rocm diff --git a/pennylane_lightning/core/__init__.py b/pennylane_lightning/core/__init__.py index d3a37803e8..30e036e210 100644 --- a/pennylane_lightning/core/__init__.py +++ b/pennylane_lightning/core/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2023 Xanadu Quantum Technologies Inc. +# Copyright 2018-2024 Xanadu Quantum Technologies Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/pennylane_lightning/lightning_gpu/__init__.py b/pennylane_lightning/lightning_gpu/__init__.py index e88765aa28..90238ba790 100644 --- a/pennylane_lightning/lightning_gpu/__init__.py +++ b/pennylane_lightning/lightning_gpu/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2023 Xanadu Quantum Technologies Inc. +# Copyright 2018-2024 Xanadu Quantum Technologies Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/pennylane_lightning/lightning_kokkos/__init__.py b/pennylane_lightning/lightning_kokkos/__init__.py index 7b1045d540..8720ed0201 100644 --- a/pennylane_lightning/lightning_kokkos/__init__.py +++ b/pennylane_lightning/lightning_kokkos/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2023 Xanadu Quantum Technologies Inc. +# Copyright 2018-2024 Xanadu Quantum Technologies Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/pennylane_lightning/lightning_qubit/__init__.py b/pennylane_lightning/lightning_qubit/__init__.py index a1b792afde..12901a7396 100644 --- a/pennylane_lightning/lightning_qubit/__init__.py +++ b/pennylane_lightning/lightning_qubit/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2023 Xanadu Quantum Technologies Inc. +# Copyright 2018-2024 Xanadu Quantum Technologies Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..b50ac438d2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,28 @@ +[build-system] +requires = [ "cmake~=3.24.0", "ninja; platform_system!='Windows'", "setuptools>=42", "toml",] +build-backend = "setuptools.build_meta" + +[project] +name = "PennyLane_Lightning" +description = "PennyLane-Lightning plugin" +readme = "README.rst" +requires-python = ">=3.9" +classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering :: Physics",] +dependencies = [ "pennylane>=0.37",] +dynamic = [ "version",] +[[project.maintainers]] +name = "Xanadu Quantum Technologies Inc." +email = "software@xanadu.ai" + +[project.license] +text = "Apache License 2.0" + +[project.optional-dependencies] +gpu = [ "pennylane-lightning-gpu",] +kokkos = [ "pennylane-lightning-kokkos",] + +[project.urls] +Homepage = "https://github.com/PennyLaneAI/pennylane-lightning" + +[project.entry-points."pennylane.plugins"] +"lightning.qubit" = "pennylane_lightning.lightning_qubit:LightningQubit" diff --git a/requirements-dev.txt b/requirements-dev.txt index 80268897c6..34e7884616 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ -pip~=22.0 git+https://github.com/PennyLaneAI/pennylane.git@master +build ninja flaky pybind11 diff --git a/scripts/backend_support.py b/scripts/backend_support.py new file mode 100755 index 0000000000..9f6cd38974 --- /dev/null +++ b/scripts/backend_support.py @@ -0,0 +1,56 @@ +# Copyright 2024 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +r""" +Internal logic to check and set backend variables. +""" +import os + +default_backend = "lightning_qubit" +supported_backends = {"lightning_kokkos", "lightning_qubit", "lightning_gpu", "lightning_tensor"} +supported_backends.update({sb.replace("_", ".") for sb in supported_backends}) + + +def get_backend(): + """Return backend. + + The backend is ``lightning_qubit`` by default. + Allowed values are: "lightning_kokkos", "lightning_qubit", "lightning_gpu" and "lightning_tensor". + A dot can also be used instead of an underscore. + If the environment variable ``PL_BACKEND`` is defined, its value is used. + Otherwise, if the environment variable ``CMAKE_ARGS`` is defined and it + contains the CMake option ``PL_BACKEND``, its value is used. + Dots are replaced by underscores upon exiting. + """ + _backend = None + if "PL_BACKEND" in os.environ: + _backend = os.environ.get("PL_BACKEND", default_backend) + _backend = _backend.replace(".", "_") + if "CMAKE_ARGS" in os.environ: + cmake_args = os.environ["CMAKE_ARGS"].split(" ") + arg = [x for x in cmake_args if "PL_BACKEND" in x] + if not arg and _backend is not None: + cmake_backend = _backend + else: + cmake_backend = arg[0].split("=")[1].replace(".", "_") if arg else default_backend + # CMake determined backend will always take precedence over PL_BACKEND. + _backend = cmake_backend + if _backend is None: + _backend = default_backend + if _backend not in supported_backends: + raise ValueError(f"Invalid backend {_backend}.") + return _backend + + +backend = get_backend() +device_name = backend.replace("_", ".") diff --git a/scripts/configure_pyproject_toml.py b/scripts/configure_pyproject_toml.py new file mode 100755 index 0000000000..57517954e3 --- /dev/null +++ b/scripts/configure_pyproject_toml.py @@ -0,0 +1,99 @@ +# Copyright 2024 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +r""" +Project configuration script. +""" +import argparse +import os +from pathlib import Path + +import toml +from backend_support import backend, device_name + +path_to_version = Path("pennylane_lightning").absolute() / "core" / "_version.py" +with open(path_to_version, encoding="utf-8") as f: + version = f.readlines()[-1].split()[-1].strip("\"'") + + +######################################################################## +# Parsing arguments +######################################################################## +def parse_args(): + """Parse external arguments provided to the script.""" + parser = argparse.ArgumentParser( + prog="python configure_pyproject_toml.py", + description="This module configures the pyproject.toml file for a Lightning backend (package).", + ) + + parser.add_argument( + "--path", + type=str, + default="", + nargs="?", + help="pyproject.toml file path", + ) + + return parser.parse_args() + + +if __name__ == "__main__": + parsed_args = parse_args() + pyproject_path = os.path.join(parsed_args.path, "pyproject.toml") + + pyproject = toml.load(pyproject_path) + + # ------------------------ + # Configure Build. + # ------------------------ + requires = [ + "cmake~=3.24.0", + "ninja; platform_system!='Windows'", + "setuptools>=42", + "toml", + ] + if backend == "lightning_gpu": + requires.append("custatevec-cu12") + if backend == "lightning_tensor": + requires.append("cutensornet-cu12") + + pyproject["build-system"]["requires"] = requires + + # ------------------------ + # Configure Project. + # ------------------------ + suffix = backend.replace("lightning_", "") + suffix = suffix.upper() if suffix == "gpu" else suffix.title() + + plugin = "pennylane_lightning." + backend + ":Lightning" + suffix + + pkg_suffix = "" if suffix == "Qubit" else "_" + suffix + + # Specifying the project name. + pyproject["project"]["name"] = f"PennyLane_Lightning{pkg_suffix}" + + # Project entry point. + pyproject["project"]["entry-points"]["pennylane.plugins"] = {device_name: plugin} + + dependencies = [ + "pennylane>=0.37", + ] + + if backend != "lightning_qubit": + dependencies += ["pennylane_lightning==" + version] + + # Package requirements. + pyproject["project"]["dependencies"] = dependencies + + with open(pyproject_path, "w", encoding="utf-8") as file: + toml.dump(pyproject, file) diff --git a/scripts/gen_pyver_matrix.py b/scripts/gen_pyver_matrix.py old mode 100644 new mode 100755 index 956264d0c6..0d65d03b9d --- a/scripts/gen_pyver_matrix.py +++ b/scripts/gen_pyver_matrix.py @@ -1,6 +1,6 @@ import argparse -import re import json +import re def version_map(py_ver: str): @@ -52,4 +52,4 @@ def version_map(py_ver: str): json_out = json.dumps(output_list) - print(json_out) \ No newline at end of file + print(json_out) diff --git a/setup.py b/setup.py index e0ce37fc5c..cd51c3a93d 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -# Copyright 2018-2023 Xanadu Quantum Technologies Inc. +# Copyright 2018-2024 Xanadu Quantum Technologies Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,52 +16,15 @@ import subprocess import shutil import sys +import toml + from pathlib import Path from setuptools import setup, Extension, find_namespace_packages from setuptools.command.build_ext import build_ext -default_backend = "lightning_qubit" -supported_backends = {"lightning_kokkos", "lightning_qubit", "lightning_gpu", "lightning_tensor"} -supported_backends.update({sb.replace("_", ".") for sb in supported_backends}) - - -def get_backend(): - """Return backend. - - The backend is ``lightning_qubit`` by default. - Allowed values are: "lightning_kokkos", "lightning_qubit" and "lightning_gpu". - A dot can also be used instead of an underscore. - If the environment variable ``PL_BACKEND`` is defined, its value is used. - Otherwise, if the environment variable ``CMAKE_ARGS`` is defined and it - contains the CMake option ``PL_BACKEND``, its value is used. - Dots are replaced by underscores upon exiting. - """ - backend = None - if "PL_BACKEND" in os.environ: - backend = os.environ.get("PL_BACKEND", default_backend) - backend = backend.replace(".", "_") - if "CMAKE_ARGS" in os.environ: - cmake_args = os.environ["CMAKE_ARGS"].split(" ") - arg = [x for x in cmake_args if "PL_BACKEND" in x] - if not arg and backend is not None: - cmake_backend = backend - else: - cmake_backend = arg[0].split("=")[1].replace(".", "_") if arg else default_backend - if backend is not None and backend != cmake_backend: - raise ValueError( - f"Backends {backend} and {cmake_backend} specified by PL_BACKEND and CMAKE_ARGS respectively do not match." - ) - backend = cmake_backend - if backend is None: - backend = default_backend - if backend not in supported_backends: - raise ValueError(f"Invalid backend {backend}.") - return backend - - -backend = get_backend() -device_name = backend.replace("_", ".") - +project_name = toml.load("pyproject.toml")['project']['name'] +backend = project_name.replace("PennyLane_", "").lower() +if (backend == "lightning"): backend = "lightning_qubit" class CMakeExtension(Extension): def __init__(self, name, sourcedir=""): @@ -166,53 +129,23 @@ def build_extension(self, ext: CMakeExtension): env=os.environ, ) - with open(os.path.join("pennylane_lightning", "core", "_version.py"), encoding="utf-8") as f: version = f.readlines()[-1].split()[-1].strip("\"'") -requirements = [ - "pennylane>=0.36", -] - packages_list = ["pennylane_lightning." + backend] if backend == "lightning_qubit": packages_list += ["pennylane_lightning.core"] -else: - requirements += ["pennylane_lightning==" + version] - -suffix = backend.replace("lightning_", "") -if suffix == "gpu": - suffix = suffix[0:].upper() -suffix = suffix[0].upper() + suffix[1:] - -pennylane_plugins = [device_name + " = pennylane_lightning." + backend + ":Lightning" + suffix] - -pkg_suffix = "" if suffix == "Qubit" else "_" + suffix info = { - "name": f"PennyLane_Lightning{pkg_suffix}", "version": version, - "maintainer": "Xanadu Inc.", - "maintainer_email": "software@xanadu.ai", - "url": "https://github.com/PennyLaneAI/pennylane-lightning", - "license": "Apache License 2.0", "packages": find_namespace_packages(include=packages_list), "include_package_data": True, - "entry_points": {"pennylane.plugins": pennylane_plugins}, - "description": "PennyLane-Lightning plugin", - "long_description": open("README.rst").read(), - "long_description_content_type": "text/x-rst", - "install_requires": requirements, "ext_modules": ( [] if os.environ.get("SKIP_COMPILATION", False) else [CMakeExtension(f"{backend}_ops")] ), "cmdclass": {"build_ext": CMakeBuild}, "ext_package": "pennylane_lightning", - "extras_require": { - "gpu": ["pennylane-lightning-gpu"], - "kokkos": ["pennylane-lightning-kokkos"], - }, } if backend == "lightning_qubit": @@ -227,24 +160,4 @@ def build_extension(self, ext: CMakeExtension): } ) -classifiers = [ - "Development Status :: 4 - Beta", - "Environment :: Console", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: Apache Software License", - "Natural Language :: English", - "Operating System :: POSIX", - "Operating System :: MacOS :: MacOS X", - "Operating System :: POSIX :: Linux", - "Operating System :: Microsoft :: Windows", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3 :: Only", - "Topic :: Scientific/Engineering :: Physics", -] - -setup(classifiers=classifiers, **(info)) +setup(**(info)) From 23eae794ec93808e83433ce979695429b19a99e9 Mon Sep 17 00:00:00 2001 From: Shuli Shu <31480676+multiphaseCFD@users.noreply.github.com> Date: Tue, 13 Aug 2024 08:55:56 -0400 Subject: [PATCH 169/227] Add `qml.state()` support to `lightning.tensor` (#827) Please complete the following checklist when submitting a PR: - [x] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [ ] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [ ] Ensure that the test suite passes, by running `make test`. - [x] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [x] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** [SC-70248] **Description of the Change:** **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** --------- Co-authored-by: ringo-but-quantum Co-authored-by: Lee James O'Riordan Co-authored-by: Lee J. O'Riordan Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 20 +++ .../lightning_tensor/tncuda/TNCudaBase.hpp | 126 ++++++++++++++++++ tests/new_api/test_device.py | 5 + tests/test_comparison.py | 4 +- tests/test_gates.py | 12 +- 5 files changed, 163 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 22dcde661a..7808e597eb 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -318,6 +318,26 @@ class MPSTNCuda final : public TNCudaBase> { this->get_state_tensor(res); } + /** + * @brief Get the full state vector representation of a MPS quantum state. + * Note that users/developers should be responsible to ensure that there is + * sufficient memory on the host to store the full state vector. + * + * @param res Pointer to the host memory to store the full state vector + * @param res_length Length of the result vector + */ + void getData(ComplexT *res, const std::size_t res_length) { + PL_ABORT_IF(log2(res_length) != BaseType::getNumQubits(), + "The size of the result vector should be equal to the " + "dimension of the quantum state."); + + std::size_t avail_gpu_memory = getFreeMemorySize(); + + PL_ABORT_IF(log2(avail_gpu_memory) < BaseType::getNumQubits(), + "State tensor size exceeds the available GPU memory!"); + this->get_state_tensor(res); + } + /** * @brief Get the full state vector representation of a MPS quantum state. * diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 541d99f034..dcaa95aceb 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -401,6 +401,132 @@ class TNCudaBase : public TensornetBase { static_cast(gate_cache_->get_gate_device_ptr(id)), /* int32_t unitary*/ 1)); } + /** + * @brief Get the state vector representation of a tensor network. + * + * @param host_data Pointer to the host memory for state tensor data. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is set to 1 by default. + */ + void get_state_tensor(ComplexT *host_data, + const int32_t numHyperSamples = 1) { + std::vector wires(BaseType::getNumQubits()); + std::iota(wires.begin(), wires.end(), 0); + + const std::size_t length = std::size_t{1} << wires.size(); + + DataBuffer d_output_tensor(length, getDevTag(), true); + + get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), + wires, numHyperSamples); + + d_output_tensor.CopyGpuDataToHost(host_data, length); + } + + /** + * @brief Get a slice of the state tensor + * + * @param tensor_data Pointer to the device memory for state tensor data. + * @param tensor_data_size Size of the state tensor data. + * @param wires Wires to get the state tensor for. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is set to 1 by default. + */ + void get_state_tensor(CFP_t *tensor_data, + const std::size_t tensor_data_size, + const std::vector &wires, + const int32_t numHyperSamples = 1) { + // NOTE: this is a solution to get the full state tensor + // TODO: projected_modes and projectedModeValues are to be updated for + // prob() support. + auto stateModes = cuUtil::NormalizeCastIndices( + wires, BaseType::getNumQubits()); + + std::vector projected_modes{}; + + std::vector projectedModeValues{}; + + cutensornetStateAccessor_t accessor; + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateAccessor( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* int32_t numProjectedModes */ + static_cast(projected_modes.size()), + /* const int32_t *projectedModes */ projected_modes.data(), + /* const int64_t *amplitudesTensorStrides */ nullptr, + /* cutensornetStateAccessor_t *tensorNetworkAccessor*/ &accessor)); + + // Configure the computation + const cutensornetAccessorAttributes_t accessor_attribute = + CUTENSORNET_ACCESSOR_CONFIG_NUM_HYPER_SAMPLES; + PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorConfigure( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetStateAccessor_t */ accessor, + /* cutensornetAccessorAttributes_t */ accessor_attribute, + /* const void * */ &numHyperSamples, + /* size_t */ sizeof(numHyperSamples))); + + // prepare the computation + cutensornetWorkspaceDescriptor_t workDesc; + PL_CUTENSORNET_IS_SUCCESS( + cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); + + // TODO we assign half (magic number is) of free memory size to the + // maximum memory usage. + const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; + + PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorPrepare( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetStateAccessor_t*/ accessor, + /* size_t */ scratchSize, + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* cudaStream_t unused as of v24.03 */ 0x0)); + + // Allocate workspace buffer + std::size_t worksize = + getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); + + PL_ABORT_IF(worksize > scratchSize, + "Insufficient workspace size on Device!"); + + const std::size_t d_scratch_length = worksize / sizeof(std::size_t); + DataBuffer d_scratch(d_scratch_length, getDevTag(), + true); + + setWorkSpaceMemory(getTNCudaHandle(), workDesc, + reinterpret_cast(d_scratch.getData()), + worksize); + + // compute the specified slice of the quantum circuit amplitudes tensor + ComplexT stateNorm2{0.0, 0.0}; + PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorCompute( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetStateAccessor_t */ accessor, + /* const int64_t * projectedModeValues */ + projectedModeValues.data(), + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* void *amplitudesTensor*/ + static_cast(tensor_data), + /* void *stateNorm */ static_cast(&stateNorm2), + /* cudaStream_t cudaStream */ 0x0)); + + PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); + + const ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; + + CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; + + SharedCublasCaller cublascaller = make_shared_cublas_caller(); + + scaleC_CUDA(scale_scalar_cu, tensor_data, + tensor_data_size, getDevTag().getDeviceID(), + getDevTag().getStreamID(), *cublascaller); + + PL_CUTENSORNET_IS_SUCCESS( + cutensornetDestroyWorkspaceDescriptor(workDesc)); + PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); + } + /** * @brief Save quantumState information to data provided by a user * diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 2c58d64dd5..f6dddfd9ac 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -22,6 +22,7 @@ from conftest import PHI, THETA, VARPHI, LightningDevice, device_name from pennylane.devices import DefaultExecutionConfig, DefaultQubit, ExecutionConfig, MCMConfig from pennylane.devices.default_qubit import adjoint_ops +from pennylane.measurements import ProbabilityMP from pennylane.tape import QuantumScript if device_name == "lightning.qubit": @@ -461,6 +462,10 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): """Test that execute returns the correct results with multiple measurements.""" + if device_name == "lightning.tensor": + if isinstance(mp1, ProbabilityMP) or isinstance(mp2, ProbabilityMP): + pytest.skip("qml.probs() not supported in lightning.tensor") + if isinstance(mp2.obs, qml.ops.LinearCombination) and not qml.operation.active_new_opmath(): mp2.obs = qml.operation.convert_to_legacy_H(mp2.obs) diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 3e40cc03c3..f8398b3031 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -152,7 +152,7 @@ def circuit(measurement): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor device dose not direct access to state", + reason="lightning.tensor device dose not support direct access to state", ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 3)) @pytest.mark.parametrize("wires", [3]) @@ -208,7 +208,7 @@ def circuit(measurement): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor device dose not direct access to state", + reason="lightning.tensor device dose not support the direct access to state", ) @pytest.mark.parametrize("basis_state", itertools.product(*[(0, 1)] * 4)) @pytest.mark.parametrize("wires", [4]) diff --git a/tests/test_gates.py b/tests/test_gates.py index a4e19d6356..855619efc5 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -299,7 +299,11 @@ def test_qubit_RY(theta, phi, tol): init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) def circuit(): - qml.StatePrep(init_state, wires=range(n_qubits)) + ( + qml.StatePrep(init_state, wires=range(n_qubits)) + if device_name != "lightning.tensor" + else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) + ) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) @@ -330,7 +334,11 @@ def test_qubit_unitary(n_wires, theta, phi, tol): for perm in perms: def circuit(): - qml.StatePrep(init_state, wires=range(n_qubits)) + ( + qml.StatePrep(init_state, wires=range(n_qubits)) + if device_name != "lightning.tensor" + else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) + ) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) From 2e4473973c24c9cacb2f850a25b8075f14c5e600 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 13:24:01 +0000 Subject: [PATCH 170/227] tidy up code --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 22 +-- .../lightning_tensor/tncuda/TNCudaBase.hpp | 125 ------------------ 2 files changed, 1 insertion(+), 146 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 7808e597eb..2fdc7c696b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -315,27 +315,7 @@ class MPSTNCuda final : public TNCudaBase> { PL_ABORT_IF(log2(avail_gpu_memory) < BaseType::getNumQubits(), "State tensor size exceeds the available GPU memory!"); - this->get_state_tensor(res); - } - - /** - * @brief Get the full state vector representation of a MPS quantum state. - * Note that users/developers should be responsible to ensure that there is - * sufficient memory on the host to store the full state vector. - * - * @param res Pointer to the host memory to store the full state vector - * @param res_length Length of the result vector - */ - void getData(ComplexT *res, const std::size_t res_length) { - PL_ABORT_IF(log2(res_length) != BaseType::getNumQubits(), - "The size of the result vector should be equal to the " - "dimension of the quantum state."); - - std::size_t avail_gpu_memory = getFreeMemorySize(); - - PL_ABORT_IF(log2(avail_gpu_memory) < BaseType::getNumQubits(), - "State tensor size exceeds the available GPU memory!"); - this->get_state_tensor(res); + BaseType::get_state_tensor(res); } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index dcaa95aceb..31f1f5a361 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -401,131 +401,6 @@ class TNCudaBase : public TensornetBase { static_cast(gate_cache_->get_gate_device_ptr(id)), /* int32_t unitary*/ 1)); } - /** - * @brief Get the state vector representation of a tensor network. - * - * @param host_data Pointer to the host memory for state tensor data. - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is set to 1 by default. - */ - void get_state_tensor(ComplexT *host_data, - const int32_t numHyperSamples = 1) { - std::vector wires(BaseType::getNumQubits()); - std::iota(wires.begin(), wires.end(), 0); - - const std::size_t length = std::size_t{1} << wires.size(); - - DataBuffer d_output_tensor(length, getDevTag(), true); - - get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), - wires, numHyperSamples); - - d_output_tensor.CopyGpuDataToHost(host_data, length); - } - - /** - * @brief Get a slice of the state tensor - * - * @param tensor_data Pointer to the device memory for state tensor data. - * @param tensor_data_size Size of the state tensor data. - * @param wires Wires to get the state tensor for. - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is set to 1 by default. - */ - void get_state_tensor(CFP_t *tensor_data, - const std::size_t tensor_data_size, - const std::vector &wires, - const int32_t numHyperSamples = 1) { - // NOTE: this is a solution to get the full state tensor - // TODO: projected_modes and projectedModeValues are to be updated for - // prob() support. - auto stateModes = cuUtil::NormalizeCastIndices( - wires, BaseType::getNumQubits()); - - std::vector projected_modes{}; - - std::vector projectedModeValues{}; - - cutensornetStateAccessor_t accessor; - PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateAccessor( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* int32_t numProjectedModes */ - static_cast(projected_modes.size()), - /* const int32_t *projectedModes */ projected_modes.data(), - /* const int64_t *amplitudesTensorStrides */ nullptr, - /* cutensornetStateAccessor_t *tensorNetworkAccessor*/ &accessor)); - - // Configure the computation - const cutensornetAccessorAttributes_t accessor_attribute = - CUTENSORNET_ACCESSOR_CONFIG_NUM_HYPER_SAMPLES; - PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorConfigure( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetStateAccessor_t */ accessor, - /* cutensornetAccessorAttributes_t */ accessor_attribute, - /* const void * */ &numHyperSamples, - /* size_t */ sizeof(numHyperSamples))); - - // prepare the computation - cutensornetWorkspaceDescriptor_t workDesc; - PL_CUTENSORNET_IS_SUCCESS( - cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); - - // TODO we assign half (magic number is) of free memory size to the - // maximum memory usage. - const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; - - PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorPrepare( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetStateAccessor_t*/ accessor, - /* size_t */ scratchSize, - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* cudaStream_t unused as of v24.03 */ 0x0)); - - // Allocate workspace buffer - std::size_t worksize = - getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); - - PL_ABORT_IF(worksize > scratchSize, - "Insufficient workspace size on Device!"); - - const std::size_t d_scratch_length = worksize / sizeof(std::size_t); - DataBuffer d_scratch(d_scratch_length, getDevTag(), - true); - - setWorkSpaceMemory(getTNCudaHandle(), workDesc, - reinterpret_cast(d_scratch.getData()), - worksize); - - // compute the specified slice of the quantum circuit amplitudes tensor - ComplexT stateNorm2{0.0, 0.0}; - PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorCompute( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetStateAccessor_t */ accessor, - /* const int64_t * projectedModeValues */ - projectedModeValues.data(), - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* void *amplitudesTensor*/ - static_cast(tensor_data), - /* void *stateNorm */ static_cast(&stateNorm2), - /* cudaStream_t cudaStream */ 0x0)); - - PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); - - const ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; - - CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; - - SharedCublasCaller cublascaller = make_shared_cublas_caller(); - - scaleC_CUDA(scale_scalar_cu, tensor_data, - tensor_data_size, getDevTag().getDeviceID(), - getDevTag().getStreamID(), *cublascaller); - - PL_CUTENSORNET_IS_SUCCESS( - cutensornetDestroyWorkspaceDescriptor(workDesc)); - PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); - } /** * @brief Save quantumState information to data provided by a user From 3168eefea6a37b8024e469a48025eb55edc6ac25 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Tue, 13 Aug 2024 13:24:26 +0000 Subject: [PATCH 171/227] Auto update version from '0.38.0-dev31' to '0.38.0-dev32' --- 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 955e962322..1e786a92cd 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.38.0-dev31" +__version__ = "0.38.0-dev32" From 2ba023f146d5c04a928e7ffd3322498bbc48a3ec Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 13:47:20 +0000 Subject: [PATCH 172/227] tidy up python layer --- tests/new_api/test_device.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index f6dddfd9ac..29dbf60b9b 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -462,10 +462,6 @@ def test_execute_single_measurement(self, theta, phi, mp, dev): ) def test_execute_multi_measurement(self, theta, phi, dev, mp1, mp2): """Test that execute returns the correct results with multiple measurements.""" - if device_name == "lightning.tensor": - if isinstance(mp1, ProbabilityMP) or isinstance(mp2, ProbabilityMP): - pytest.skip("qml.probs() not supported in lightning.tensor") - if isinstance(mp2.obs, qml.ops.LinearCombination) and not qml.operation.active_new_opmath(): mp2.obs = qml.operation.convert_to_legacy_H(mp2.obs) From 9a51c7febb2b31e2b615330a4e95cfe71c957de3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:02:09 +0000 Subject: [PATCH 173/227] add docstring --- .../src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 2fdc7c696b..beffad3596 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -266,7 +266,7 @@ class MPSTNCuda final : public TNCudaBase> { // Optional: SVD cutensornetTensorSVDAlgo_t algo = - CUTENSORNET_TENSOR_SVD_ALGO_GESVDJ; // default + CUTENSORNET_TENSOR_SVD_ALGO_GESVDJ; // default option PL_CUTENSORNET_IS_SUCCESS(cutensornetStateConfigure( /* const cutensornetHandle_t */ BaseType::getTNCudaHandle(), @@ -295,6 +295,11 @@ class MPSTNCuda final : public TNCudaBase> { const_cast(getSitesExtentsPtr().data()), reinterpret_cast(getTensorsOutDataPtr().data())); + // TODO: This is a dummy tensor update to allow multiple calls to the + // `append_mps_final_state` method as well as appending additional + // operations to the graph. This line can be removed in the future when + // the `cutensornet` backend allows multiple calls to the + // `cutensornetStateFinalizeMPS` method. BaseType::dummy_tensor_update(); } From d62cb9a8b721b04a9b022264411b25ae7f673eca Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:05:48 +0000 Subject: [PATCH 174/227] add changelog --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 27c0442c8a..1343185407 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add `qml.prob()` measurement support to `lightning.tensor`. + [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) + * Add `qml.state()` measurement support to `lightning.tensor`. [(#827)](https://github.com/PennyLaneAI/pennylane-lightning/pull/827) From 64db2e79cbcc522f502cbc98d7b6d6062cfd7e62 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:10:58 +0000 Subject: [PATCH 175/227] fix typo --- .github/CHANGELOG.md | 2 +- .../tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 1343185407..ac4a627e75 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `qml.prob()` measurement support to `lightning.tensor`. +* Add `qml.probs()` measurement support to `lightning.tensor`. [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) * Add `qml.state()` measurement support to `lightning.tensor`. diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp index 0bacdcbf9b..3000e80054 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp @@ -80,6 +80,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, mps_state.applyOperation("Identity", {index}, inverse); + // Test for multiple final states appendings mps_state.append_mps_final_state(); cp_t expected(1.0 / std::sqrt(2), 0); From a9c2682b558d544b048f1c35c2c020f1ae2539a4 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:37:48 +0000 Subject: [PATCH 176/227] further tidy up the code --- .github/CHANGELOG.md | 3 + .../lightning_tensor/tncuda/TNCudaBase.hpp | 158 ++++++++++-------- 2 files changed, 88 insertions(+), 73 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index ac4a627e75..70b97ac82c 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -30,6 +30,9 @@ ### Improvements +* Multiple calls to the `append_mps_final_state()` API is allowed. + [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) + * `ENABLE_LAPACK` is off by default for all Lightning backends. [(#825)](https://github.com/PennyLaneAI/pennylane-lightning/pull/825) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 31f1f5a361..0d69fcc61c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -315,7 +315,7 @@ class TNCudaBase : public TensornetBase { * * @param host_data Pointer to the host memory for state tensor data. * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. + * and is set to 1 by default. */ void get_state_tensor(ComplexT *host_data, const int32_t numHyperSamples = 1) { @@ -335,13 +335,11 @@ class TNCudaBase : public TensornetBase { /** * @brief Get a slice of the full state tensor * - * @param tensor_data Pointer to the tensor data on the device memory. + * @param tensor_data Pointer to the device memory for state tensor data. * @param tensor_data_size Size of the tensor data. * @param wires Wires to get the state tensor for. * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. - * - * @return Full state tensor on the host memory + * and is set to 1 by default. */ void get_state_tensor(CFP_t *tensor_data, const std::size_t tensor_data_size, @@ -385,76 +383,17 @@ class TNCudaBase : public TensornetBase { } } - protected: - void dummy_tensor_update() { - if (gate_cache_->is_cache_empty()) { - applyOperation("Identity", {0}, false); - } - - std::size_t id = gate_cache_->get_cache_head_idx(); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* int64_t tensorId*/ static_cast(id), - /* void* */ - static_cast(gate_cache_->get_gate_device_ptr(id)), - /* int32_t unitary*/ 1)); - } - - /** - * @brief Save quantumState information to data provided by a user - * - * @param tensorPtr Pointer to tensors provided by a user - */ - void computeState(int64_t **extentsPtr, void **tensorPtr) { - cutensornetWorkspaceDescriptor_t workDesc; - PL_CUTENSORNET_IS_SUCCESS( - cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); - - // TODO we assign half (magic number is) of free memory size to the - // maximum memory usage. - const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStatePrepare( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* size_t maxWorkspaceSizeDevice */ scratchSize, - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* cudaStream_t unused as of v24.03*/ 0x0)); - - std::size_t worksize = - getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); - - PL_ABORT_IF(worksize > scratchSize, - "Insufficient workspace size on Device!"); - - const std::size_t d_scratch_length = worksize / sizeof(std::size_t); - DataBuffer d_scratch(d_scratch_length, getDevTag(), - true); - - setWorkSpaceMemory(getTNCudaHandle(), workDesc, - reinterpret_cast(d_scratch.getData()), - worksize); - - PL_CUTENSORNET_IS_SUCCESS(cutensornetStateCompute( - /* const cutensornetHandle_t */ getTNCudaHandle(), - /* cutensornetState_t */ getQuantumState(), - /* cutensornetWorkspaceDescriptor_t */ workDesc, - /* int64_t * */ extentsPtr, - /* int64_t *stridesOut */ nullptr, - /* void * */ tensorPtr, - /* cudaStream_t */ getDevTag().getStreamID())); - - PL_CUTENSORNET_IS_SUCCESS( - cutensornetDestroyWorkspaceDescriptor(workDesc)); - } - private: /** * @brief Get accessor of a state tensor + * + * @param tensor_data Pointer to the device memory for state tensor data. + * @param tensor_data_size Size of the tensor data. + * @param projected_modes Projected modes to get the state tensor for. + * @param projectedModeValues Values of the projected modes. + * @param numHyperSamples Number of hyper samples to use in the calculation + * and is set to 1 by default. */ - void get_accessor_(CFP_t *tensor_data, const std::size_t tensor_data_size, const std::vector &projected_modes, const std::vector &projectedModeValues, @@ -470,7 +409,7 @@ class TNCudaBase : public TensornetBase { /* cutensornetStateAccessor_t *tensorNetworkAccessor*/ &accessor)); // Configure the computation - cutensornetAccessorAttributes_t accessor_attribute = + const cutensornetAccessorAttributes_t accessor_attribute = CUTENSORNET_ACCESSOR_CONFIG_NUM_HYPER_SAMPLES; PL_CUTENSORNET_IS_SUCCESS(cutensornetAccessorConfigure( /* const cutensornetHandle_t */ getTNCudaHandle(), @@ -525,7 +464,7 @@ class TNCudaBase : public TensornetBase { PL_CUDA_IS_SUCCESS(cudaStreamSynchronize(getDevTag().getStreamID())); - ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; + const ComplexT scale_scalar = ComplexT{1.0, 0.0} / stateNorm2; CFP_t scale_scalar_cu{scale_scalar.real(), scale_scalar.imag()}; @@ -537,5 +476,78 @@ class TNCudaBase : public TensornetBase { cutensornetDestroyWorkspaceDescriptor(workDesc)); PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroyAccessor(accessor)); } + + protected: + /** + * @brief Dummy tensor operator update to allow multiple calls of + * appendMPSFinalize. This is a workaround to avoid the issue of the + * cutensornet library not allowing multiple calls of appendMPSFinalize. + * + * This function either appends a new `Identity` gate to the graph when the + * gate cache is empty or update the exisisting gate operator by itself. + */ + void dummy_tensor_update() { + if (gate_cache_->is_cache_empty()) { + applyOperation("Identity", {0}, false); + } + + std::size_t id = gate_cache_->get_cache_head_idx(); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* int64_t tensorId*/ static_cast(id), + /* void* */ + static_cast(gate_cache_->get_gate_device_ptr(id)), + /* int32_t unitary*/ 1)); + } + + /** + * @brief Save quantumState information to data provided by a user + * + * @param tensorPtr Pointer to tensors provided by a user + */ + void computeState(int64_t **extentsPtr, void **tensorPtr) { + cutensornetWorkspaceDescriptor_t workDesc; + PL_CUTENSORNET_IS_SUCCESS( + cutensornetCreateWorkspaceDescriptor(getTNCudaHandle(), &workDesc)); + + // TODO we assign half (magic number is) of free memory size to the + // maximum memory usage. + const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStatePrepare( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* size_t maxWorkspaceSizeDevice */ scratchSize, + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* cudaStream_t unused as of v24.03*/ 0x0)); + + std::size_t worksize = + getWorkSpaceMemorySize(getTNCudaHandle(), workDesc); + + PL_ABORT_IF(worksize > scratchSize, + "Insufficient workspace size on Device!"); + + const std::size_t d_scratch_length = worksize / sizeof(std::size_t); + DataBuffer d_scratch(d_scratch_length, getDevTag(), + true); + + setWorkSpaceMemory(getTNCudaHandle(), workDesc, + reinterpret_cast(d_scratch.getData()), + worksize); + + PL_CUTENSORNET_IS_SUCCESS(cutensornetStateCompute( + /* const cutensornetHandle_t */ getTNCudaHandle(), + /* cutensornetState_t */ getQuantumState(), + /* cutensornetWorkspaceDescriptor_t */ workDesc, + /* int64_t * */ extentsPtr, + /* int64_t *stridesOut */ nullptr, + /* void * */ tensorPtr, + /* cudaStream_t */ getDevTag().getStreamID())); + + PL_CUTENSORNET_IS_SUCCESS( + cutensornetDestroyWorkspaceDescriptor(workDesc)); + } }; } // namespace Pennylane::LightningTensor::TNCuda From e8bbdf8c9d52c689fa8e8e8e75a3030d1b19ad4b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:42:04 +0000 Subject: [PATCH 177/227] fix typo --- .../core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 0d69fcc61c..3fcc88bcc3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -336,7 +336,7 @@ class TNCudaBase : public TensornetBase { * @brief Get a slice of the full state tensor * * @param tensor_data Pointer to the device memory for state tensor data. - * @param tensor_data_size Size of the tensor data. + * @param tensor_data_size Size of the state tensor data. * @param wires Wires to get the state tensor for. * @param numHyperSamples Number of hyper samples to use in the calculation * and is set to 1 by default. From 2511d858d0f38ca11f1891240492512d4dbfb98e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 14:49:16 +0000 Subject: [PATCH 178/227] update docstring --- .../src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index beffad3596..9650fc51a7 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -297,9 +297,9 @@ class MPSTNCuda final : public TNCudaBase> { // TODO: This is a dummy tensor update to allow multiple calls to the // `append_mps_final_state` method as well as appending additional - // operations to the graph. This line can be removed in the future when - // the `cutensornet` backend allows multiple calls to the - // `cutensornetStateFinalizeMPS` method. + // operations to the graph. This is a temporary solution and this line + // can be removed in the future when the `cutensornet` backend allows + // multiple calls to the `cutensornetStateFinalizeMPS` method. BaseType::dummy_tensor_update(); } From 38b0db27f46f3bbfb12d8db0de4eeeffc5dcced1 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 15:13:54 +0000 Subject: [PATCH 179/227] add more docstrings --- .../src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 4 +++- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 2 +- pennylane_lightning/lightning_tensor/_tensornet.py | 8 +++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 9650fc51a7..9582a6f42e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -166,6 +166,9 @@ class MPSTNCuda final : public TNCudaBase> { setBasisState(zeroState); } + /** + * @brief Set the quantum state to zero state. + */ void setZeroState() { reset(); } /** @@ -175,7 +178,6 @@ class MPSTNCuda final : public TNCudaBase> { * @param data Pointer to the data on host. * @param length Length of the data. */ - void setIthMPSSite(const std::size_t i, const ComplexT *data, std::size_t length) { PL_ABORT_IF(BaseType::getNumQubits() < i, diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index b0a010e6e3..5d18cf5e5a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -83,7 +83,7 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { static_cast *>(numpyArrayInfo.ptr); tensor_network.setIthMPSSite(idx, data_ptr, ith_site.size()); }, - "Copy StateVector data to C++ backend") + "Pass MPS site data to the C++ backend") .def( "setBasisState", [](TensorNet &tensor_network, diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 13f634c6d0..b645c8abd9 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -31,7 +31,8 @@ from pennylane.wires import Wires -def split(M, bond_dim): +def svd_split(M, bond_dim): + """SVD split a matrix into a matrix product state via numpy linalg.""" U, S, Vd = np.linalg.svd(M, full_matrices=False) U = U @ np.diag(S) # Append singular values to U bonds = len(S) @@ -45,10 +46,11 @@ def split(M, bond_dim): def dense_to_mps(psi, n_wires, bond_dim): + """Convert a dense state vector to a matrix product state.""" Ms = [] psi = np.reshape(psi, (2, -1)) # split psi[2, 2, 2, 2..] = psi[2, (2x2x2...)] - U, S, Vd = split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] + U, S, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] Ms.append(U) bondL = Vd.shape[0] @@ -56,7 +58,7 @@ def dense_to_mps(psi, n_wires, bond_dim): for _ in range(n_wires - 2): psi = np.reshape(psi, (2 * bondL, -1)) # reshape psi[2 * bondL, (2x2x2...)] - U, S, Vd = split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] + U, S, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] Ms.append(U) psi = Vd From 3ebf1a0567d69c1a58d94f1df24e816df5aca8a0 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 15:27:25 +0000 Subject: [PATCH 180/227] tidy up code --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 9582a6f42e..0500e296e9 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -64,7 +64,7 @@ class MPSTNCuda final : public TNCudaBase> { MPSStatus MPSInitialized_ = MPSStatus::MPSInitNotSet; const std::size_t maxBondDim_; - + const std::vector bondDims_; const std::vector> sitesModes_; const std::vector> sitesExtents_; const std::vector> sitesExtents_int64_; @@ -86,7 +86,8 @@ class MPSTNCuda final : public TNCudaBase> { explicit MPSTNCuda(const std::size_t numQubits, const std::size_t maxBondDim) : BaseType(numQubits), maxBondDim_(maxBondDim), - sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()), + bondDims_(setBondDims_()), sitesModes_(setSitesModes_()), + sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); setZeroState(); @@ -98,7 +99,8 @@ class MPSTNCuda final : public TNCudaBase> { explicit MPSTNCuda(const std::size_t numQubits, const std::size_t maxBondDim, DevTag dev_tag) : BaseType(numQubits, dev_tag), maxBondDim_(maxBondDim), - sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()), + bondDims_(setBondDims_()), sitesModes_(setSitesModes_()), + sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); setZeroState(); @@ -217,20 +219,6 @@ class MPSTNCuda final : public TNCudaBase> { CFP_t value_cu = cuUtil::complexToCu(ComplexT{1.0, 0.0}); - // TODO: Refactor this part to set bondDims as a data member variable - std::vector bondDims(BaseType::getNumQubits() - 1, - maxBondDim_); - - for (std::size_t i = 0; i < bondDims.size(); i++) { - std::size_t bondDim = - std::min(i + 1, BaseType::getNumQubits() - i - 1); - if (bondDim > log2(maxBondDim_)) { - bondDims[i] = maxBondDim_; - } else { - bondDims[i] = std::size_t{1} << bondDim; - } - } - for (std::size_t i = 0; i < BaseType::getNumQubits(); i++) { tensors_[i].getDataBuffer().zeroInit(); std::size_t target = 0; @@ -240,7 +228,7 @@ class MPSTNCuda final : public TNCudaBase> { if (i == 0) { target = basisState[idx]; } else { - target = basisState[idx] == 0 ? 0 : bondDims[i - 1]; + target = basisState[idx] == 0 ? 0 : bondDims_[i - 1]; } PL_CUDA_IS_SUCCESS( @@ -342,6 +330,27 @@ class MPSTNCuda final : public TNCudaBase> { } private: + /** + * @brief Return bondDims to the member initializer + * NOTE: This method only works for the open boundary condition + * @return std::vector + */ + std::vector setBondDims_() { + std::vector localBondDims(BaseType::getNumQubits() - 1, + maxBondDim_); + + for (std::size_t i = 0; i < localBondDims.size(); i++) { + std::size_t bondDim = + std::min(i + 1, BaseType::getNumQubits() - i - 1); + if (bondDim > log2(maxBondDim_)) { + localBondDims[i] = maxBondDim_; + } else { + localBondDims[i] = std::size_t{1} << bondDim; + } + } + return localBondDims; + } + /** * @brief Return siteModes to the member initializer * NOTE: This method only works for the open boundary condition @@ -377,19 +386,6 @@ class MPSTNCuda final : public TNCudaBase> { */ std::vector> setSitesExtents_() { std::vector> localSitesExtents; - // TODO: Refactor this part to set bondDims as a data member variable - std::vector bondDims(BaseType::getNumQubits() - 1, - maxBondDim_); - - for (std::size_t i = 0; i < bondDims.size(); i++) { - std::size_t bondDim = - std::min(i + 1, BaseType::getNumQubits() - i - 1); - if (bondDim > log2(maxBondDim_)) { - bondDims[i] = maxBondDim_; - } else { - bondDims[i] = std::size_t{1} << bondDim; - } - } for (std::size_t i = 0; i < BaseType::getNumQubits(); i++) { std::vector localSiteExtents; @@ -397,16 +393,16 @@ class MPSTNCuda final : public TNCudaBase> { if (i == 0) { // Leftmost site (state mode, shared mode) localSiteExtents = std::vector( - {BaseType::getQubitDims()[i], bondDims[i]}); + {BaseType::getQubitDims()[i], bondDims_[i]}); } else if (i == BaseType::getNumQubits() - 1) { // Rightmost site (shared mode, state mode) localSiteExtents = std::vector( - {bondDims[i - 1], BaseType::getQubitDims()[i]}); + {bondDims_[i - 1], BaseType::getQubitDims()[i]}); } else { // Interior sites (state mode, state mode, shared mode) localSiteExtents = std::vector( - {bondDims[i - 1], BaseType::getQubitDims()[i], - bondDims[i]}); + {bondDims_[i - 1], BaseType::getQubitDims()[i], + bondDims_[i]}); } localSitesExtents.push_back(std::move(localSiteExtents)); } From 5620b9edc48e2ac7398f34ddf8828ed8f5ccb1d3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 15:51:02 +0000 Subject: [PATCH 181/227] tidy up code & turn on more python unit tests --- .../simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 5 ++--- .../lightning_tensor/lightning_tensor.py | 1 - tests/test_apply.py | 10 +--------- tests/test_comparison.py | 2 +- tests/test_expval.py | 10 +++++----- tests/test_gates.py | 12 ++---------- 6 files changed, 11 insertions(+), 29 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 0500e296e9..8c28dd14c3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -389,7 +389,6 @@ class MPSTNCuda final : public TNCudaBase> { for (std::size_t i = 0; i < BaseType::getNumQubits(); i++) { std::vector localSiteExtents; - if (i == 0) { // Leftmost site (state mode, shared mode) localSiteExtents = std::vector( @@ -440,8 +439,8 @@ class MPSTNCuda final : public TNCudaBase> { } /** - * @brief Update quantumState (cutensornetState_t) with data provided by a - * user + * @brief Append initial MPS sites to the compute graph with data provided + * by a user * */ void appendInitialMPSState_() { diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 6fb6b798c0..df2200c74d 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -278,7 +278,6 @@ def __init__( self._method = method self._c_dtype = c_dtype - # Set default values aligned with default.tensor self._max_bond_dim = kwargs.get("max_bond_dim", 128) self._cutoff = kwargs.get("cutoff", 0) self._cutoff_mode = kwargs.get("cutoff_mode", "abs") diff --git a/tests/test_apply.py b/tests/test_apply.py index bf9dd7794c..bc696a0a96 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -1434,10 +1434,6 @@ def compute_matrix(*params, **hyperparams): with pytest.raises(ValueError, match="Unsupported operation"): dev.apply_lightning([EmptyGate(0)]) - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support StatePrep", - ) @pytest.mark.parametrize( "ops0", [ @@ -1503,11 +1499,7 @@ def test_circuit_with_stateprep(op, theta, phi, tol): init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0, 0, 0, 0, 0], wires=[0, 1, 2, 3, 4]) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 4967b72bd0..2c16862ae0 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -269,7 +269,7 @@ def circuit(measurement): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor device does not support initialization with a state vector", + reason="lightning.tensor device does not support does not support the direct access to state", ) @pytest.mark.parametrize( "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] diff --git a/tests/test_expval.py b/tests/test_expval.py index 3b262ace18..4fb1042731 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -135,10 +135,6 @@ def test_hadamard_expectation(self, theta, phi, qubit_device, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.Projector()", - ) def test_projector_expectation(self, theta, phi, qubit_device, tol): """Test that Projector variance value is correct""" n_qubits = 2 @@ -150,7 +146,11 @@ def test_projector_expectation(self, theta, phi, qubit_device, tol): init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) - obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) + obs = ( + qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) + if device_name != "lightning.tensor" + else qml.Projector(np.array([0, 1]) / np.sqrt(2), wires=[0]) + ) def circuit(): qml.StatePrep(init_state, wires=range(n_qubits)) diff --git a/tests/test_gates.py b/tests/test_gates.py index 855619efc5..a4e19d6356 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -299,11 +299,7 @@ def test_qubit_RY(theta, phi, tol): init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) @@ -334,11 +330,7 @@ def test_qubit_unitary(n_wires, theta, phi, tol): for perm in perms: def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) From 18e311c23e4b8fb892e0a01ce80114e19d235261 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 17:16:50 +0000 Subject: [PATCH 182/227] test --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 31 ++++++++--------- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 4 +-- .../tncuda/measurements/CMakeLists.txt | 7 +++- .../tncuda/tests/Tests_MPSTNCuda.cpp | 34 +++++++++++++++++++ .../lightning_tensor/_tensornet.py | 3 +- scripts/configure_pyproject_toml.py | 2 +- 6 files changed, 59 insertions(+), 22 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 8c28dd14c3..4f8bde2892 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -174,28 +174,27 @@ class MPSTNCuda final : public TNCudaBase> { void setZeroState() { reset(); } /** - * @brief Set the ith MPS site. + * @brief Update the ith MPS site. * - * @param i Index of the MPS site. - * @param data Pointer to the data on host. - * @param length Length of the data. + * @param site_idx Index of the MPS site. + * @param host_data Pointer to the data on host. + * @param host_data_size Length of the data. */ - void setIthMPSSite(const std::size_t i, const ComplexT *data, - std::size_t length) { - PL_ABORT_IF(BaseType::getNumQubits() < i, - "The size of a basis state should be equal to the number " - "of qubits."); + void updateIthMPSSite(const std::size_t site_idx, const ComplexT *host_data, + std::size_t host_data_size) { + PL_ABORT_IF_NOT( + site_idx < BaseType::getNumQubits(), + "The site index should be less than the number of qubits."); - const std::size_t idx = BaseType::getNumQubits() - i - 1; - PL_ABORT_IF(length > tensors_[idx].getDataBuffer().getLength(), - "The length of the data should be equal to the dimension " - "of the qubit."); + const std::size_t idx = BaseType::getNumQubits() - site_idx - 1; + PL_ABORT_IF_NOT( + host_data_size == tensors_[idx].getDataBuffer().getLength(), + "The length of the host data should match its copy on the device."); tensors_[idx].getDataBuffer().zeroInit(); - PL_CUDA_IS_SUCCESS(cudaMemcpy(tensors_[idx].getDataBuffer().getData(), - data, sizeof(CFP_t) * length, - cudaMemcpyHostToDevice)); + tensors_[idx].getDataBuffer().CopyHostDataToGpu(host_data, + host_data_size); } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index 5d18cf5e5a..e679915243 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -75,13 +75,13 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { }, "Copy StateVector data into a Numpy array.") .def( - "setIthSite", + "updateIthSite", [](TensorNet &tensor_network, const std::size_t idx, np_arr_c &ith_site) { py::buffer_info numpyArrayInfo = ith_site.request(); auto *data_ptr = static_cast *>(numpyArrayInfo.ptr); - tensor_network.setIthMPSSite(idx, data_ptr, ith_site.size()); + tensor_network.updateIthMPSSite(idx, data_ptr, ith_site.size()); }, "Pass MPS site data to the C++ backend") .def( diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt index 490d6d2fa9..d19ff1dd5e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt @@ -1,7 +1,12 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25.2) project(${PL_BACKEND}_measurements LANGUAGES CXX C CUDA) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CUDA_STANDARD 20) +set(CMAKE_CUDA_STANDARD_REQUIRED ON) + set(LTENSOR_MPS_FILES cuda_kernels_measures.cu CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND}_measurements STATIC ${LTENSOR_MPS_FILES}) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index 78363c43b8..c17850b8c0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -58,6 +58,40 @@ TEMPLATE_PRODUCT_TEST_CASE("MPSTNCuda::Constructibility", } } +TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { + SECTION("Set MPS site with wrong site index") { + std::size_t num_qubits = 3; + std::size_t maxBondDim = 3; + std::size_t siteIdx = 3; + + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> site_data(1, {0.0, 0.0}); + + REQUIRE_THROWS_WITH( + mps_state.updateIthMPSSite(siteIdx, site_data.data(), + site_data.size()), + Catch::Matchers::Contains( + "The site index should be less than the number of qubits.")); + } + + SECTION("Set MPS site with wrong site data size") { + std::size_t num_qubits = 3; + std::size_t maxBondDim = 3; + std::size_t siteIdx = 0; + + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> site_data(1, {0.0, 0.0}); + + REQUIRE_THROWS_WITH( + mps_state.updateIthMPSSite(siteIdx, site_data.data(), + site_data.size()), + Catch::Matchers::Contains("The length of the host data should " + "match its copy on the device.")); + } +} + TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", float, double) { std::vector> basisStates = { diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index b645c8abd9..e6335ac275 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -201,8 +201,7 @@ def _apply_state_vector(self, state, device_wires: Wires): M = dense_to_mps(state, self._num_wires, self._max_bond_dim) for i in range(len(M)): - print(M[i].shape) - self._tensornet.setIthSite(i, M[i]) + self._tensornet.updateIthSite(i, M[i]) def _apply_basis_state(self, state, wires): """Initialize the quantum state in a specified computational basis state. diff --git a/scripts/configure_pyproject_toml.py b/scripts/configure_pyproject_toml.py index 57517954e3..8f643db8ca 100755 --- a/scripts/configure_pyproject_toml.py +++ b/scripts/configure_pyproject_toml.py @@ -57,7 +57,7 @@ def parse_args(): # Configure Build. # ------------------------ requires = [ - "cmake~=3.24.0", + "cmake~=3.26.0", "ninja; platform_system!='Windows'", "setuptools>=42", "toml", From b84db90416da9fb876f213e6e637aa98e95c1ecc Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 18:01:01 +0000 Subject: [PATCH 183/227] update C++ unit tests --- .../tncuda/measurements/CMakeLists.txt | 7 +---- .../tncuda/tests/Tests_MPSTNCuda.cpp | 27 +++++++++++++++++++ scripts/configure_pyproject_toml.py | 2 +- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt index d19ff1dd5e..490d6d2fa9 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt @@ -1,12 +1,7 @@ -cmake_minimum_required(VERSION 3.25.2) +cmake_minimum_required(VERSION 3.20) project(${PL_BACKEND}_measurements LANGUAGES CXX C CUDA) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CUDA_STANDARD 20) -set(CMAKE_CUDA_STANDARD_REQUIRED ON) - set(LTENSOR_MPS_FILES cuda_kernels_measures.cu CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND}_measurements STATIC ${LTENSOR_MPS_FILES}) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index c17850b8c0..1bfce1ca41 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -90,6 +90,33 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { Catch::Matchers::Contains("The length of the host data should " "match its copy on the device.")); } + + SECTION("Set MPS sites") { + std::size_t num_qubits = 2; + std::size_t maxBondDim = 3; + + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + mps_state.reset(); // Reset the state to zero state + + std::vector> site0_data(4, {0.0, 0.0}); //MSB + std::vector> site1_data(4, {0.0, 0.0}); //LSB + + site0_data[2] = {1.0, 0.0}; + site1_data[1] = {1.0, 0.0}; + + mps_state.updateIthMPSSite(0, site0_data.data(), site0_data.size()); + mps_state.updateIthMPSSite(1, site1_data.data(), site1_data.size()); + + auto results = mps_state.getDataVector(); + + std::vector> expected_state( + std::size_t{1} << num_qubits, std::complex({0.0, 0.0})); + + expected_state[3] = {1.0, 0.0}; + + CHECK(expected_state == Pennylane::Util::approx(results)); + } } TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", diff --git a/scripts/configure_pyproject_toml.py b/scripts/configure_pyproject_toml.py index 8f643db8ca..57517954e3 100755 --- a/scripts/configure_pyproject_toml.py +++ b/scripts/configure_pyproject_toml.py @@ -57,7 +57,7 @@ def parse_args(): # Configure Build. # ------------------------ requires = [ - "cmake~=3.26.0", + "cmake~=3.24.0", "ninja; platform_system!='Windows'", "setuptools>=42", "toml", From 4e9c9fe69b4207c676fe45e44d398e990adc696b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 18:03:56 +0000 Subject: [PATCH 184/227] add changelog --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 70b97ac82c..f8440786ea 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add `qml.StatePrep()` and `qml.QubitStateVector()` support to `lightning.tensor`. + [(#849)](https://github.com/PennyLaneAI/pennylane-lightning/pull/849) + * Add `qml.probs()` measurement support to `lightning.tensor`. [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) From 3d873f081ab7c591b38e7dd67de31fa5592a7943 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 18:07:29 +0000 Subject: [PATCH 185/227] update python docstring and make format --- .../lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp | 4 ++-- pennylane_lightning/lightning_tensor/_tensornet.py | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index 1bfce1ca41..d581b74609 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -99,8 +99,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { mps_state.reset(); // Reset the state to zero state - std::vector> site0_data(4, {0.0, 0.0}); //MSB - std::vector> site1_data(4, {0.0, 0.0}); //LSB + std::vector> site0_data(4, {0.0, 0.0}); // MSB + std::vector> site1_data(4, {0.0, 0.0}); // LSB site0_data[2] = {1.0, 0.0}; site1_data[1] = {1.0, 0.0}; diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index e6335ac275..fadb841a17 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -153,16 +153,14 @@ def reset_state(self): self._tensornet.reset() def _preprocess_state_vector(self, state, device_wires): - """Initialize the internal state vector in a specified state. + """Convert a specified state to a full internal state vector. Args: state (array[complex]): normalized input state of length ``2**len(wires)`` - or broadcasted state of shape ``(batch_size, 2**len(wires))`` device_wires (Wires): wires that get initialized in the state Returns: array[complex]: normalized input state of length ``2**len(wires)`` - or broadcasted state of shape ``(batch_size, 2**len(wires))`` """ output_shape = [2] * self._num_wires # special case for integral types @@ -189,7 +187,7 @@ def _preprocess_state_vector(self, state, device_wires): return np.reshape(full_state, output_shape).ravel(order="C") def _apply_state_vector(self, state, device_wires: Wires): - """Initialize the internal state vector in a specified state. + """Convert a specified state to MPS sites. Args: state (array[complex]): normalized input state of length ``2**len(wires)`` or broadcasted state of shape ``(batch_size, 2**len(wires))`` From bac26ac50538a235ddbc39b751623a74d752799f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 18:40:19 +0000 Subject: [PATCH 186/227] required cmake version to 3.26 --- scripts/configure_pyproject_toml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/configure_pyproject_toml.py b/scripts/configure_pyproject_toml.py index 57517954e3..8f643db8ca 100755 --- a/scripts/configure_pyproject_toml.py +++ b/scripts/configure_pyproject_toml.py @@ -57,7 +57,7 @@ def parse_args(): # Configure Build. # ------------------------ requires = [ - "cmake~=3.24.0", + "cmake~=3.26.0", "ninja; platform_system!='Windows'", "setuptools>=42", "toml", From 9dc2ffb59bc0c078273a8ea02f28ed3ba963f869 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 18:41:33 +0000 Subject: [PATCH 187/227] change cmake version from 3.24 to 3.26 --- scripts/configure_pyproject_toml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/configure_pyproject_toml.py b/scripts/configure_pyproject_toml.py index 57517954e3..8f643db8ca 100755 --- a/scripts/configure_pyproject_toml.py +++ b/scripts/configure_pyproject_toml.py @@ -57,7 +57,7 @@ def parse_args(): # Configure Build. # ------------------------ requires = [ - "cmake~=3.24.0", + "cmake~=3.26.0", "ninja; platform_system!='Windows'", "setuptools>=42", "toml", From 4a97ad9b543c9c93cdda102daa0af4b629a7e606 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 19:08:05 +0000 Subject: [PATCH 188/227] revert some changes in py tests --- tests/test_var.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_var.py b/tests/test_var.py index c5b700c58c..78097467e2 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -61,6 +61,9 @@ def test_projector_var(self, theta, phi, qubit_device, tol): dev_def = qml.device("default.qubit", wires=n_qubits) dev = qubit_device(wires=n_qubits) + if "Projector" not in dev.observables: + pytest.skip("Device does not support the Projector observable.") + init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) obs = ( From e8f05a6e0e38419b21c2d1cc48f7fca89fa8131b Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 20:11:43 +0000 Subject: [PATCH 189/227] cmake 3.26->3.24 --- scripts/configure_pyproject_toml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/configure_pyproject_toml.py b/scripts/configure_pyproject_toml.py index 8f643db8ca..57517954e3 100755 --- a/scripts/configure_pyproject_toml.py +++ b/scripts/configure_pyproject_toml.py @@ -57,7 +57,7 @@ def parse_args(): # Configure Build. # ------------------------ requires = [ - "cmake~=3.26.0", + "cmake~=3.24.0", "ninja; platform_system!='Windows'", "setuptools>=42", "toml", From 491d0673de1bf13faa6e9bc5247ee23caa3c6114 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 21:01:04 +0000 Subject: [PATCH 190/227] revert cmake 3.26 to 3.24 --- scripts/configure_pyproject_toml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/configure_pyproject_toml.py b/scripts/configure_pyproject_toml.py index 8f643db8ca..57517954e3 100755 --- a/scripts/configure_pyproject_toml.py +++ b/scripts/configure_pyproject_toml.py @@ -57,7 +57,7 @@ def parse_args(): # Configure Build. # ------------------------ requires = [ - "cmake~=3.26.0", + "cmake~=3.24.0", "ninja; platform_system!='Windows'", "setuptools>=42", "toml", From 761450ca867cb6af6f8282e77f78edc9fa9ce206 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Tue, 13 Aug 2024 21:01:23 +0000 Subject: [PATCH 191/227] Auto update version from '0.38.0-dev32' to '0.38.0-dev33' --- 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 1e786a92cd..281ac48074 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.38.0-dev32" +__version__ = "0.38.0-dev33" From 464aba7dff62a9ac259b90b7787ad61a16663369 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 22:32:36 +0000 Subject: [PATCH 192/227] cmake 3.24 --- .../lightning_tensor/tncuda/measurements/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt index 490d6d2fa9..f5c3a80860 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20) project(${PL_BACKEND}_measurements LANGUAGES CXX C CUDA) +if(NOT DEFINED CMAKE_CUDA20_STANDARD_COMPILE_OPTION) + set(CMAKE_CUDA20_STANDARD_COMPILE_OPTION "") + set(CMAKE_CUDA20_EXTENSION_COMPILE_OPTION "") +endif() + set(LTENSOR_MPS_FILES cuda_kernels_measures.cu CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND}_measurements STATIC ${LTENSOR_MPS_FILES}) From 61206fc633aeb1d22bbbe7383618e49f5d78c5f1 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 13 Aug 2024 22:36:41 +0000 Subject: [PATCH 193/227] enable cmake 3.24 --- .../lightning_tensor/tncuda/measurements/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt index 490d6d2fa9..f5c3a80860 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20) project(${PL_BACKEND}_measurements LANGUAGES CXX C CUDA) +if(NOT DEFINED CMAKE_CUDA20_STANDARD_COMPILE_OPTION) + set(CMAKE_CUDA20_STANDARD_COMPILE_OPTION "") + set(CMAKE_CUDA20_EXTENSION_COMPILE_OPTION "") +endif() + set(LTENSOR_MPS_FILES cuda_kernels_measures.cu CACHE INTERNAL "" FORCE) add_library(${PL_BACKEND}_measurements STATIC ${LTENSOR_MPS_FILES}) From 4ae83ac885cfa4008d66fe8f06092c363f2e963f Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 19 Aug 2024 13:17:49 +0000 Subject: [PATCH 194/227] apply some Vincent's comments --- .../src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 5 +++-- .../lightning_tensor/tncuda/gates/TNCudaGateCache.hpp | 4 +--- .../tncuda/measurements/cuda_kernels_measures.cu | 4 ++-- pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp | 3 +++ 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 3fcc88bcc3..2a0d80c1b0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -366,8 +366,9 @@ class TNCudaBase : public TensornetBase { } else { DataBuffer tmp(tensor_data_size, getDevTag(), true); - for (std::size_t idx = 0; - idx < (size_t(1) << projected_modes.size()); idx++) { + const std::size_t projected_modes_size = size_t(1) + << projected_modes.size(); + for (std::size_t idx = 0; idx < projected_modes_size; idx++) { for (std::size_t j = 0; j < projected_modes.size(); j++) { projectedModeValues[j] = (idx >> j) & 1; } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp index 63556f5f9c..7073e4d74d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp @@ -165,9 +165,7 @@ template class TNCudaGateCache { */ auto get_cache_head_idx() const -> std::size_t { auto it = device_gates_.begin(); - std::size_t idx; - idx = it->first; - return idx; + return it->first; } /** diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu index c43e1e3fb4..1b428daa90 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu @@ -107,7 +107,7 @@ template void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, std::size_t thread_per_block, cudaStream_t stream_id) { auto dv = std::div(data_size, thread_per_block); - std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); + const std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); dim3 blockSize(thread_per_block, 1, 1); dim3 gridSize(block_per_grid, 1); @@ -133,7 +133,7 @@ void normalizeProbs_CUDA_call(PrecisionT *probs, const int data_size, std::size_t thread_per_block, cudaStream_t stream_id) { auto dv = std::div(data_size, thread_per_block); - std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); + const std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); dim3 blockSize(thread_per_block, 1, 1); dim3 gridSize(block_per_grid, 1); diff --git a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp index 00c995529f..d1441b6aa8 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/LinearAlg.hpp @@ -118,6 +118,9 @@ inline void GEMM_CUDA_device(T *A, T *B, T *C, const int m, const int k, * * @param A Device data pointer of vector A. * @param n Length of the vector. + * @param dev_id the device on which the function should be executed. + * @param stream_id the CUDA stream on which the operation should be executed. + * @param cublas the CublasCaller object that manages the cuBLAS handle. * @param res Device data pointer to store the result. */ template From c95bf1d81bdd4099688e7b92fb6f0ac7a3b22b08 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 19 Aug 2024 13:20:16 +0000 Subject: [PATCH 195/227] Auto update version from '0.38.0-dev33' to '0.38.0-dev36' --- 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 281ac48074..67e62e0daa 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.38.0-dev33" +__version__ = "0.38.0-dev36" From 052f2155e595a39b3a381f32365ea081215ab825 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 19 Aug 2024 13:29:38 +0000 Subject: [PATCH 196/227] apply more suggestions --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- .../measurements/cuda_kernels_measures.cu | 51 ++++++++----------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 2a0d80c1b0..b9f338995e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -492,7 +492,7 @@ class TNCudaBase : public TensornetBase { applyOperation("Identity", {0}, false); } - std::size_t id = gate_cache_->get_cache_head_idx(); + const std::size_t id = gate_cache_->get_cache_head_idx(); PL_CUTENSORNET_IS_SUCCESS(cutensornetStateUpdateTensorOperator( /* const cutensornetHandle_t */ getTNCudaHandle(), diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu index 1b428daa90..f00ab8e58b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu @@ -17,36 +17,6 @@ #include "cuda_helpers.hpp" namespace Pennylane::LightningTensor::TNCuda::Measures { -/** - * @brief Explicitly get the probability of given state tensor data on GPU - * device. - * - * @param state Complex data pointer of state tensor on device. - * @param probs The probability result on device. - * @param data_size The length of state tensor on device. - * @param thread_per_block Number of threads set per block. - * @param stream_id Stream id of CUDA calls - */ -void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, - const std::size_t thread_per_block, cudaStream_t stream_id); -void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, - const std::size_t thread_per_block, cudaStream_t stream_id); - -/** - * @brief Explicitly get the probability of given state tensor data on GPU - * device. - * - * @param probs The probability to be normalized. - * @param data_size The length of state tensor on device. - * @param thread_per_block Number of threads set per block. - * @param stream_id Stream id of CUDA calls - */ -void normalizeProbs_CUDA(float *probs, const int data_size, const float sum, - const std::size_t thread_per_block, - cudaStream_t stream_id); -void normalizeProbs_CUDA(double *probs, const int data_size, const double sum, - const std::size_t thread_per_block, - cudaStream_t stream_id); /** * @brief The CUDA kernel that calculate the probability from a given state @@ -107,7 +77,7 @@ template void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, std::size_t thread_per_block, cudaStream_t stream_id) { auto dv = std::div(data_size, thread_per_block); - const std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); + std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); dim3 blockSize(thread_per_block, 1, 1); dim3 gridSize(block_per_grid, 1); @@ -144,6 +114,16 @@ void normalizeProbs_CUDA_call(PrecisionT *probs, const int data_size, } // Definitions +/** + * @brief Explicitly get the probability of given state tensor data on GPU + * device. + * + * @param state Complex data pointer of state tensor on device. + * @param probs The probability result on device. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ void getProbs_CUDA(cuComplex *state, float *probs, const int data_size, const std::size_t thread_per_block, cudaStream_t stream_id) { getProbs_CUDA_call(state, probs, data_size, @@ -156,6 +136,15 @@ void getProbs_CUDA(cuDoubleComplex *state, double *probs, const int data_size, thread_per_block, stream_id); } +/** + * @brief Explicitly get the probability of given state tensor data on GPU + * device. + * + * @param probs The probability to be normalized. + * @param data_size The length of state tensor on device. + * @param thread_per_block Number of threads set per block. + * @param stream_id Stream id of CUDA calls + */ void normalizeProbs_CUDA(float *probs, const int data_size, const float sum, const std::size_t thread_per_block, cudaStream_t stream_id) { From e3b45ec3455fe156dd7118536b7001e4b3618c0d Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 19 Aug 2024 13:35:13 +0000 Subject: [PATCH 197/227] Auto update version from '0.38.0-dev36' to '0.38.0-dev37' --- 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 67e62e0daa..3d04670e9d 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.38.0-dev36" +__version__ = "0.38.0-dev37" From 73ba4a887253a5dc0cf68bab23d8dc6d3e419589 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 19 Aug 2024 14:11:42 +0000 Subject: [PATCH 198/227] Auto update version from '0.38.0-dev36' to '0.38.0-dev37' --- 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 67e62e0daa..3d04670e9d 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.38.0-dev36" +__version__ = "0.38.0-dev37" From 87d19399c1d4f9479e10314af16979edae715732 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 19 Aug 2024 14:16:09 +0000 Subject: [PATCH 199/227] is_cache_empty->is_empty --- .../core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 2 +- .../lightning_tensor/tncuda/gates/TNCudaGateCache.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index b9f338995e..8ca3da2d12 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -488,7 +488,7 @@ class TNCudaBase : public TensornetBase { * gate cache is empty or update the exisisting gate operator by itself. */ void dummy_tensor_update() { - if (gate_cache_->is_cache_empty()) { + if (gate_cache_->is_empty()) { applyOperation("Identity", {0}, false); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp index 7073e4d74d..377ccc66ce 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/TNCudaGateCache.hpp @@ -171,7 +171,7 @@ template class TNCudaGateCache { /** * @brief Returns if the `device_gates_` is empty. */ - auto is_cache_empty() const -> bool { return device_gates_.empty(); } + auto is_empty() const -> bool { return device_gates_.empty(); } private: const DevTag device_tag_; From d86fa355d18ef6e22bece20b08f8aa0eaa110975 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 19 Aug 2024 14:19:22 +0000 Subject: [PATCH 200/227] update --- .../tncuda/measurements/cuda_kernels_measures.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu index f00ab8e58b..266486d24b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu @@ -77,7 +77,7 @@ template void getProbs_CUDA_call(GPUDataT *state, PrecisionT *probs, const int data_size, std::size_t thread_per_block, cudaStream_t stream_id) { auto dv = std::div(data_size, thread_per_block); - std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); + const std::size_t num_blocks = dv.quot + (dv.rem == 0 ? 0 : 1); const std::size_t block_per_grid = (num_blocks == 0 ? 1 : num_blocks); dim3 blockSize(thread_per_block, 1, 1); dim3 gridSize(block_per_grid, 1); From 1092fadfda8454fd3c1c338498ede53c389e54c9 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 19 Aug 2024 14:37:16 +0000 Subject: [PATCH 201/227] apply Vincent's comments --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 7 +++---- .../tncuda/tests/Tests_MPSTNCuda.cpp | 16 ++++++++-------- .../lightning_tensor/_tensornet.py | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 4f8bde2892..0e62f75624 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -169,7 +169,7 @@ class MPSTNCuda final : public TNCudaBase> { } /** - * @brief Set the quantum state to zero state. + * @brief Set the quantum state to the zero state. */ void setZeroState() { reset(); } @@ -341,9 +341,8 @@ class MPSTNCuda final : public TNCudaBase> { for (std::size_t i = 0; i < localBondDims.size(); i++) { std::size_t bondDim = std::min(i + 1, BaseType::getNumQubits() - i - 1); - if (bondDim > log2(maxBondDim_)) { - localBondDims[i] = maxBondDim_; - } else { + + if (bondDim <= log2(maxBondDim_)) { localBondDims[i] = std::size_t{1} << bondDim; } } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index d581b74609..f1795a011d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -60,9 +60,9 @@ TEMPLATE_PRODUCT_TEST_CASE("MPSTNCuda::Constructibility", TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { SECTION("Set MPS site with wrong site index") { - std::size_t num_qubits = 3; - std::size_t maxBondDim = 3; - std::size_t siteIdx = 3; + const std::size_t num_qubits = 3; + const std::size_t maxBondDim = 3; + const std::size_t siteIdx = 3; MPSTNCuda mps_state{num_qubits, maxBondDim}; @@ -76,9 +76,9 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { } SECTION("Set MPS site with wrong site data size") { - std::size_t num_qubits = 3; - std::size_t maxBondDim = 3; - std::size_t siteIdx = 0; + const std::size_t num_qubits = 3; + const std::size_t maxBondDim = 3; + const std::size_t siteIdx = 0; MPSTNCuda mps_state{num_qubits, maxBondDim}; @@ -92,8 +92,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { } SECTION("Set MPS sites") { - std::size_t num_qubits = 2; - std::size_t maxBondDim = 3; + const std::size_t num_qubits = 2; + const std::size_t maxBondDim = 3; MPSTNCuda mps_state{num_qubits, maxBondDim}; diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index fadb841a17..235082599a 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -32,7 +32,7 @@ def svd_split(M, bond_dim): - """SVD split a matrix into a matrix product state via numpy linalg.""" + """SVD split a matrix into a matrix product state via numpy linalg. Note that this function is to be moved to the C++ layer.""" U, S, Vd = np.linalg.svd(M, full_matrices=False) U = U @ np.diag(S) # Append singular values to U bonds = len(S) From c337dc324cd3cc7ee8458a2a47fcc1d7d9b447c3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Mon, 19 Aug 2024 15:01:19 +0000 Subject: [PATCH 202/227] wrap update MPS sites into C++ layer --- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 16 +++++++++------- .../lightning_tensor/_tensornet.py | 3 +-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index e679915243..9094f53e39 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -75,13 +75,15 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { }, "Copy StateVector data into a Numpy array.") .def( - "updateIthSite", - [](TensorNet &tensor_network, const std::size_t idx, - np_arr_c &ith_site) { - py::buffer_info numpyArrayInfo = ith_site.request(); - auto *data_ptr = - static_cast *>(numpyArrayInfo.ptr); - tensor_network.updateIthMPSSite(idx, data_ptr, ith_site.size()); + "updateMPSSites", + [](TensorNet &tensor_network, std::vector &sites) { + for (std::size_t idx = 0; idx < sites.size(); idx++) { + py::buffer_info numpyArrayInfo = sites[idx].request(); + auto *data_ptr = static_cast *>( + numpyArrayInfo.ptr); + tensor_network.updateIthMPSSite(idx, data_ptr, + sites[idx].size()); + } }, "Pass MPS site data to the C++ backend") .def( diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 235082599a..a91debc13a 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -198,8 +198,7 @@ def _apply_state_vector(self, state, device_wires: Wires): M = dense_to_mps(state, self._num_wires, self._max_bond_dim) - for i in range(len(M)): - self._tensornet.updateIthSite(i, M[i]) + self._tensornet.updateMPSSites(M) def _apply_basis_state(self, state, wires): """Initialize the quantum state in a specified computational basis state. From 617aceeb7f5e48b7faeaaf45861205b096330f66 Mon Sep 17 00:00:00 2001 From: Shuli Shu <31480676+multiphaseCFD@users.noreply.github.com> Date: Tue, 20 Aug 2024 09:05:51 -0400 Subject: [PATCH 203/227] Update .github/CHANGELOG.md Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- .github/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 779bd7ee21..0382902837 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,7 +2,7 @@ ### New features since last release -* Add `qml.probs()` measurement support to `lightning.tensor`. +* Add the analytic `qml.probs()` measurement support to `lightning.tensor`. [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) * Add `qml.state()` measurement support to `lightning.tensor`. From c914297d03fb48eb3ac758f94c346806f8c3f41d Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Tue, 20 Aug 2024 13:06:08 +0000 Subject: [PATCH 204/227] Auto update version from '0.38.0-dev37' to '0.38.0-dev39' --- 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 3d04670e9d..b4c1ef4399 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.38.0-dev37" +__version__ = "0.38.0-dev39" From a6db6af664962cd024e095a2056b8b845329c4d3 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 20 Aug 2024 13:48:04 +0000 Subject: [PATCH 205/227] apply some Ali's suggestions --- .../simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 10 +++++++++- .../simulators/lightning_tensor/tncuda/TNCudaBase.hpp | 9 ++++----- .../tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp | 2 ++ .../tncuda/measurements/MeasurementsTNCuda.hpp | 10 ++++++++-- .../tncuda/measurements/cuda_kernels_measures.cu | 2 +- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 26d4d27d6e..dad38bfdd6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -258,7 +258,15 @@ class MPSTNCuda final : public TNCudaBase> { // `append_mps_final_state` method as well as appending additional // operations to the graph. This is a temporary solution and this line // can be removed in the future when the `cutensornet` backend allows - // multiple calls to the `cutensornetStateFinalizeMPS` method. + // multiple calls to the `cutensornetStateFinalizeMPS` method. For more + // details, please see the `cutensornet` high-level API workflow logic + // [here] + // (https://docs.nvidia.com/cuda/cuquantum/latest/cutensornet/api/functions.html#high-level-tensor-network-api). + // In order to proceed with the following gate operations or + // measurements after calling the `cutensornetStateCompute()` API, we + // have to call the `cutensornetStateUpdateTensor()` API, which is + // wrapped inside the `dummy_tensor_update()` method. + // BaseType::dummy_tensor_update(); } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 8ca3da2d12..6041a1d150 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -350,11 +350,10 @@ class TNCudaBase : public TensornetBase { std::vector projected_modes{}; - for (std::size_t idx = 0; idx < BaseType::getNumQubits(); idx++) { - auto it = std::find(stateModes.begin(), stateModes.end(), - static_cast(idx)); + for (int32_t idx = 0; idx < BaseType::getNumQubits(); idx++) { + auto it = std::find(stateModes.begin(), stateModes.end(), idx); if (it == stateModes.end()) { - projected_modes.emplace_back(static_cast(idx)); + projected_modes.emplace_back(idx); } } @@ -485,7 +484,7 @@ class TNCudaBase : public TensornetBase { * cutensornet library not allowing multiple calls of appendMPSFinalize. * * This function either appends a new `Identity` gate to the graph when the - * gate cache is empty or update the exisisting gate operator by itself. + * gate cache is empty or update the existing gate operator by itself. */ void dummy_tensor_update() { if (gate_cache_->is_empty()) { diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp index 3000e80054..8718cb1934 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/gates/tests/Test_MPSTNCuda_NonParam.cpp @@ -74,6 +74,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::Gates::Hadamard", "[MPSTNCuda_Nonparam]", float, const std::size_t index = GENERATE(0, 1, 2); MPSTNCuda mps_state{num_qubits, maxExtent, dev_tag}; + mps_state.append_mps_final_state(); + mps_state.applyOperation("Hadamard", {index}, inverse); mps_state.append_mps_final_state(); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 751ed64fba..2ceb9cac34 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -79,10 +79,16 @@ template class MeasurementsTNCuda { /** * @brief Probabilities for a subset of the full system. * + * @tparam thread_per_block Number of threads per block in the CUDA kernel + * and is default as `256`. `256` is chosen as a default value because it is + * a balance of warp size and occupancy. Note that this number is not + * optimal for all cases and may need to be adjusted based on the specific + * use case, especially the number of elements in the subset is small. + * * @param wires Wires will restrict probabilities to a subset * of the full system. - * @param numHyperSamples Number of hyper samples to use in the calculation - * and is default as 1. + * @param numHyperSamples Number of hyper samples to be used in the + * calculation and is default as 1. * * @return Floating point std::vector with probabilities. */ diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu index 266486d24b..520ca9fd2d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/cuda_kernels_measures.cu @@ -19,7 +19,7 @@ namespace Pennylane::LightningTensor::TNCuda::Measures { /** - * @brief The CUDA kernel that calculate the probability from a given state + * @brief The CUDA kernel that calculates the probability from a given state * tensor data on GPU device. * * @tparam GPUDataT cuComplex data type (cuComplex or cuDoubleComplex). From 89a3815d85fea103e51ba2786282d6870b511790 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 20 Aug 2024 14:46:45 +0000 Subject: [PATCH 206/227] run some calculations on cpu when the suset is small --- .../lightning_tensor/tncuda/TNCudaBase.hpp | 3 +- .../measurements/MeasurementsTNCuda.hpp | 57 +++++++++++++------ 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp index 6041a1d150..35f296930c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCudaBase.hpp @@ -350,7 +350,8 @@ class TNCudaBase : public TensornetBase { std::vector projected_modes{}; - for (int32_t idx = 0; idx < BaseType::getNumQubits(); idx++) { + for (int32_t idx = 0; + idx < static_cast(BaseType::getNumQubits()); idx++) { auto it = std::find(stateModes.begin(), stateModes.end(), idx); if (it == stateModes.end()) { projected_modes.emplace_back(idx); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 2ceb9cac34..dda0fafb00 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -115,24 +115,45 @@ template class MeasurementsTNCuda { d_output_tensor.getLength(), wires, numHyperSamples); - getProbs_CUDA(d_output_tensor.getData(), d_output_probs.getData(), - length, static_cast(thread_per_block), - tensor_network_.getDevTag().getStreamID()); - - PrecisionT sum; - - asum_CUDA_device(d_output_probs.getData(), length, - tensor_network_.getDevTag().getDeviceID(), - tensor_network_.getDevTag().getStreamID(), - tensor_network_.getCublasCaller(), &sum); - - PL_ABORT_IF(sum == 0.0, "Sum of probabilities is zero."); - - normalizeProbs_CUDA(d_output_probs.getData(), length, sum, - static_cast(thread_per_block), - tensor_network_.getDevTag().getStreamID()); - - d_output_probs.CopyGpuDataToHost(h_res.data(), h_res.size()); + // `7` here means `256` elements to be calculated + // LCOV_EXCL_START + if (wires.size() > 7) { + getProbs_CUDA(d_output_tensor.getData(), d_output_probs.getData(), + length, static_cast(thread_per_block), + tensor_network_.getDevTag().getStreamID()); + + PrecisionT sum; + + asum_CUDA_device( + d_output_probs.getData(), length, + tensor_network_.getDevTag().getDeviceID(), + tensor_network_.getDevTag().getStreamID(), + tensor_network_.getCublasCaller(), &sum); + + PL_ABORT_IF(sum == 0.0, "Sum of probabilities is zero."); + + normalizeProbs_CUDA(d_output_probs.getData(), length, sum, + static_cast(thread_per_block), + tensor_network_.getDevTag().getStreamID()); + + d_output_probs.CopyGpuDataToHost(h_res.data(), h_res.size()); + } else { + // LCOV_EXCL_STOP + std::vector h_state_vector(length); + d_output_tensor.CopyGpuDataToHost(h_state_vector.data(), + h_state_vector.size()); + for (std::size_t i = 0; i < length; i++) { + h_res[i] = std::norm(h_state_vector[i]); + } + + PrecisionT sum = std::accumulate(h_res.begin(), h_res.end(), 0.0); + + PL_ABORT_IF(sum == 0.0, "Sum of probabilities is zero."); + + for (std::size_t i = 0; i < length; i++) { + h_res[i] /= sum; + } + } return h_res; } From b7706f2891a911bb571b926103f31fb6aa4db883 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 20 Aug 2024 14:47:24 +0000 Subject: [PATCH 207/227] add TODOs --- .../tncuda/measurements/MeasurementsTNCuda.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index dda0fafb00..6ca7f2283e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -142,14 +142,16 @@ template class MeasurementsTNCuda { std::vector h_state_vector(length); d_output_tensor.CopyGpuDataToHost(h_state_vector.data(), h_state_vector.size()); + // TODO: OMP support for (std::size_t i = 0; i < length; i++) { h_res[i] = std::norm(h_state_vector[i]); } + // TODO: OMP support PrecisionT sum = std::accumulate(h_res.begin(), h_res.end(), 0.0); PL_ABORT_IF(sum == 0.0, "Sum of probabilities is zero."); - + // TODO: OMP support for (std::size_t i = 0; i < length; i++) { h_res[i] /= sum; } From 2aaaf65db19b5a8ae76bf0b52a90ec5b9227d43d Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Tue, 20 Aug 2024 14:49:13 +0000 Subject: [PATCH 208/227] Auto update version from '0.38.0-dev38' to '0.38.0-dev39' --- 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 358f5c7cc7..b4c1ef4399 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.38.0-dev38" +__version__ = "0.38.0-dev39" From b014fbedcac8cbb0e6b19e2d3ae57c2312ddf14a Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Tue, 20 Aug 2024 16:23:19 +0000 Subject: [PATCH 209/227] add unit tests for asum_CUDA_device --- .../cuda_utils/tests/Test_LinearAlgebra.cpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp index b5b837f1e2..a4201f22d5 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp @@ -26,8 +26,7 @@ /** * @file - * Tests linear algebra functionality defined for the class - * StateVectorCudaManaged. + * Tests CUDA library based linear algebra functionality. */ /// @cond DEV @@ -97,3 +96,23 @@ TEMPLATE_TEST_CASE("Linear Algebra::SparseMV", "[Linear Algebra]", float, } } } + +TEMPLATE_TEST_CASE("Linear Algebra::asum_CUDA_device", "[Linear Algebra]", + float, double) { + std::vector vec{1.0, 2.0, 3.0, 4.0, 5.0, + 6.0, 7.0, 8.0, 9.0, 10.0}; + + DataBuffer vec_d(vec.size()); + + vec_d.CopyHostDataToGpu(vec.data(), vec.size()); + + auto cublasCaller = make_shared_cublas_caller(); + + SECTION("Testing asum_CUDA_device") { + TestType result; + asum_CUDA_device(vec_d.getData(), vec_d.getLength(), vec_d.getDevice(), + vec_d.getStream(), *cublasCaller, &result); + + CHECK(result == Approx(55.0)); + } +} From 36546a5c0a83a042bbdd3e5f2eaff83465ca0f26 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 21 Aug 2024 13:23:19 +0000 Subject: [PATCH 210/227] update docstring --- .../tncuda/measurements/MeasurementsTNCuda.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp index 6ca7f2283e..e7234367bc 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/MeasurementsTNCuda.hpp @@ -108,16 +108,16 @@ template class MeasurementsTNCuda { d_output_tensor.zeroInit(); - DataBuffer d_output_probs( - length, tensor_network_.getDevTag(), true); - tensor_network_.get_state_tensor(d_output_tensor.getData(), d_output_tensor.getLength(), wires, numHyperSamples); - // `7` here means `256` elements to be calculated + // `10` here means `1024` elements to be calculated // LCOV_EXCL_START - if (wires.size() > 7) { + if (wires.size() > 10) { + DataBuffer d_output_probs( + length, tensor_network_.getDevTag(), true); + getProbs_CUDA(d_output_tensor.getData(), d_output_probs.getData(), length, static_cast(thread_per_block), tensor_network_.getDevTag().getStreamID()); @@ -139,6 +139,10 @@ template class MeasurementsTNCuda { d_output_probs.CopyGpuDataToHost(h_res.data(), h_res.size()); } else { // LCOV_EXCL_STOP + // This branch dispatches the calculation to the CPU for a small + // number of wires. The CPU calculation is faster than the GPU + // calculation for a small number of wires due to the overhead of + // the GPU kernel launch. std::vector h_state_vector(length); d_output_tensor.CopyGpuDataToHost(h_state_vector.data(), h_state_vector.size()); From 882cc775ff8ce771b5219ded0b43f323598e3dc1 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 21 Aug 2024 13:23:42 +0000 Subject: [PATCH 211/227] Auto update version from '0.38.0-dev39' to '0.38.0-dev40' --- 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 b4c1ef4399..d6ffb292ae 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.38.0-dev39" +__version__ = "0.38.0-dev40" From 145c6d731df443d5cfb9c532948945d50f3c1a37 Mon Sep 17 00:00:00 2001 From: Ali Asadi <10773383+maliasadi@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:33:14 -0400 Subject: [PATCH 212/227] Update generate_samples in LK and LGPU to support qml.measurements.Shots (#839) **Context:** PR https://github.com/PennyLaneAI/pennylane/pull/6046 wraps the legacy device API automatically in various device creation, qnode, and execute functions. As LK and LGPU plugins still rely on the legacy device API, the shots tests and the `generate_samples` logic in `lightning_kokkos.py` and `lightning_gpu.py` should be updated to adhere the new convention. **Related Shortcut Stories:** [sc-65998] --------- Co-authored-by: ringo-but-quantum Co-authored-by: Shiro-Raven Co-authored-by: albi3ro --- .github/CHANGELOG.md | 5 +- pennylane_lightning/core/_version.py | 2 +- .../lightning_gpu/lightning_gpu.py | 7 +- .../lightning_kokkos/lightning_kokkos.py | 3 + .../test_measurements_samples_MCMC.py | 21 +--- .../lightning_tensor/test_tensornet_class.py | 4 +- tests/test_adjoint_jacobian.py | 17 ++- tests/test_apply.py | 101 ++++-------------- tests/test_expval.py | 90 +++------------- tests/test_gates.py | 2 +- tests/test_measurements.py | 26 ++--- tests/test_native_mcm.py | 3 +- tests/test_templates.py | 4 +- tests/test_var.py | 35 ++---- 14 files changed, 82 insertions(+), 238 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index ec738851d1..bb485719ca 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -32,6 +32,9 @@ * Multiple calls to the `append_mps_final_state()` API is allowed in `lightning.tensor`. [(#830)](https://github.com/PennyLaneAI/pennylane-lightning/pull/830) + +* Update `generate_samples` in `LightningKokkos` and `LightningGPU` to support `qml.measurements.Shots` type instances. + [(#839)](https://github.com/PennyLaneAI/pennylane-lightning/pull/839) * LightningQubit gains native support for the `PauliRot` gate. [(#834)](https://github.com/PennyLaneAI/pennylane-lightning/pull/834) @@ -142,7 +145,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Astral Cai, Amintor Dusko, Vincent Michaud-Rioux, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Raul Torres, Paul Haochen Wang +Ali Asadi, Astral Cai, Ahmed Darwish, Amintor Dusko, Vincent Michaud-Rioux, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Shuli Shu, Raul Torres, Paul Haochen Wang --- diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index d6ffb292ae..b4c1ef4399 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.38.0-dev40" +__version__ = "0.38.0-dev39" diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index af05d868fc..117e9840de 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -38,7 +38,6 @@ from pennylane_lightning.core.lightning_base import LightningBase try: - from pennylane_lightning.lightning_gpu_ops import ( DevPool, MeasurementsC64, @@ -818,9 +817,9 @@ def generate_samples(self): array[int]: array of samples in binary representation with shape ``(dev.shots, dev.num_wires)`` """ - return self.measurements.generate_samples(len(self.wires), self.shots).astype( - int, copy=False - ) + shots = self.shots if isinstance(self.shots, int) else self.shots.total_shots + + return self.measurements.generate_samples(len(self.wires), shots).astype(int, copy=False) # pylint: disable=protected-access def expval(self, observable, shot_range=None, bin_size=None): diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 6fea7c1628..5ea499702a 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -614,6 +614,9 @@ def generate_samples(self, shots=None): ``(dev.shots, dev.num_wires)`` """ shots = self.shots if shots is None else shots + + shots = shots.total_shots if isinstance(shots, qml.measurements.Shots) else shots + measure = ( MeasurementsC64(self._kokkos_state) if self.use_csingle diff --git a/tests/lightning_qubit/test_measurements_samples_MCMC.py b/tests/lightning_qubit/test_measurements_samples_MCMC.py index 562c705dbe..fd49f84d8f 100644 --- a/tests/lightning_qubit/test_measurements_samples_MCMC.py +++ b/tests/lightning_qubit/test_measurements_samples_MCMC.py @@ -46,15 +46,8 @@ def test_mcmc_sample_dimensions(self, dev, num_shots, measured_wires, operation, the correct dimensions """ ops = [qml.RX(1.5708, wires=[0]), qml.RX(1.5708, wires=[1])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=operation)], shots=num_shots) - s1 = dev.execute(tape) - else: - dev.apply(ops) - dev.shots = num_shots - dev._wires_measured = measured_wires - dev._samples = dev.generate_samples() - s1 = dev.sample(operation) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=operation)], shots=num_shots) + s1 = dev.execute(tape) assert np.array_equal(s1.shape, (shape,)) @@ -67,14 +60,8 @@ def test_sample_values(self, tol, kernel): device_name, wires=2, shots=1000, mcmc=True, kernel_name=kernel, num_burnin=100 ) ops = [qml.RX(1.5708, wires=[0])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=qml.PauliZ(0))], shots=1000) - s1 = dev.execute(tape) - else: - dev.apply([qml.RX(1.5708, wires=[0])]) - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - s1 = dev.sample(qml.PauliZ(0)) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=qml.PauliZ(0))], shots=1000) + s1 = dev.execute(tape) # s1 should only contain 1 and -1, which is guaranteed if # they square to 1 diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index e25e5336b1..c5af8a4af2 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -21,7 +21,6 @@ import pennylane as qml import pytest from conftest import LightningDevice, device_name # tested device -from pennylane import DeviceError from pennylane.wires import Wires if device_name != "lightning.tensor": @@ -88,6 +87,7 @@ def test_errors_apply_operation_state_preparation(operation, par): tensornet = LightningTensorNet(wires, bondDims) with pytest.raises( - DeviceError, match="lightning.tensor does not support initialization with a state vector." + qml.DeviceError, + match="lightning.tensor does not support initialization with a state vector.", ): tensornet.apply_operations([operation(np.array(par), Wires(range(wires)))]) diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index b2cd0da685..5d5a9115b1 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -700,13 +700,13 @@ def dev(self, request): return qml.device(device_name, wires=2, c_dtype=request.param) @pytest.mark.skipif(ld._new_API, reason="Old API required") - def test_finite_shots_warning(self): - """Tests that a warning is raised when computing the adjoint diff on a device with finite shots""" + def test_finite_shots_error(self): + """Tests that an error is raised when computing the adjoint diff on a device with finite shots""" dev = qml.device(device_name, wires=1, shots=1) - with pytest.warns( - UserWarning, match="Requested adjoint differentiation to be computed with finite shots." + with pytest.raises( + qml.QuantumFunctionError, match="does not support adjoint with requested circuit." ): @qml.qnode(dev, diff_method="adjoint") @@ -714,9 +714,6 @@ def circ(x): qml.RX(x, wires=0) return qml.expval(qml.PauliZ(0)) - with pytest.warns( - UserWarning, match="Requested adjoint differentiation to be computed with finite shots." - ): qml.grad(circ)(0.1) def test_qnode(self, mocker, dev): @@ -741,7 +738,7 @@ def circuit(x, y, z): spy = ( mocker.spy(dev, "execute_and_compute_derivatives") if ld._new_API - else mocker.spy(dev, "adjoint_jacobian") + else mocker.spy(dev.target_device, "adjoint_jacobian") ) tol, h = get_tolerance_and_stepsize(dev, step_size=True) @@ -926,7 +923,7 @@ def cost(p1, p2): if ld._new_API: spy = mocker.spy(dev, "execute_and_compute_derivatives") else: - spy = mocker.spy(dev, "adjoint_jacobian") + spy = mocker.spy(dev.target_device, "adjoint_jacobian") # analytic gradient grad_fn = qml.grad(cost) @@ -968,7 +965,7 @@ def circuit(params): spy_analytic = ( mocker.spy(dev, "execute_and_compute_derivatives") if ld._new_API - else mocker.spy(dev, "adjoint_jacobian") + else mocker.spy(dev.target_device, "adjoint_jacobian") ) tol, h = get_tolerance_and_stepsize(dev, step_size=True) diff --git a/tests/test_apply.py b/tests/test_apply.py index f13df70fa1..7cecbd550d 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -566,13 +566,8 @@ def test_expval_single_wire_no_parameters( dev = qubit_device(wires=1) obs = operation(wires=[0]) ops = [stateprep(np.array(input), wires=[0])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) - res = dev.execute(tape) - else: - dev.reset() - dev.apply(ops, obs.diagonalizing_gates()) - res = dev.expval(obs) + tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) + res = dev.execute(tape) assert np.isclose(res, expected_output, atol=tol, rtol=0) @@ -630,13 +625,8 @@ def test_var_single_wire_no_parameters( dev = qubit_device(wires=1) obs = operation(wires=[0]) ops = [stateprep(np.array(input), wires=[0])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) - res = dev.execute(tape) - else: - dev.reset() - dev.apply(ops, obs.diagonalizing_gates()) - res = dev.var(obs) + tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) + res = dev.execute(tape) assert np.isclose(res, expected_output, atol=tol, rtol=0) @@ -680,42 +670,22 @@ def test_sample_dimensions(self, qubit_device): shots = 10 obs = qml.PauliZ(wires=[0]) - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) - s1 = dev.execute(tape) - else: - dev.reset() - dev.apply(ops) - dev.shots = shots - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - s1 = dev.sample(obs) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) + s1 = dev.execute(tape) + assert np.array_equal(s1.shape, (shots,)) shots = 12 obs = qml.PauliZ(wires=[1]) - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) - s2 = dev.execute(tape) - else: - dev.reset() - dev.shots = shots - dev._wires_measured = {1} - dev._samples = dev.generate_samples() - s2 = dev.sample(qml.PauliZ(wires=[1])) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) + s2 = dev.execute(tape) assert np.array_equal(s2.shape, (shots,)) shots = 17 obs = qml.PauliX(0) @ qml.PauliZ(1) - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) - s3 = dev.execute(tape) - else: - dev.reset() - dev.shots = shots - dev._wires_measured = {0, 1} - dev._samples = dev.generate_samples() - s3 = dev.sample(qml.PauliZ(wires=[1])) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) + s3 = dev.execute(tape) + assert np.array_equal(s3.shape, (shots,)) def test_sample_values(self, qubit_device, tol): @@ -730,18 +700,10 @@ def test_sample_values(self, qubit_device, tol): ops = [qml.RX(1.5708, wires=[0])] - shots = 1000 + shots = qml.measurements.Shots(1000) obs = qml.PauliZ(0) - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) - s1 = dev.execute(tape) - else: - dev.reset() - dev.apply(ops) - dev.shots = shots - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - s1 = dev.sample(obs) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) + s1 = dev.execute(tape) # s1 should only contain 1 and -1, which is guaranteed if # they square to 1 @@ -756,13 +718,8 @@ def test_load_default_qubit_device(self): """Test that the default plugin loads correctly""" dev = qml.device(device_name, wires=2) - if dev._new_API: - assert not dev.shots - assert len(dev.wires) == 2 - else: - assert dev.shots is None - assert dev.num_wires == 2 - assert dev.short_name == device_name + assert not dev.shots + assert len(dev.wires) == 2 @pytest.mark.xfail(ld._new_API, reason="Old device API required.") def test_no_backprop(self): @@ -1276,14 +1233,10 @@ def test_multi_samples_return_correlated_results(self, qubit_device): def circuit(): qml.Hadamard(0) qml.CNOT(wires=[0, 1]) - if ld._new_API: - return qml.sample(wires=[0, 1]) - else: - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) + return qml.sample(wires=[0, 1]) outcomes = circuit() - if ld._new_API: - outcomes = outcomes.T + outcomes = outcomes.T assert np.array_equal(outcomes[0], outcomes[1]) @@ -1305,14 +1258,10 @@ def test_multi_samples_return_correlated_results_more_wires_than_size_of_observa def circuit(): qml.Hadamard(0) qml.CNOT(wires=[0, 1]) - if ld._new_API: - return qml.sample(wires=[0, 1]) - else: - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) + return qml.sample(wires=[0, 1]) outcomes = circuit() - if ld._new_API: - outcomes = outcomes.T + outcomes = outcomes.T assert np.array_equal(outcomes[0], outcomes[1]) @@ -1350,14 +1299,10 @@ def circuit(): qml.Snapshot() qml.adjoint(qml.Snapshot()) qml.CNOT(wires=[0, 1]) - if ld._new_API: - return qml.sample(wires=[0, 1]) - else: - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) + return qml.sample(wires=[0, 1]) outcomes = circuit() - if ld._new_API: - outcomes = outcomes.T + outcomes = outcomes.T assert np.array_equal(outcomes[0], outcomes[1]) diff --git a/tests/test_expval.py b/tests/test_expval.py index f40f644123..87c65bbb0b 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -38,15 +38,8 @@ def test_identity_expectation(self, theta, phi, qubit_device, tol): O1 = qml.Identity(wires=[0]) O2 = qml.Identity(wires=[1]) ops = [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) - res = dev.execute(tape) - else: - dev.apply( - ops, - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - res = np.array([dev.expval(O1), dev.expval(O2)]) + tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) + res = dev.execute(tape) assert np.allclose(res, np.array([1, 1]), tol) def test_pauliz_expectation(self, theta, phi, qubit_device, tol): @@ -56,16 +49,8 @@ def test_pauliz_expectation(self, theta, phi, qubit_device, tol): O1 = qml.PauliZ(wires=[0]) O2 = qml.PauliZ(wires=[1]) ops = [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) - res = dev.execute(tape) - else: - dev.apply( - ops, - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) - - res = np.array([dev.expval(O1), dev.expval(O2)]) + tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) + res = dev.execute(tape) assert np.allclose(res, np.array([np.cos(theta), np.cos(theta) * np.cos(phi)]), tol) def test_paulix_expectation(self, theta, phi, qubit_device, tol): @@ -75,17 +60,9 @@ def test_paulix_expectation(self, theta, phi, qubit_device, tol): O1 = qml.PauliX(wires=[0]) O2 = qml.PauliX(wires=[1]) ops = [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) - res = dev.execute(tape) + tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) + res = dev.execute(tape) - else: - dev.apply( - ops, - 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.dtype), @@ -99,17 +76,9 @@ def test_pauliy_expectation(self, theta, phi, qubit_device, tol): O1 = qml.PauliY(wires=[0]) O2 = qml.PauliY(wires=[1]) ops = [qml.RX(theta, wires=[0]), qml.RX(phi, wires=[1]), qml.CNOT(wires=[0, 1])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) - res = dev.execute(tape) - - else: - dev.apply( - ops, - rotations=[*O1.diagonalizing_gates(), *O2.diagonalizing_gates()], - ) + tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) + res = dev.execute(tape) - 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): @@ -119,17 +88,9 @@ def test_hadamard_expectation(self, theta, phi, qubit_device, tol): O1 = qml.Hadamard(wires=[0]) O2 = qml.Hadamard(wires=[1]) ops = [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) - res = dev.execute(tape) + tape = qml.tape.QuantumScript(ops, [qml.expval(O1), qml.expval(O2)]) + res = dev.execute(tape) - else: - dev.apply( - ops, - 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) @@ -325,12 +286,8 @@ def test_paulix_pauliy(self, theta, phi, varphi, qubit_device, tol): qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 2]), ] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) - res = dev.execute(tape) - else: - dev.apply(ops, rotations=obs.diagonalizing_gates()) - res = dev.expval(obs) + tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) + res = dev.execute(tape) expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) @@ -348,16 +305,8 @@ def test_pauliz_identity(self, theta, phi, varphi, qubit_device, tol): qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 2]), ] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) - res = dev.execute(tape) - else: - dev.apply( - ops, - rotations=obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) + tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) + res = dev.execute(tape) expected = np.cos(varphi) * np.cos(phi) @@ -375,15 +324,8 @@ def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, qubit_device, tol): qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 2]), ] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) - res = dev.execute(tape) - else: - dev.apply( - ops, - rotations=obs.diagonalizing_gates(), - ) - res = dev.expval(obs) + tape = qml.tape.QuantumScript(ops, [qml.expval(op=obs)]) + res = dev.execute(tape) expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) assert np.allclose(res, expected, tol) diff --git a/tests/test_gates.py b/tests/test_gates.py index 36893a056c..fa120b820c 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -380,7 +380,7 @@ def test_state_prep(n_targets, tol): [qml.state()], ) ref = dq.execute([tape])[0] - res = dev.execute([tape])[0] if ld._new_API else dev.execute(tape) + res = dev.execute([tape])[0] assert np.allclose(res.ravel(), ref.ravel(), tol) diff --git a/tests/test_measurements.py b/tests/test_measurements.py index e2c7d0bf2f..0fdb3fafa3 100644 --- a/tests/test_measurements.py +++ b/tests/test_measurements.py @@ -389,7 +389,7 @@ def circuit(): qml.RX(0.52, wires=0) return qml.expval(qml.RX(0.742, wires=[0])) - with pytest.raises(qml._device.DeviceError, match="Observable RX.*not supported"): + with pytest.raises(qml.DeviceError, match="Observable RX.*not supported"): circuit() def test_observable_return_type_is_expectation(self, dev): @@ -490,7 +490,7 @@ def circuit(): qml.RX(0.52, wires=0) return qml.var(qml.RX(0.742, wires=[0])) - with pytest.raises(qml._device.DeviceError, match="Observable RX.*not supported"): + with pytest.raises(qml.DeviceError, match="Observable RX.*not supported"): circuit() def test_observable_return_type_is_variance(self, dev): @@ -519,7 +519,7 @@ def circuit(): qml.RX(0.52, wires=0) return qml.var(qml.RX(0.742, wires=[0])) - with pytest.raises(qml._device.DeviceError, match="Observable RX.*not supported"): + with pytest.raises(qml.DeviceError, match="Observable RX.*not supported"): circuit() @@ -647,14 +647,8 @@ def test_sample_dimensions(self, qubit_device, shots, wires): dev = qubit_device(wires=2, shots=shots) ops = [qml.RX(1.5708, wires=[0]), qml.RX(1.5708, wires=[1])] obs = qml.PauliZ(wires=[0]) - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) - s1 = dev.execute(tape) - else: - dev.apply(ops) - dev._wires_measured = wires - dev._samples = dev.generate_samples() - s1 = dev.sample(obs) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) + s1 = dev.execute(tape) assert np.array_equal(s1.shape, (shots,)) def test_sample_values(self, qubit_device, tol): @@ -665,14 +659,8 @@ def test_sample_values(self, qubit_device, tol): dev = qubit_device(wires=2, shots=shots) ops = [qml.RX(1.5708, wires=[0])] obs = qml.PauliZ(0) - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) - s1 = dev.execute(tape) - else: - dev.apply(ops) - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - s1 = dev.sample(qml.PauliZ(0)) + tape = qml.tape.QuantumScript(ops, [qml.sample(op=obs)], shots=shots) + s1 = dev.execute(tape) # s1 should only contain 1 and -1, which is guaranteed if # they square to 1 diff --git a/tests/test_native_mcm.py b/tests/test_native_mcm.py index f7b9c030fc..4ca3b66b74 100644 --- a/tests/test_native_mcm.py +++ b/tests/test_native_mcm.py @@ -20,7 +20,6 @@ import pytest from conftest import LightningDevice, device_name, validate_measurements from flaky import flaky -from pennylane._device import DeviceError if device_name not in ("lightning.qubit", "lightning.kokkos"): pytest.skip("Native MCM not supported. Skipping.", allow_module_level=True) @@ -86,7 +85,7 @@ def func(x, y): if device_name == "lightning.qubit": with pytest.raises( - DeviceError, + qml.DeviceError, match=f"not accepted with finite shots on lightning.qubit", ): func(*params) diff --git a/tests/test_templates.py b/tests/test_templates.py index 32952aef28..3f242d7af5 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -174,7 +174,7 @@ def circuit(feature_vector): X = np.arange(1, n_qubits + 1) - with pytest.raises(qml._device.DeviceError, match="not supported"): + with pytest.raises(qml.DeviceError, match="not supported"): _ = qml.QNode(circuit, dev, diff_method=None)(X) @@ -240,7 +240,7 @@ def circuit(weights): shapes = qml.CVNeuralNetLayers.shape(n_layers=2, n_wires=n_qubits) weights = [np.random.random(shape) for shape in shapes] - with pytest.raises(qml._device.DeviceError, match="not supported"): + with pytest.raises(qml.DeviceError, match="not supported"): _ = qml.QNode(circuit, dev, diff_method=None)(weights) diff --git a/tests/test_var.py b/tests/test_var.py index 16b7ee1f3e..f2675fa2dc 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -42,15 +42,10 @@ def test_var(self, theta, phi, qubit_device, tol): qml.RX(phi, wires=[0]), qml.RY(theta, wires=[0]), ] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) - var = dev.execute(tape) - else: - dev.apply( - ops, - rotations=[*obs.diagonalizing_gates()], - ) - var = dev.var(obs) + + tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) + var = dev.execute(tape) + expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta) ** 2 * np.cos(2 * phi)) assert np.allclose(var, expected, tol) @@ -99,15 +94,8 @@ def test_paulix_pauliy(self, theta, phi, varphi, qubit_device, tol): qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 2]), ] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) - res = dev.execute(tape) - else: - dev.apply( - ops, - rotations=obs.diagonalizing_gates(), - ) - res = dev.var(obs) + tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) + res = dev.execute(tape) expected = ( 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 @@ -131,15 +119,8 @@ def test_pauliz_hadamard_pauliy(self, theta, phi, varphi, qubit_device, tol): qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 2]), ] - if ld._new_API: - tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) - res = dev.execute(tape) - else: - dev.apply( - ops, - rotations=obs.diagonalizing_gates(), - ) - res = dev.var(obs) + tape = qml.tape.QuantumScript(ops, [qml.var(op=obs)]) + res = dev.execute(tape) expected = ( 3 From bce32f8b418b57b605c79be87e522e98b87f1e27 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 21 Aug 2024 13:26:07 +0000 Subject: [PATCH 213/227] Auto update version from '0.38.0-dev39' to '0.38.0-dev40' --- 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 b4c1ef4399..d6ffb292ae 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.38.0-dev39" +__version__ = "0.38.0-dev40" From 6308d6dc9115dc6a5c18b4af03e61629cacad94b Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 21 Aug 2024 14:22:31 +0000 Subject: [PATCH 214/227] Auto update version from '0.38.0-dev40' to '0.38.0-dev41' --- 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 d6ffb292ae..a8ba109987 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.38.0-dev40" +__version__ = "0.38.0-dev41" From 2de2f2647a8c78151a75103a04ff1950e780d208 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 21 Aug 2024 14:26:43 +0000 Subject: [PATCH 215/227] fix codefactor complains --- pennylane_lightning/lightning_tensor/_tensornet.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index a91debc13a..1e9323edfe 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -42,7 +42,7 @@ def svd_split(M, bond_dim): # keep only chi bonds chi = np.min([bonds, bond_dim]) U, S, Vd = U[:, :, :chi], S[:chi], Vd[:chi] - return U, S, Vd + return U, Vd def dense_to_mps(psi, n_wires, bond_dim): @@ -50,7 +50,7 @@ def dense_to_mps(psi, n_wires, bond_dim): Ms = [] psi = np.reshape(psi, (2, -1)) # split psi[2, 2, 2, 2..] = psi[2, (2x2x2...)] - U, S, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] + U, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] Vd[mu, (2x2x2x..)] Ms.append(U) bondL = Vd.shape[0] @@ -58,7 +58,7 @@ def dense_to_mps(psi, n_wires, bond_dim): for _ in range(n_wires - 2): psi = np.reshape(psi, (2 * bondL, -1)) # reshape psi[2 * bondL, (2x2x2...)] - U, S, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] S[mu] Vd[mu, (2x2x2x..)] + U, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] Vd[mu, (2x2x2x..)] Ms.append(U) psi = Vd @@ -182,8 +182,8 @@ def _preprocess_state_vector(self, state, device_wires): # get full state vector to be factorized into MPS full_state = np.zeros(2**self._num_wires, dtype=self.dtype) - for i in range(len(state)): - full_state[ravelled_indices[i]] = state[i] + for i, value in enumerate(state): + full_state[ravelled_indices[i]] = value return np.reshape(full_state, output_shape).ravel(order="C") def _apply_state_vector(self, state, device_wires: Wires): From 285e1c995b18d20c105a7fdc0a1ab94acf3bfe7e Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 21 Aug 2024 17:16:15 +0000 Subject: [PATCH 216/227] apply Vincent's comments --- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 21 ++++++++----------- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 12 +++++------ .../tncuda/tests/Tests_MPSTNCuda.cpp | 12 +++++------ .../lightning_tensor/_tensornet.py | 2 +- .../lightning_tensor/lightning_tensor.py | 1 - tests/new_api/test_device.py | 2 +- tests/test_expval.py | 12 +++++------ tests/test_var.py | 12 +++++------ 8 files changed, 35 insertions(+), 39 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 10166f4e09..42f4de459b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -90,7 +90,7 @@ class MPSTNCuda final : public TNCudaBase> { sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); - setZeroState(); + reset(); appendInitialMPSState_(); } @@ -103,7 +103,7 @@ class MPSTNCuda final : public TNCudaBase> { sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); - setZeroState(); + reset(); appendInitialMPSState_(); } @@ -169,19 +169,15 @@ class MPSTNCuda final : public TNCudaBase> { } /** - * @brief Set the quantum state to the zero state. - */ - void setZeroState() { reset(); } - - /** - * @brief Update the ith MPS site. + * @brief Update the ith MPS site data. * * @param site_idx Index of the MPS site. * @param host_data Pointer to the data on host. * @param host_data_size Length of the data. */ - void updateIthMPSSite(const std::size_t site_idx, const ComplexT *host_data, - std::size_t host_data_size) { + void updateIthMPSSiteData(const std::size_t site_idx, + const ComplexT *host_data, + std::size_t host_data_size) { PL_ABORT_IF_NOT( site_idx < BaseType::getNumQubits(), "The site index should be less than the number of qubits."); @@ -346,11 +342,12 @@ class MPSTNCuda final : public TNCudaBase> { std::vector localBondDims(BaseType::getNumQubits() - 1, maxBondDim_); + const std::size_t ubDim = log2(maxBondDim_); for (std::size_t i = 0; i < localBondDims.size(); i++) { - std::size_t bondDim = + const std::size_t bondDim = std::min(i + 1, BaseType::getNumQubits() - i - 1); - if (bondDim <= log2(maxBondDim_)) { + if (bondDim <= ubDim) { localBondDims[i] = std::size_t{1} << bondDim; } } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index 9094f53e39..fb56c54006 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -75,14 +75,14 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { }, "Copy StateVector data into a Numpy array.") .def( - "updateMPSSites", - [](TensorNet &tensor_network, std::vector &sites) { - for (std::size_t idx = 0; idx < sites.size(); idx++) { - py::buffer_info numpyArrayInfo = sites[idx].request(); + "updateMPSSitesData", + [](TensorNet &tensor_network, std::vector &tensors) { + for (std::size_t idx = 0; idx < tensors.size(); idx++) { + py::buffer_info numpyArrayInfo = tensors[idx].request(); auto *data_ptr = static_cast *>( numpyArrayInfo.ptr); - tensor_network.updateIthMPSSite(idx, data_ptr, - sites[idx].size()); + tensor_network.updateIthMPSSiteData(idx, data_ptr, + tensors[idx].size()); } }, "Pass MPS site data to the C++ backend") diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index f1795a011d..a3867e0ca4 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -69,8 +69,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { std::vector> site_data(1, {0.0, 0.0}); REQUIRE_THROWS_WITH( - mps_state.updateIthMPSSite(siteIdx, site_data.data(), - site_data.size()), + mps_state.updateIthMPSSiteData(siteIdx, site_data.data(), + site_data.size()), Catch::Matchers::Contains( "The site index should be less than the number of qubits.")); } @@ -85,8 +85,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { std::vector> site_data(1, {0.0, 0.0}); REQUIRE_THROWS_WITH( - mps_state.updateIthMPSSite(siteIdx, site_data.data(), - site_data.size()), + mps_state.updateIthMPSSiteData(siteIdx, site_data.data(), + site_data.size()), Catch::Matchers::Contains("The length of the host data should " "match its copy on the device.")); } @@ -105,8 +105,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { site0_data[2] = {1.0, 0.0}; site1_data[1] = {1.0, 0.0}; - mps_state.updateIthMPSSite(0, site0_data.data(), site0_data.size()); - mps_state.updateIthMPSSite(1, site1_data.data(), site1_data.size()); + mps_state.updateIthMPSSiteData(0, site0_data.data(), site0_data.size()); + mps_state.updateIthMPSSiteData(1, site1_data.data(), site1_data.size()); auto results = mps_state.getDataVector(); diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 1e9323edfe..e99846cdb9 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -198,7 +198,7 @@ def _apply_state_vector(self, state, device_wires: Wires): M = dense_to_mps(state, self._num_wires, self._max_bond_dim) - self._tensornet.updateMPSSites(M) + self._tensornet.updateMPSSitesData(M) def _apply_basis_state(self, state, wires): """Initialize the quantum state in a specified computational basis state. diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index df2200c74d..2029b20faa 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -125,7 +125,6 @@ "PauliX", "PauliY", "PauliZ", - "Projector", "Hadamard", "Hermitian", "Identity", diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index 3d78dffd21..d491d8eedd 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -84,7 +84,7 @@ def test_accepted_observables(self): is supported by the device.""" valid_obs = qml.Projector([0], 0) invalid_obs = self.DummyOperator(0) - result = True + result = True if device_name != "lightning.tensor" else False assert accepted_observables(valid_obs) is result assert accepted_observables(invalid_obs) is False diff --git a/tests/test_expval.py b/tests/test_expval.py index 97dbac1c9c..b07ac4a8e2 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -96,6 +96,10 @@ def test_hadamard_expectation(self, theta, phi, qubit_device, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) + @pytest.mark.skipif( + device_name == "lightning.tensor", + reason="lightning.tensor does not support qml.Projector()", + ) def test_projector_expectation(self, theta, phi, qubit_device, tol): """Test that Projector variance value is correct""" n_qubits = 2 @@ -106,12 +110,8 @@ def test_projector_expectation(self, theta, phi, qubit_device, tol): pytest.skip("Device does not support the Projector observable.") init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) - init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) - obs = ( - qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) - if device_name != "lightning.tensor" - else qml.Projector(np.array([0, 1]) / np.sqrt(2), wires=[0]) - ) + init_state /= np.linalg.norm(init_state) + obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) def circuit(): qml.StatePrep(init_state, wires=range(n_qubits)) diff --git a/tests/test_var.py b/tests/test_var.py index 2bfedd640f..f2675fa2dc 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -50,6 +50,10 @@ def test_var(self, theta, phi, qubit_device, tol): assert np.allclose(var, expected, tol) + pytest.mark.skipif( + device_name == "lightning.tensor", reason="lightning.tensor doesn't support projector." + ) + def test_projector_var(self, theta, phi, qubit_device, tol): """Test that Projector variance value is correct""" n_qubits = 2 @@ -60,12 +64,8 @@ def test_projector_var(self, theta, phi, qubit_device, tol): pytest.skip("Device does not support the Projector observable.") init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) - init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) - obs = ( - qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) - if device_name != "lightning.tensor" - else qml.Projector(np.array([0, 1]) / np.sqrt(2), wires=[1]) - ) + init_state /= np.linalg.norm(init_state) + obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) def circuit(): qml.StatePrep(init_state, wires=range(n_qubits)) From 6a926810689a527f8de2ca38b4c920ec181165a4 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 21 Aug 2024 20:08:07 +0000 Subject: [PATCH 217/227] apply Ali's comments --- .../simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 6 +++--- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 6 +++--- .../tncuda/tests/Tests_MPSTNCuda.cpp | 12 ++++++------ pennylane_lightning/lightning_tensor/_tensornet.py | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index 42f4de459b..178d987a10 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -175,9 +175,9 @@ class MPSTNCuda final : public TNCudaBase> { * @param host_data Pointer to the data on host. * @param host_data_size Length of the data. */ - void updateIthMPSSiteData(const std::size_t site_idx, - const ComplexT *host_data, - std::size_t host_data_size) { + void updateMPSSiteData(const std::size_t site_idx, + const ComplexT *host_data, + std::size_t host_data_size) { PL_ABORT_IF_NOT( site_idx < BaseType::getNumQubits(), "The site index should be less than the number of qubits."); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index fb56c54006..aee4834a72 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -81,11 +81,11 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { py::buffer_info numpyArrayInfo = tensors[idx].request(); auto *data_ptr = static_cast *>( numpyArrayInfo.ptr); - tensor_network.updateIthMPSSiteData(idx, data_ptr, - tensors[idx].size()); + tensor_network.updateMPSSiteData(idx, data_ptr, + tensors[idx].size()); } }, - "Pass MPS site data to the C++ backend") + "Pass MPS site data to the C++ backend.") .def( "setBasisState", [](TensorNet &tensor_network, diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index a3867e0ca4..1cea281878 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -69,8 +69,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { std::vector> site_data(1, {0.0, 0.0}); REQUIRE_THROWS_WITH( - mps_state.updateIthMPSSiteData(siteIdx, site_data.data(), - site_data.size()), + mps_state.updateMPSSiteData(siteIdx, site_data.data(), + site_data.size()), Catch::Matchers::Contains( "The site index should be less than the number of qubits.")); } @@ -85,8 +85,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { std::vector> site_data(1, {0.0, 0.0}); REQUIRE_THROWS_WITH( - mps_state.updateIthMPSSiteData(siteIdx, site_data.data(), - site_data.size()), + mps_state.updateMPSSiteData(siteIdx, site_data.data(), + site_data.size()), Catch::Matchers::Contains("The length of the host data should " "match its copy on the device.")); } @@ -105,8 +105,8 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { site0_data[2] = {1.0, 0.0}; site1_data[1] = {1.0, 0.0}; - mps_state.updateIthMPSSiteData(0, site0_data.data(), site0_data.size()); - mps_state.updateIthMPSSiteData(1, site1_data.data(), site1_data.size()); + mps_state.updateMPSSiteData(0, site0_data.data(), site0_data.size()); + mps_state.updateMPSSiteData(1, site1_data.data(), site1_data.size()); auto results = mps_state.getDataVector(); diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index e99846cdb9..74ed4906e6 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -156,11 +156,11 @@ def _preprocess_state_vector(self, state, device_wires): """Convert a specified state to a full internal state vector. Args: - state (array[complex]): normalized input state of length ``2**len(wires)`` + state (array[complex]): normalized input state of length ``2**len(device_wires)`` device_wires (Wires): wires that get initialized in the state Returns: - array[complex]: normalized input state of length ``2**len(wires)`` + array[complex]: normalized input state of length ``2**len(device_wires)`` """ output_shape = [2] * self._num_wires # special case for integral types @@ -189,8 +189,8 @@ def _preprocess_state_vector(self, state, device_wires): def _apply_state_vector(self, state, device_wires: Wires): """Convert a specified state to MPS sites. Args: - state (array[complex]): normalized input state of length ``2**len(wires)`` - or broadcasted state of shape ``(batch_size, 2**len(wires))`` + state (array[complex]): normalized input state of length ``2**len(device_wires)`` + or broadcasted state of shape ``(batch_size, 2**len(device_wires))`` device_wires (Wires): wires that get initialized in the state """ From 0275d684eb58de4ceb11d1d5ef032fe5929de4e5 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 21 Aug 2024 20:08:29 +0000 Subject: [PATCH 218/227] Auto update version from '0.38.0-dev41' to '0.38.0-dev42' --- 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 a8ba109987..f68075d103 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.38.0-dev41" +__version__ = "0.38.0-dev42" From 4d5b690cbf7844775c65e483b858e682259cfa76 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 21 Aug 2024 20:18:48 +0000 Subject: [PATCH 219/227] pre-allocate Ms --- pennylane_lightning/lightning_tensor/_tensornet.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 74ed4906e6..226861f7ed 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -47,24 +47,24 @@ def svd_split(M, bond_dim): def dense_to_mps(psi, n_wires, bond_dim): """Convert a dense state vector to a matrix product state.""" - Ms = [] + Ms = [[] for _ in range(n_wires)] psi = np.reshape(psi, (2, -1)) # split psi[2, 2, 2, 2..] = psi[2, (2x2x2...)] U, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] Vd[mu, (2x2x2x..)] - Ms.append(U) + Ms[0] = U bondL = Vd.shape[0] psi = Vd - for _ in range(n_wires - 2): + for i in range(1, n_wires - 1): psi = np.reshape(psi, (2 * bondL, -1)) # reshape psi[2 * bondL, (2x2x2...)] U, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] Vd[mu, (2x2x2x..)] - Ms.append(U) + Ms[i] = U psi = Vd bondL = Vd.shape[0] - Ms.append(Vd) + Ms[n_wires - 1] = Vd return Ms From 1be48ebf673ef84e10ed3338c1503e8e4ea4d97d Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Wed, 21 Aug 2024 21:22:35 +0000 Subject: [PATCH 220/227] Trigger CIs From 96e65b22088fd44fabad2baff318a97fc8a7c639 Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 22 Aug 2024 13:10:44 +0000 Subject: [PATCH 221/227] add essential headers to unit tests --- .../core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp index a4201f22d5..6043e505ad 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp @@ -1,4 +1,4 @@ -// Copyright 2018-2023 Xanadu Quantum Technologies Inc. +// Copyright 2018-2024 Xanadu Quantum Technologies Inc. // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include From 07ef802ee27d4435a7b32e3327a2bdffb179b2df Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 22 Aug 2024 13:11:06 +0000 Subject: [PATCH 222/227] Auto update version from '0.38.0-dev42' to '0.38.0-dev43' --- 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 f68075d103..33a207e9fb 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.38.0-dev42" +__version__ = "0.38.0-dev43" From befbb0a9b8c18b53e275f5623bb66632ae4a599e Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Thu, 22 Aug 2024 08:24:44 -0400 Subject: [PATCH 223/227] Bugfix Dockerfile + new build system (#863) Please complete the following checklist when submitting a PR: - [ ] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [ ] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [ ] Ensure that the test suite passes, by running `make test`. - [ ] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [ ] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** **Description of the Change:** **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** --------- Co-authored-by: ringo-but-quantum --- .github/CHANGELOG.md | 3 +++ docker/Dockerfile | 22 +++++++++++----------- pennylane_lightning/core/_version.py | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 0e996e7012..072a5a44ae 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -114,6 +114,9 @@ ### Bug fixes +* Update dependencies and `build` command options following changes in the build system. + [(#863)](https://github.com/PennyLaneAI/pennylane-lightning/pull/863) + * Replace structured bindings by variables in `GateImplementationsLM.hpp`. [(#856)](https://github.com/PennyLaneAI/pennylane-lightning/pull/856) diff --git a/docker/Dockerfile b/docker/Dockerfile index cc38d8506d..a538aba390 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -73,14 +73,14 @@ RUN python3 -m venv $VIRTUAL_ENV ENV PATH="$VIRTUAL_ENV/bin:$PATH" RUN rm -rf tmp && git clone --depth 1 --branch ${LIGHTNING_VERSION} https://github.com/PennyLaneAI/pennylane-lightning.git tmp\ && mv tmp/* /opt/pennylane-lightning && rm -rf tmp -RUN pip install --no-cache-dir cmake ninja pybind11 wheel +RUN pip install --no-cache-dir build cmake ninja pybind11 toml wheel # Download Lightning release and build lightning-qubit backend FROM base-build-python AS build-wheel-lightning-qubit WORKDIR /opt/pennylane-lightning RUN pip uninstall -y pennylane-lightning -RUN python scripts/configure_pyproject_toml.py -RUN python -m build +RUN python scripts/configure_pyproject_toml.py || true +RUN python -m build --wheel # Install lightning-qubit backend FROM base-runtime AS wheel-lightning-qubit @@ -93,8 +93,8 @@ FROM base-build-python AS build-wheel-lightning-kokkos-openmp WORKDIR /opt/pennylane-lightning ENV PL_BACKEND=lightning_kokkos RUN pip uninstall -y pennylane-lightning -RUN python scripts/configure_pyproject_toml.py -RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON" python -m build +RUN python scripts/configure_pyproject_toml.py || true +RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON" python -m build --wheel # Install lightning-kokkos OpenMP backend FROM base-runtime AS wheel-lightning-kokkos-openmp @@ -118,8 +118,8 @@ WORKDIR /opt/pennylane-lightning ENV PL_BACKEND=lightning_kokkos RUN pip uninstall -y pennylane-lightning RUN echo >> cmake/support_kokkos.cmake && echo "find_package(CUDAToolkit REQUIRED)" >> cmake/support_kokkos.cmake -RUN python scripts/configure_pyproject_toml.py -RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON -DKokkos_ENABLE_CUDA:BOOL=ON -DKokkos_ARCH_${CUDA_ARCH}=ON" python -m build +RUN python scripts/configure_pyproject_toml.py || true +RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON -DKokkos_ENABLE_CUDA:BOOL=ON -DKokkos_ARCH_${CUDA_ARCH}=ON" python -m build --wheel # Install python3 and setup runtime virtual env in CUDA-12-runtime image (includes CUDA runtime and math libraries) # Install lightning-kokkos CUDA backend @@ -148,8 +148,8 @@ WORKDIR /opt/pennylane-lightning ENV PL_BACKEND=lightning_gpu RUN pip install --no-cache-dir wheel custatevec-cu12 RUN pip uninstall -y pennylane-lightning -RUN python scripts/configure_pyproject_toml.py -RUN CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") python -m build +RUN python scripts/configure_pyproject_toml.py || true +RUN CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") python -m build --wheel # Install python3 and setup runtime virtual env in CUDA-12-runtime image (includes CUDA runtime and math libraries) @@ -193,8 +193,8 @@ ENV CMAKE_PREFIX_PATH=/opt/rocm:$CMAKE_PREFIX_PATH ENV CXX=hipcc ENV PL_BACKEND=lightning_kokkos RUN pip uninstall -y pennylane-lightning -RUN python scripts/configure_pyproject_toml.py -RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON -DKokkos_ENABLE_HIP:BOOL=ON -DKokkos_ARCH_${AMD_ARCH}=ON" python -m build +RUN python scripts/configure_pyproject_toml.py || true +RUN CMAKE_ARGS="-DKokkos_ENABLE_SERIAL:BOOL=ON -DKokkos_ENABLE_OPENMP:BOOL=ON -DKokkos_ENABLE_HIP:BOOL=ON -DKokkos_ARCH_${AMD_ARCH}=ON" python -m build --wheel # Install lightning-kokkos HIP backend FROM rocm/dev-ubuntu-22.04:5.7 AS wheel-lightning-kokkos-rocm diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 33a207e9fb..f68075d103 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.38.0-dev43" +__version__ = "0.38.0-dev42" From be3fd9ce51f47cd11b84b69bb0dbaa80021f9b9b Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 22 Aug 2024 13:12:38 +0000 Subject: [PATCH 224/227] Auto update version from '0.38.0-dev42' to '0.38.0-dev43' --- 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 f68075d103..33a207e9fb 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.38.0-dev42" +__version__ = "0.38.0-dev43" From 737ca5ba7ca620cee426bcb5962d73fb00d0003c Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 22 Aug 2024 13:14:24 +0000 Subject: [PATCH 225/227] Auto update version from '0.38.0-dev42' to '0.38.0-dev43' --- 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 f68075d103..33a207e9fb 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.38.0-dev42" +__version__ = "0.38.0-dev43" From 8ce797b1218813a4663b3eb11a76de8f17b5f4ba Mon Sep 17 00:00:00 2001 From: Shuli Shu <08cnbj@gmail.com> Date: Thu, 22 Aug 2024 13:18:46 +0000 Subject: [PATCH 226/227] fix typo --- .../core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp index 6043e505ad..95b2299699 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include From 86c1b8292b86b1eddb169e27ad51d83b8a06a10b Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 22 Aug 2024 20:06:39 +0000 Subject: [PATCH 227/227] Auto update version from '0.38.0-dev43' to '0.38.0-dev44' --- 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 33a207e9fb..b7dfacadb0 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.38.0-dev43" +__version__ = "0.38.0-dev44"