Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update lightning qubit memory management #601

Merged
merged 35 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
635767f
update dev version
AmintorDusko Jan 25, 2024
5c05425
update clean
AmintorDusko Jan 25, 2024
567d21f
expand .gitignore
AmintorDusko Jan 25, 2024
b761f3f
expand lightning qubit class specific python bindings
AmintorDusko Jan 25, 2024
762ee8c
add some statevector manipulation methods to statevector managed simu…
AmintorDusko Jan 25, 2024
99150d8
update lightning qubit python class
AmintorDusko Jan 25, 2024
404d249
add c++ unit tests
AmintorDusko Jan 25, 2024
b760684
add comments to test
AmintorDusko Jan 25, 2024
ab3304a
update lightning_qubit.py
AmintorDusko Jan 25, 2024
6b9de7c
remove obsolete tests
AmintorDusko Jan 26, 2024
dd1e632
rename statevector instance
AmintorDusko Jan 26, 2024
2e497fb
return some important tests
AmintorDusko Jan 26, 2024
d0675d1
implement PR review sugestions
AmintorDusko Jan 26, 2024
1ec3cd2
add review suggestion
AmintorDusko Jan 26, 2024
9c66497
Add semi-colon.
vincentmr Jan 26, 2024
31f4104
Fix Projector obs in L-Qubit and add Proj support in L-Kokkos.
vincentmr Jan 29, 2024
7ee08a2
Implement previous commit fix for None shots only.
vincentmr Jan 29, 2024
8df8a2a
Add tests for Proj expval/var
vincentmr Jan 29, 2024
e19003e
Merge branch 'master' into update_lightning_qubit_memory_management
AmintorDusko Jan 29, 2024
9e39e05
Auto update version
github-actions[bot] Jan 29, 2024
e6412bf
Trigger CI
AmintorDusko Jan 29, 2024
4e7f1a9
remove comment
AmintorDusko Jan 29, 2024
0c8cffb
add projector support to LGPU
AmintorDusko Jan 29, 2024
645bbe0
format
AmintorDusko Jan 29, 2024
40a8a00
revert changes for LGPU
AmintorDusko Jan 29, 2024
8d28fd4
skip tests for Projector observable not supported
AmintorDusko Jan 29, 2024
f115f6f
expand tests for lightning.qubit
AmintorDusko Jan 29, 2024
3d67dfe
update changelog
AmintorDusko Jan 29, 2024
4134f0e
Merge branch 'master' into update_lightning_qubit_memory_management
AmintorDusko Jan 29, 2024
0d7b876
Auto update version
github-actions[bot] Jan 29, 2024
2e7d363
Trigger CI
AmintorDusko Jan 29, 2024
6a2cab9
add some review suggestions
AmintorDusko Jan 29, 2024
e800725
remove identities
AmintorDusko Jan 30, 2024
1dc6b3e
update LKokkos and LQubit _apply_state_vector
AmintorDusko Jan 30, 2024
91d672e
Update tests/test_apply.py
AmintorDusko Jan 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

### Improvements

* Decouple LightningQubit memory ownership from numpy and migrate it to Lightning-Qubit managed state-vector class.
[(#601)](https://github.com/PennyLaneAI/pennylane-lightning/pull/601)

* Expand support for Projector observables on Lightning-Kokkos.
[(#601)](https://github.com/PennyLaneAI/pennylane-lightning/pull/601)

* Split Docker build cron job into two jobs: master and latest. This is mainly for reporting in the `plugin-test-matrix` repo.
[(#600)](https://github.com/PennyLaneAI/pennylane-lightning/pull/600)

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ doc/code/api/
PennyLane_Lightning.egg-info/
PennyLane_Lightning_Kokkos.egg-info/
build/
build_lightning_*/
Build/
BuildCov/
BuildGBench/
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ help:
clean:
find . -type d -name '__pycache__' -exec rm -r {} \+
rm -rf build Build BuildTests BuildTidy BuildGBench
rm -rf build_*
rm -rf .coverage coverage_html_report/
rm -rf pennylane_lightning/*_ops*

Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/core/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.35.0-dev9"
__version__ = "0.35.0-dev10"
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#pragma once

#include <algorithm> // fill
#include <complex>
#include <vector>

Expand Down Expand Up @@ -71,12 +72,12 @@ class StateVectorLQubitManaged final
* @param memory_model Memory model the statevector will use
*/
explicit StateVectorLQubitManaged(
size_t num_qubits, Threading threading = Threading::SingleThread,
std::size_t num_qubits, Threading threading = Threading::SingleThread,
CPUMemoryModel memory_model = bestCPUMemoryModel())
: BaseType{num_qubits, threading, memory_model},
data_{exp2(num_qubits), ComplexT{0.0, 0.0},
getAllocator<ComplexT>(this->memory_model_)} {
data_[0] = {1, 0};
setBasisState(0U);
}

/**
Expand All @@ -102,7 +103,7 @@ class StateVectorLQubitManaged final
* @param threading Threading option the statevector to use
* @param memory_model Memory model the statevector will use
*/
StateVectorLQubitManaged(const ComplexT *other_data, size_t other_size,
StateVectorLQubitManaged(const ComplexT *other_data, std::size_t other_size,
Threading threading = Threading::SingleThread,
CPUMemoryModel memory_model = bestCPUMemoryModel())
: BaseType(log2PerfectPower(other_size), threading, memory_model),
Expand Down Expand Up @@ -139,6 +140,39 @@ class StateVectorLQubitManaged final

~StateVectorLQubitManaged() = default;

/**
* @brief Prepares a single computational basis state.
*
* @param index Index of the target element.
*/
void setBasisState(const std::size_t index) {
std::fill(data_.begin(), data_.end(), 0);
AmintorDusko marked this conversation as resolved.
Show resolved Hide resolved
data_[index] = {1, 0};
}

/**
* @brief Set values for a batch of elements of the state-vector.
*
* @param values Values to be set for the target elements.
* @param indices Indices of the target elements.
*/
void setStateVector(const std::vector<std::size_t> &indices,
const std::vector<ComplexT> &values) {
for (std::size_t n = 0; n < indices.size(); n++) {
data_[indices[n]] = values[n];
}
}

/**
* @brief Reset the data back to the \f$\ket{0}\f$ state.
*
*/
void resetStateVector() {
if (this->getLength() > 0) {
setBasisState(0U);
}
}

[[nodiscard]] auto getData() -> ComplexT * { return data_.data(); }

[[nodiscard]] auto getData() const -> const ComplexT * {
Expand All @@ -164,7 +198,7 @@ class StateVectorLQubitManaged final
* @param new_data data pointer to new data.
* @param new_size size of underlying data storage.
*/
void updateData(const ComplexT *new_data, size_t new_size) {
void updateData(const ComplexT *new_data, std::size_t new_size) {
PL_ASSERT(data_.size() == new_size);
std::copy(new_data, new_data + new_size, data_.data());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include "GateOperation.hpp"
#include "MeasurementsLQubit.hpp"
#include "ObservablesLQubit.hpp"
#include "StateVectorLQubitRaw.hpp"
#include "StateVectorLQubitManaged.hpp"
#include "TypeList.hpp"
#include "VectorJacobianProduct.hpp"

Expand All @@ -36,16 +36,16 @@ using namespace Pennylane::Bindings;
using namespace Pennylane::LightningQubit::Algorithms;
using namespace Pennylane::LightningQubit::Measures;
using namespace Pennylane::LightningQubit::Observables;
using Pennylane::LightningQubit::StateVectorLQubitRaw;
using Pennylane::LightningQubit::StateVectorLQubitManaged;
} // namespace
/// @endcond

namespace py = pybind11;

namespace Pennylane::LightningQubit {
using StateVectorBackends =
Pennylane::Util::TypeList<StateVectorLQubitRaw<float>,
StateVectorLQubitRaw<double>, void>;
Pennylane::Util::TypeList<StateVectorLQubitManaged<float>,
StateVectorLQubitManaged<double>, void>;

/**
* @brief Get a gate kernel map for a statevector.
Expand Down Expand Up @@ -162,12 +162,68 @@ void registerControlledGate(PyClass &pyclass) {
*/
template <class StateVectorT, class PyClass>
void registerBackendClassSpecificBindings(PyClass &pyclass) {
using PrecisionT =
typename StateVectorT::PrecisionT; // Statevector's precision
using ComplexT = typename StateVectorT::ComplexT;
using ParamT = PrecisionT; // Parameter's data precision
using np_arr_c = py::array_t<std::complex<ParamT>,
py::array::c_style | py::array::forcecast>;

registerGatesForStateVector<StateVectorT>(pyclass);
registerControlledGate<StateVectorT>(pyclass);
pyclass.def("applyControlledMatrix", &applyControlledMatrix<StateVectorT>,
"Apply controlled operation");
pyclass.def("kernel_map", &svKernelMap<StateVectorT>,
"Get internal kernels for operations");

pyclass
.def(py::init([](std::size_t num_qubits) {
return new StateVectorT(num_qubits);
}))
.def("resetStateVector", &StateVectorT::resetStateVector)
.def(
"setBasisState",
[](StateVectorT &sv, const size_t index) {
AmintorDusko marked this conversation as resolved.
Show resolved Hide resolved
sv.setBasisState(index);
},
"Create Basis State.")
.def(
"setStateVector",
[](StateVectorT &sv, const std::vector<std::size_t> &indices,
const np_arr_c &state) {
const auto buffer = state.request();
std::vector<ComplexT> state_in;
if (buffer.size) {
const auto ptr = static_cast<const ComplexT *>(buffer.ptr);
state_in = std::vector<ComplexT>{ptr, ptr + buffer.size};
}
sv.setStateVector(indices, state_in);
},
"Set State Vector with values and their corresponding indices")
.def(
"getState",
mlxd marked this conversation as resolved.
Show resolved Hide resolved
[](const StateVectorT &sv, np_arr_c &state) {
py::buffer_info numpyArrayInfo = state.request();
auto *data_ptr =
static_cast<std::complex<PrecisionT> *>(numpyArrayInfo.ptr);
if (state.size()) {
std::copy(sv.getData(), sv.getData() + sv.getLength(),
data_ptr);
}
},
"Copy StateVector data into a Numpy array.")
.def(
"UpdateData",
mlxd marked this conversation as resolved.
Show resolved Hide resolved
[](StateVectorT &device_sv, const np_arr_c &state) {
const py::buffer_info numpyArrayInfo = state.request();
auto *data_ptr = static_cast<ComplexT *>(numpyArrayInfo.ptr);
const auto length =
static_cast<size_t>(numpyArrayInfo.shape[0]);
if (length) {
device_sv.updateData(data_ptr, length);
}
},
"Copy StateVector data into a Numpy array.")
.def("applyControlledMatrix", &applyControlledMatrix<StateVectorT>,
"Apply controlled operation")
.def("kernel_map", &svKernelMap<StateVectorT>,
"Get internal kernels for operations");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

#include <catch2/catch.hpp>

#include "LinearAlgebra.hpp" //randomUnitary
#include "CPUMemoryModel.hpp" // getBestAllocator
#include "LinearAlgebra.hpp" //randomUnitary
#include "StateVectorLQubitManaged.hpp"
#include "StateVectorLQubitRaw.hpp"
#include "TestHelpers.hpp" // createRandomStateVectorData, TestVector
Expand Down Expand Up @@ -107,4 +108,58 @@ TEMPLATE_TEST_CASE("StateVectorLQubitManaged::StateVectorLQubitManaged",

REQUIRE(sv.getDataVector() == approx(st_data));
}
}
}

TEMPLATE_TEST_CASE("StateVectorLQubitManaged::setBasisState",
"[StateVectorLQubitManaged]", float, double) {
using PrecisionT = TestType;
using ComplexT = std::complex<PrecisionT>;
using TestVectorT = TestVector<ComplexT>;

const std::size_t num_qubits = 3;

SECTION("Prepares a single computational basis state.") {
TestVectorT init_state =
createRandomStateVectorData<PrecisionT>(re, num_qubits);

TestVectorT expected_state(size_t{1U} << num_qubits, 0.0,
getBestAllocator<ComplexT>());
std::size_t index = GENERATE(0, 1, 2, 3, 4, 5, 6, 7);
expected_state[index] = {1.0, 0.0};
StateVectorLQubitManaged<PrecisionT> sv(init_state);
sv.setBasisState(index);

REQUIRE(sv.getDataVector() == approx(expected_state));
}
}

TEMPLATE_TEST_CASE("StateVectorLQubitManaged::SetStateVector",
"[StateVectorLQubitManaged]", float, double) {
using PrecisionT = TestType;
using ComplexT = std::complex<PrecisionT>;
using TestVectorT = TestVector<ComplexT>;

const std::size_t num_qubits = 3;

SECTION("Set state vector with values and indices") {
TestVectorT init_state =
createRandomStateVectorData<PrecisionT>(re, num_qubits);

auto expected_state = init_state;

for (size_t i = 0; i < Pennylane::Util::exp2(num_qubits - 1); i++) {
std::swap(expected_state[i * 2], expected_state[i * 2 + 1]);
}

AmintorDusko marked this conversation as resolved.
Show resolved Hide resolved
std::vector<std::size_t> indices = {0, 2, 4, 6, 1, 3, 5, 7};

std::vector<ComplexT> values = {
init_state[1], init_state[3], init_state[5], init_state[7],
init_state[0], init_state[2], init_state[4], init_state[6]};

StateVectorLQubitManaged<PrecisionT> sv{num_qubits};
sv.setStateVector(indices, values);

REQUIRE(sv.getDataVector() == approx(expected_state));
}
}
18 changes: 10 additions & 8 deletions pennylane_lightning/lightning_kokkos/lightning_kokkos.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
"Hadamard",
"Hermitian",
"Identity",
"Projector",
"SparseHamiltonian",
"Hamiltonian",
"Sum",
Expand Down Expand Up @@ -196,7 +197,7 @@
shots=None,
batch_obs=False,
kokkos_args=None,
): # pylint: disable=unused-argument
): # pylint: disable=unused-argument, too-many-arguments
super().__init__(wires, shots=shots, c_dtype=c_dtype)

if kokkos_args is None:
Expand All @@ -213,10 +214,6 @@
if not LightningKokkos.kokkos_config:
LightningKokkos.kokkos_config = _kokkos_configuration()

# Create the initial state. Internally, we store the
# state as an array of dimension [2]*wires.
self._pre_rotated_state = _kokkos_dtype(c_dtype)(self.num_wires)

@staticmethod
def _asarray(arr, dtype=None):
arr = np.asarray(arr) # arr is not copied
Expand Down Expand Up @@ -347,9 +344,8 @@
"""

if isinstance(state, self._kokkos_state.__class__):
state_data = np.zeros(state.size, dtype=self.C_DTYPE)
state_data = self._asarray(state_data, dtype=self.C_DTYPE)
state.DeviceToHost(state_data.ravel(order="C"))
state_data = allocate_aligned_array(state.size, np.dtype(self.C_DTYPE), True)
state.DeviceToHost(state_data)

Check warning on line 348 in pennylane_lightning/lightning_kokkos/lightning_kokkos.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_kokkos/lightning_kokkos.py#L347-L348

Added lines #L347 - L348 were not covered by tests
state = state_data

ravelled_indices, state = self._preprocess_state_vector(state, device_wires)
Expand Down Expand Up @@ -468,6 +464,9 @@
if observable.name in [
"Projector",
]:
if self.shots is None:
qs = qml.tape.QuantumScript([], [qml.expval(observable)])
self.apply(self._get_diagonalizing_gates(qs))

Check warning on line 469 in pennylane_lightning/lightning_kokkos/lightning_kokkos.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_kokkos/lightning_kokkos.py#L467-L469

Added lines #L467 - L469 were not covered by tests
return super().expval(observable, shot_range=shot_range, bin_size=bin_size)

if self.shots is not None:
Expand Down Expand Up @@ -528,6 +527,9 @@
if observable.name in [
"Projector",
]:
if self.shots is None:
qs = qml.tape.QuantumScript([], [qml.var(observable)])
self.apply(self._get_diagonalizing_gates(qs))

Check warning on line 532 in pennylane_lightning/lightning_kokkos/lightning_kokkos.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_kokkos/lightning_kokkos.py#L530-L532

Added lines #L530 - L532 were not covered by tests
return super().var(observable, shot_range=shot_range, bin_size=bin_size)

if self.shots is not None:
Expand Down
Loading
Loading