Skip to content

Commit 1951544

Browse files
multiphaseCFDringo-but-quantumvincentmrmaliasadimlxd
committed
Add stateprep support to lightning.tensor - MPS (#849)
### Before submitting 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-71278] Add `qml.StatePrep()` and `qml.QubitStateVector()` support to `lightning.tensor`. Note that `svd` decomposition is conduct by `numpy` in the python layer based on the fact that `svd` operation with `numpy` on cpu is faster than `cutensornet` on `A100` GPU if the `bond dimension` is less than `256`. For more info, please visit [here](https://developer.nvidia.com/cuquantum-sdk). **Description of the Change:** **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** --------- Co-authored-by: ringo-but-quantum <[email protected]> Co-authored-by: Vincent Michaud-Rioux <[email protected]> Co-authored-by: Ali Asadi <[email protected]> Co-authored-by: Lee James O'Riordan <[email protected]> Co-authored-by: Josh Izaac <[email protected]> Co-authored-by: Lee J. O'Riordan <[email protected]> Co-authored-by: Pietropaolo Frisoni <[email protected]> Co-authored-by: erick-xanadu <[email protected]> Co-authored-by: Astral Cai <[email protected]> Co-authored-by: Amintor Dusko <[email protected]> Co-authored-by: Shiro-Raven <[email protected]> Co-authored-by: albi3ro <[email protected]>
1 parent fdf9c71 commit 1951544

File tree

16 files changed

+248
-149
lines changed

16 files changed

+248
-149
lines changed

.github/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
### New features since last release
44

5+
* Add `qml.StatePrep()` and `qml.QubitStateVector()` support to `lightning.tensor`.
6+
[(#849)](https://github.com/PennyLaneAI/pennylane-lightning/pull/849)
7+
58
* Add LightningGPU Linux (aarch64+GraceHopper) wheels to PyPI.
69
[(#815)](https://github.com/PennyLaneAI/pennylane-lightning/pull/815)
710

pennylane_lightning/core/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
Version number (major.minor.patch[-label])
1717
"""
1818

19-
__version__ = "0.38.0-dev43"
19+
__version__ = "0.38.0-dev44"

pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp

+63-15
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class MPSTNCuda final : public TNCudaBase<Precision, MPSTNCuda<Precision>> {
6464
MPSStatus MPSInitialized_ = MPSStatus::MPSInitNotSet;
6565

6666
const std::size_t maxBondDim_;
67-
67+
const std::vector<std::size_t> bondDims_;
6868
const std::vector<std::vector<std::size_t>> sitesModes_;
6969
const std::vector<std::vector<std::size_t>> sitesExtents_;
7070
const std::vector<std::vector<int64_t>> sitesExtents_int64_;
@@ -86,19 +86,25 @@ class MPSTNCuda final : public TNCudaBase<Precision, MPSTNCuda<Precision>> {
8686
explicit MPSTNCuda(const std::size_t numQubits,
8787
const std::size_t maxBondDim)
8888
: BaseType(numQubits), maxBondDim_(maxBondDim),
89-
sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()),
89+
bondDims_(setBondDims_()), sitesModes_(setSitesModes_()),
90+
sitesExtents_(setSitesExtents_()),
9091
sitesExtents_int64_(setSitesExtents_int64_()) {
9192
initTensors_();
93+
reset();
94+
appendInitialMPSState_();
9295
}
9396

9497
// TODO: Add method to the constructor to allow users to select methods at
9598
// runtime in the C++ layer
9699
explicit MPSTNCuda(const std::size_t numQubits,
97100
const std::size_t maxBondDim, DevTag<int> dev_tag)
98101
: BaseType(numQubits, dev_tag), maxBondDim_(maxBondDim),
99-
sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()),
102+
bondDims_(setBondDims_()), sitesModes_(setSitesModes_()),
103+
sitesExtents_(setSitesExtents_()),
100104
sitesExtents_int64_(setSitesExtents_int64_()) {
101105
initTensors_();
106+
reset();
107+
appendInitialMPSState_();
102108
}
103109

104110
~MPSTNCuda() = default;
@@ -162,6 +168,31 @@ class MPSTNCuda final : public TNCudaBase<Precision, MPSTNCuda<Precision>> {
162168
setBasisState(zeroState);
163169
}
164170

171+
/**
172+
* @brief Update the ith MPS site data.
173+
*
174+
* @param site_idx Index of the MPS site.
175+
* @param host_data Pointer to the data on host.
176+
* @param host_data_size Length of the data.
177+
*/
178+
void updateMPSSiteData(const std::size_t site_idx,
179+
const ComplexT *host_data,
180+
std::size_t host_data_size) {
181+
PL_ABORT_IF_NOT(
182+
site_idx < BaseType::getNumQubits(),
183+
"The site index should be less than the number of qubits.");
184+
185+
const std::size_t idx = BaseType::getNumQubits() - site_idx - 1;
186+
PL_ABORT_IF_NOT(
187+
host_data_size == tensors_[idx].getDataBuffer().getLength(),
188+
"The length of the host data should match its copy on the device.");
189+
190+
tensors_[idx].getDataBuffer().zeroInit();
191+
192+
tensors_[idx].getDataBuffer().CopyHostDataToGpu(host_data,
193+
host_data_size);
194+
}
195+
165196
/**
166197
* @brief Update quantum state with a basis state.
167198
* NOTE: This API assumes the bond vector is a standard basis vector
@@ -192,18 +223,13 @@ class MPSTNCuda final : public TNCudaBase<Precision, MPSTNCuda<Precision>> {
192223
if (i == 0) {
193224
target = basisState[idx];
194225
} else {
195-
target = basisState[idx] == 0 ? 0 : maxBondDim_;
226+
target = basisState[idx] == 0 ? 0 : bondDims_[i - 1];
196227
}
197228

198229
PL_CUDA_IS_SUCCESS(
199230
cudaMemcpy(&tensors_[i].getDataBuffer().getData()[target],
200231
&value_cu, sizeof(CFP_t), cudaMemcpyHostToDevice));
201232
}
202-
203-
if (MPSInitialized_ == MPSStatus::MPSInitNotSet) {
204-
MPSInitialized_ = MPSStatus::MPSInitSet;
205-
updateQuantumStateMPS_();
206-
}
207233
};
208234

209235
/**
@@ -307,6 +333,27 @@ class MPSTNCuda final : public TNCudaBase<Precision, MPSTNCuda<Precision>> {
307333
}
308334

309335
private:
336+
/**
337+
* @brief Return bondDims to the member initializer
338+
* NOTE: This method only works for the open boundary condition
339+
* @return std::vector<std::size_t>
340+
*/
341+
std::vector<std::size_t> setBondDims_() {
342+
std::vector<std::size_t> localBondDims(BaseType::getNumQubits() - 1,
343+
maxBondDim_);
344+
345+
const std::size_t ubDim = log2(maxBondDim_);
346+
for (std::size_t i = 0; i < localBondDims.size(); i++) {
347+
const std::size_t bondDim =
348+
std::min(i + 1, BaseType::getNumQubits() - i - 1);
349+
350+
if (bondDim <= ubDim) {
351+
localBondDims[i] = std::size_t{1} << bondDim;
352+
}
353+
}
354+
return localBondDims;
355+
}
356+
310357
/**
311358
* @brief Return siteModes to the member initializer
312359
* NOTE: This method only works for the open boundary condition
@@ -348,15 +395,16 @@ class MPSTNCuda final : public TNCudaBase<Precision, MPSTNCuda<Precision>> {
348395
if (i == 0) {
349396
// Leftmost site (state mode, shared mode)
350397
localSiteExtents = std::vector<std::size_t>(
351-
{BaseType::getQubitDims()[i], maxBondDim_});
398+
{BaseType::getQubitDims()[i], bondDims_[i]});
352399
} else if (i == BaseType::getNumQubits() - 1) {
353400
// Rightmost site (shared mode, state mode)
354401
localSiteExtents = std::vector<std::size_t>(
355-
{maxBondDim_, BaseType::getQubitDims()[i]});
402+
{bondDims_[i - 1], BaseType::getQubitDims()[i]});
356403
} else {
357404
// Interior sites (state mode, state mode, shared mode)
358405
localSiteExtents = std::vector<std::size_t>(
359-
{maxBondDim_, BaseType::getQubitDims()[i], maxBondDim_});
406+
{bondDims_[i - 1], BaseType::getQubitDims()[i],
407+
bondDims_[i]});
360408
}
361409
localSitesExtents.push_back(std::move(localSiteExtents));
362410
}
@@ -394,11 +442,11 @@ class MPSTNCuda final : public TNCudaBase<Precision, MPSTNCuda<Precision>> {
394442
}
395443

396444
/**
397-
* @brief Update quantumState (cutensornetState_t) with data provided by a
398-
* user
445+
* @brief Append initial MPS sites to the compute graph with data provided
446+
* by a user
399447
*
400448
*/
401-
void updateQuantumStateMPS_() {
449+
void appendInitialMPSState_() {
402450
PL_CUTENSORNET_IS_SUCCESS(cutensornetStateInitializeMPS(
403451
/*const cutensornetHandle_t */ BaseType::getTNCudaHandle(),
404452
/*cutensornetState_t*/ BaseType::getQuantumState(),

pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp

+12
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) {
7474
tensor_network.getData(data_ptr, state.size());
7575
},
7676
"Copy StateVector data into a Numpy array.")
77+
.def(
78+
"updateMPSSitesData",
79+
[](TensorNet &tensor_network, std::vector<np_arr_c> &tensors) {
80+
for (std::size_t idx = 0; idx < tensors.size(); idx++) {
81+
py::buffer_info numpyArrayInfo = tensors[idx].request();
82+
auto *data_ptr = static_cast<std::complex<PrecisionT> *>(
83+
numpyArrayInfo.ptr);
84+
tensor_network.updateMPSSiteData(idx, data_ptr,
85+
tensors[idx].size());
86+
}
87+
},
88+
"Pass MPS site data to the C++ backend.")
7789
.def(
7890
"setBasisState",
7991
[](TensorNet &tensor_network,

pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ TEMPLATE_TEST_CASE("[PauliZ]", "[MPSTNCuda_Expval]", float, double) {
203203
PrecisionT ref = -0.2115276040475712;
204204

205205
REQUIRE_THAT(res, Catch::Matchers::WithinRel(
206-
ref, static_cast<PrecisionT>(cutoff)));
206+
ref, static_cast<PrecisionT>(0.1)));
207207
}
208208
}
209209
}

pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp

+61
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,67 @@ TEMPLATE_PRODUCT_TEST_CASE("MPSTNCuda::Constructibility",
5858
}
5959
}
6060

61+
TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) {
62+
SECTION("Set MPS site with wrong site index") {
63+
const std::size_t num_qubits = 3;
64+
const std::size_t maxBondDim = 3;
65+
const std::size_t siteIdx = 3;
66+
67+
MPSTNCuda<TestType> mps_state{num_qubits, maxBondDim};
68+
69+
std::vector<std::complex<TestType>> site_data(1, {0.0, 0.0});
70+
71+
REQUIRE_THROWS_WITH(
72+
mps_state.updateMPSSiteData(siteIdx, site_data.data(),
73+
site_data.size()),
74+
Catch::Matchers::Contains(
75+
"The site index should be less than the number of qubits."));
76+
}
77+
78+
SECTION("Set MPS site with wrong site data size") {
79+
const std::size_t num_qubits = 3;
80+
const std::size_t maxBondDim = 3;
81+
const std::size_t siteIdx = 0;
82+
83+
MPSTNCuda<TestType> mps_state{num_qubits, maxBondDim};
84+
85+
std::vector<std::complex<TestType>> site_data(1, {0.0, 0.0});
86+
87+
REQUIRE_THROWS_WITH(
88+
mps_state.updateMPSSiteData(siteIdx, site_data.data(),
89+
site_data.size()),
90+
Catch::Matchers::Contains("The length of the host data should "
91+
"match its copy on the device."));
92+
}
93+
94+
SECTION("Set MPS sites") {
95+
const std::size_t num_qubits = 2;
96+
const std::size_t maxBondDim = 3;
97+
98+
MPSTNCuda<TestType> mps_state{num_qubits, maxBondDim};
99+
100+
mps_state.reset(); // Reset the state to zero state
101+
102+
std::vector<std::complex<TestType>> site0_data(4, {0.0, 0.0}); // MSB
103+
std::vector<std::complex<TestType>> site1_data(4, {0.0, 0.0}); // LSB
104+
105+
site0_data[2] = {1.0, 0.0};
106+
site1_data[1] = {1.0, 0.0};
107+
108+
mps_state.updateMPSSiteData(0, site0_data.data(), site0_data.size());
109+
mps_state.updateMPSSiteData(1, site1_data.data(), site1_data.size());
110+
111+
auto results = mps_state.getDataVector();
112+
113+
std::vector<std::complex<TestType>> expected_state(
114+
std::size_t{1} << num_qubits, std::complex<TestType>({0.0, 0.0}));
115+
116+
expected_state[3] = {1.0, 0.0};
117+
118+
CHECK(expected_state == Pennylane::Util::approx(results));
119+
}
120+
}
121+
61122
TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]",
62123
float, double) {
63124
std::vector<std::vector<std::size_t>> basisStates = {

pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2018-2023 Xanadu Quantum Technologies Inc.
1+
// Copyright 2018-2024 Xanadu Quantum Technologies Inc.
22

33
// Licensed under the Apache License, Version 2.0 (the License);
44
// you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
1414
#include <algorithm>
1515
#include <complex>
1616
#include <cstdio>
17+
#include <cuComplex.h>
18+
#include <type_traits>
1719
#include <vector>
1820

1921
#include <catch2/catch.hpp>

0 commit comments

Comments
 (0)