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

Add CUDA-12 capability #477

Merged
merged 17 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
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
5 changes: 4 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@

* Update the CMake internal references to enable sub-project compilation with affecting the parent package.
[(#478)](https://github.com/PennyLaneAI/pennylane-lightning/pull/478)


* Modify `registerAdjointJacobian` and LKokkos' `applyMatrix` method to support device execution (with CUDA-12)
[(#477)](https://github.com/PennyLaneAI/pennylane-lightning/pull/477)
vincentmr marked this conversation as resolved.
Show resolved Hide resolved

* `apply` no longer mutates the inputted list of operations.
[(#474)](https://github.com/PennyLaneAI/pennylane-lightning/pull/474)

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.32.0-dev10"
__version__ = "0.32.0-dev11"
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,9 @@ template <class StateVectorT, class Derived> class AdjointJacobianBase {
*/
inline void adjointJacobian(std::span<PrecisionT> jac,
const JacobianData<StateVectorT> &jd,
const StateVectorT &ref_data = {0},
bool apply_operations = false) {
return static_cast<Derived *>(this)->adjointJacobian(jac, jd,
return static_cast<Derived *>(this)->adjointJacobian(jac, jd, ref_data,
apply_operations);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {obs}, ops, tp};
PL_REQUIRE_THROWS_MATCHES(
adj.adjointJacobian(std::span{jacobian}, tape, true),
adj.adjointJacobian(std::span{jacobian}, tape, psi, true),
LightningException,
"The size of preallocated jacobian must be same as");
}
Expand All @@ -116,7 +116,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {obs}, ops, tp};
REQUIRE_NOTHROW(
adj.adjointJacobian(std::span{jacobian}, tape, true));
adj.adjointJacobian(std::span{jacobian}, tape, psi, true));
}
}

Expand All @@ -141,7 +141,7 @@ template <typename TypeList> void testAdjointJacobian() {

JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {obs}, ops, tp};
adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);
CHECK(-sin(p) == Approx(jacobian[0]));
Expand Down Expand Up @@ -169,7 +169,7 @@ template <typename TypeList> void testAdjointJacobian() {

JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {obs}, ops, tp};
adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);
CHECK(cos(p) == Approx(jacobian[0]).margin(1e-7));
Expand Down Expand Up @@ -199,7 +199,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{num_params, psi.getLength(),
psi.getData(), {obs1, obs2},
ops, tp};
adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);
CHECK(-sin(param[0]) == Approx(jacobian[0]).margin(1e-7));
Expand Down Expand Up @@ -233,7 +233,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{num_params, psi.getLength(),
psi.getData(), {obs1, obs2, obs3},
ops, tp};
adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);
CHECK(-sin(param[0]) == Approx(jacobian[0]).margin(1e-7));
Expand Down Expand Up @@ -271,7 +271,7 @@ template <typename TypeList> void testAdjointJacobian() {
psi.getData(), {obs1, obs2, obs3},
ops, t_params};

adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);
CHECK(-sin(param[0]) == Approx(jacobian[0]).margin(1e-7));
Expand Down Expand Up @@ -307,7 +307,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {obs}, ops, tp};

adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);

Expand Down Expand Up @@ -353,7 +353,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {obs}, ops, tp};

adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);

Expand Down Expand Up @@ -405,7 +405,7 @@ template <typename TypeList> void testAdjointJacobian() {

JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {obs}, ops, tp};
adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(theta);
CAPTURE(jacobian);
Expand Down Expand Up @@ -473,7 +473,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{
t_params.size(), psi.getLength(), psi.getData(), {obs}, ops,
t_params};
adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

std::vector<PrecisionT> expected{-0.71429188, 0.04998561,
-0.71904837};
Expand Down Expand Up @@ -510,7 +510,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{
num_params, psi.getLength(), psi.getData(), {ham}, ops, tp};

adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);
CHECK(-0.3 * sin(param[0]) == Approx(jacobian[0]).margin(1e-7));
Expand Down Expand Up @@ -546,7 +546,7 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape{num_params, psi.getLength(),
psi.getData(), {ham},
ops, t_params};
adj.adjointJacobian(std::span{jacobian}, tape, true);
adj.adjointJacobian(std::span{jacobian}, tape, psi, true);

CAPTURE(jacobian);
CHECK((-0.47 * sin(param[0]) == Approx(jacobian[0]).margin(1e-7)));
Expand Down Expand Up @@ -588,8 +588,8 @@ template <typename TypeList> void testAdjointJacobian() {
JacobianData<StateVectorT> tape2{num_params, psi.getLength(),
psi.getData(), {obs2},
ops, t_params};
adj.adjointJacobian(std::span{jacobian1}, tape1, true);
adj.adjointJacobian(std::span{jacobian2}, tape2, true);
adj.adjointJacobian(std::span{jacobian1}, tape1, psi, true);
adj.adjointJacobian(std::span{jacobian2}, tape2, psi, true);

CHECK((jacobian1 == PLApprox(jacobian2).margin(1e-7)));
}
Expand Down
4 changes: 1 addition & 3 deletions pennylane_lightning/core/src/bindings/Bindings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,7 @@ auto registerAdjointJacobian(
observables,
operations,
trainableParams};

adjoint_jacobian.adjointJacobian(std::span{jac}, jd);

adjoint_jacobian.adjointJacobian(std::span{jac}, jd, sv);
return py::array_t<PrecisionT>(py::cast(jac));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class StateVectorKokkos final
using PrecisionT = fp_t;
using ComplexT = Kokkos::complex<fp_t>;
using KokkosExecSpace = Kokkos::DefaultExecutionSpace;
using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
using KokkosVector = Kokkos::View<ComplexT *>;
using KokkosSizeTVector = Kokkos::View<size_t *>;
using KokkosRangePolicy = Kokkos::RangePolicy<KokkosExecSpace>;
Expand All @@ -81,12 +82,10 @@ class StateVectorKokkos final
Kokkos::View<PrecisionT *, Kokkos::HostSpace,
Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
using ScratchViewComplex =
Kokkos::View<ComplexT *,
Kokkos::DefaultExecutionSpace::scratch_memory_space,
Kokkos::View<ComplexT *, KokkosExecSpace::scratch_memory_space,
Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
using ScratchViewSizeT =
Kokkos::View<size_t *,
Kokkos::DefaultExecutionSpace::scratch_memory_space,
Kokkos::View<size_t *, KokkosExecSpace::scratch_memory_space,
Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
using TeamPolicy = Kokkos::TeamPolicy<>;

Expand Down Expand Up @@ -398,10 +397,14 @@ class StateVectorKokkos final
bool inverse = false) {
PL_ABORT_IF(wires.empty(), "Number of wires must be larger than 0");
size_t n = 1U << wires.size();
KokkosVector matrix_("matrix_", n * n);
for (size_t i = 0; i < n * n; i++) {
matrix_(i) = matrix[i];
}
size_t n2 = n * n;
KokkosVector matrix_("matrix_", n2);
typename KokkosVector::HostMirror matrix_h =
Kokkos::create_mirror_view(matrix_);
Kokkos::parallel_for(
Kokkos::RangePolicy<HostExecSpace>(0, n2),
KOKKOS_LAMBDA(const size_t i) { matrix_h(i) = matrix[i]; });
Kokkos::deep_copy(matrix_, matrix_h);
applyMultiQubitOp(matrix_, wires, inverse);
}

Expand Down Expand Up @@ -760,13 +763,14 @@ class StateVectorKokkos final
* @brief Get underlying data vector
*/
[[nodiscard]] auto getDataVector() -> std::vector<ComplexT> {
std::vector<ComplexT> data_(getData(), getData() + this->getLength());
std::vector<ComplexT> data_(this->getLength());
DeviceToHost(data_.data(), data_.size());
return data_;
}

[[nodiscard]] auto getDataVector() const -> const std::vector<ComplexT> {
const std::vector<ComplexT> data_(getData(),
getData() + this->getLength());
std::vector<ComplexT> data_(this->getLength());
DeviceToHost(data_.data(), data_.size());
return data_;
}

Expand All @@ -782,7 +786,7 @@ class StateVectorKokkos final
* @brief Copy data from the device space to the host space.
*
*/
inline void DeviceToHost(ComplexT *sv, size_t length) {
inline void DeviceToHost(ComplexT *sv, size_t length) const {
Kokkos::deep_copy(UnmanagedComplexHostView(sv, length), *data_);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class AdjointJacobian final
*/
void adjointJacobian(std::span<PrecisionT> jac,
const JacobianData<StateVectorT> &jd,
const StateVectorT &ref_data,
bool apply_operations = false) {
const OpsData<StateVectorT> &ops = jd.getOperations();
const std::vector<std::string> &ops_name = ops.getOpsName();
Expand Down Expand Up @@ -112,12 +113,8 @@ class AdjointJacobian final
auto tp_it = tp.rbegin();
const auto tp_rend = tp.rend();

StateVectorKokkos<PrecisionT> ref_data(jd.getPtrStateVec(),
jd.getSizeStateVec());

// Create $U_{1:p}\vert \lambda \rangle$
StateVectorT lambda(ref_data.getNumQubits());
lambda.DeviceToDevice(ref_data.getView());
StateVectorT lambda{ref_data};

// Apply given operations to statevector if requested
if (apply_operations) {
Expand All @@ -129,7 +126,7 @@ class AdjointJacobian final
StateVectorT(lambda.getNumQubits()));
this->applyObservables(H_lambda, lambda, obs);

StateVectorT mu(lambda.getNumQubits());
StateVectorT mu{lambda.getNumQubits()};

for (int op_idx = static_cast<int>(ops_name.size() - 1); op_idx >= 0;
op_idx--) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,7 @@ class Measurements final
* @return Expectation value with respect to the given observable.
*/
PrecisionT expval(const Observable<StateVectorT> &ob) {
StateVectorT ob_sv(this->_statevector.getNumQubits());
ob_sv.DeviceToDevice(this->_statevector.getView());
StateVectorT ob_sv{this->_statevector};
ob.applyInPlace(ob_sv);
return getRealOfComplexInnerProduct(this->_statevector.getView(),
ob_sv.getView());
Expand All @@ -328,8 +327,7 @@ class Measurements final
*/
PrecisionT expval(const std::vector<ComplexT> &matrix,
const std::vector<size_t> &wires) {
StateVectorT ob_sv(this->_statevector.getNumQubits());
ob_sv.DeviceToDevice(this->_statevector.getView());
StateVectorT ob_sv{this->_statevector};
ob_sv.applyMatrix(matrix, wires);
return getRealOfComplexInnerProduct(this->_statevector.getView(),
ob_sv.getView());
Expand All @@ -344,8 +342,7 @@ class Measurements final
*/
PrecisionT expval(const std::string &operation,
const std::vector<size_t> &wires) {
StateVectorT ob_sv(this->_statevector.getNumQubits());
ob_sv.DeviceToDevice(this->_statevector.getView());
StateVectorT ob_sv{this->_statevector};
ob_sv.applyOperation(operation, wires);
return getRealOfComplexInnerProduct(this->_statevector.getView(),
ob_sv.getView());
Expand Down Expand Up @@ -425,8 +422,7 @@ class Measurements final
* @return Variance with respect to the given observable.
*/
auto var(const Observable<StateVectorT> &ob) -> PrecisionT {
StateVectorT ob_sv(this->_statevector.getNumQubits());
ob_sv.DeviceToDevice(this->_statevector.getView());
StateVectorT ob_sv{this->_statevector};
ob.applyInPlace(ob_sv);

const PrecisionT mean_square =
Expand All @@ -447,8 +443,7 @@ class Measurements final
*/
PrecisionT var(const std::string &operation,
const std::vector<size_t> &wires) {
StateVectorT ob_sv(this->_statevector.getNumQubits());
ob_sv.DeviceToDevice(this->_statevector.getView());
StateVectorT ob_sv{this->_statevector};
ob_sv.applyOperation(operation, wires);

const PrecisionT mean_square =
Expand All @@ -469,8 +464,7 @@ class Measurements final
*/
PrecisionT var(const std::vector<ComplexT> &matrix,
const std::vector<size_t> &wires) {
StateVectorT ob_sv(this->_statevector.getNumQubits());
ob_sv.DeviceToDevice(this->_statevector.getView());
StateVectorT ob_sv{this->_statevector};
ob_sv.applyMatrix(matrix, wires);

const PrecisionT mean_square =
Expand Down Expand Up @@ -533,8 +527,7 @@ class Measurements final
(this->_statevector.getLength() != (size_t(row_map_size) - 1)),
"Statevector and Hamiltonian have incompatible sizes.");

StateVectorT ob_sv(this->_statevector.getNumQubits());
ob_sv.DeviceToDevice(this->_statevector.getView());
StateVectorT ob_sv{this->_statevector};

SparseMV_Kokkos<PrecisionT>(this->_statevector.getView(),
ob_sv.getView(), row_map_ptr, row_map_size,
Expand Down Expand Up @@ -582,7 +575,7 @@ class Measurements final
* @return Floating point std::vector with probabilities.
* The basis columns are rearranged according to wires.
*/
auto probs(const std::vector<size_t> &wires) {
std::vector<PrecisionT> probs(const std::vector<size_t> &wires) {
using MDPolicyType_2D =
Kokkos::MDRangePolicy<Kokkos::Rank<2, Kokkos::Iterate::Left>>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,10 @@ class Hamiltonian final : public HamiltonianBase<StateVectorT> {
* @param sv The statevector to update
*/
void applyInPlace(StateVectorT &sv) const override {
StateVectorT buffer(sv.getNumQubits());
StateVectorT buffer{sv.getNumQubits()};
buffer.initZeros();

for (size_t term_idx = 0; term_idx < this->coeffs_.size(); term_idx++) {
StateVectorT tmp(sv);
StateVectorT tmp{sv};
this->obs_[term_idx]->applyInPlace(tmp);
LightningKokkos::Util::axpy_Kokkos<PrecisionT>(
ComplexT{this->coeffs_[term_idx], 0.0}, tmp.getView(),
Expand All @@ -215,8 +214,7 @@ template <class StateVectorT, bool use_openmp> struct HamiltonianApplyInPlace {
KokkosVector res("results", sv.getLength());
Kokkos::deep_copy(res, ComplexT{0.0, 0.0});
for (size_t term_idx = 0; term_idx < coeffs.size(); term_idx++) {
StateVectorT tmp(sv.getNumQubits());
tmp.DeviceToDevice(sv.getView());
StateVectorT tmp{sv};
terms[term_idx]->applyInPlace(tmp);
LightningKokkos::Util::axpy_Kokkos<PrecisionT>(
ComplexT{coeffs[term_idx], 0.0}, tmp.getView(), res,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class AdjointJacobian final
*/
void adjointJacobian(std::span<PrecisionT> jac,
const JacobianData<StateVectorT> &jd,
[[maybe_unused]] const StateVectorT &ref_data = {0},
bool apply_operations = false) {
const OpsData<StateVectorT> &ops = jd.getOperations();
const std::vector<std::string> &ops_name = ops.getOpsName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ TEMPLATE_PRODUCT_TEST_CASE("StateVector VJP", "[Algorithms]",
}();

std::vector<PrecisionT> jac(num_params);
adj.adjointJacobian(std::span{jac}, jd);
adj.adjointJacobian(std::span{jac}, jd, sv);

REQUIRE(grad_vjp == approx(jac).margin(1e-5));
}
Expand Down
3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ pybind11
pytest
pytest-cov
pytest-mock
black==23.7.0
black==23.7.0
AmintorDusko marked this conversation as resolved.
Show resolved Hide resolved
clang-format==14
Loading