Skip to content

Commit

Permalink
Add SPVM routine for when kokkos not available. (#465)
Browse files Browse the repository at this point in the history
* Add homemade sparse product for when kokkos not available.

* Auto update version

* Trigger CI

* Fix some types.

* Add sparse qml.var test.

* Trigger CI

* Update changelog.

* Post-increment variables.

* Auto update version

* Trigger CI.

* Update .github/CHANGELOG.md

Co-authored-by: Amintor Dusko <[email protected]>

* Move changelog entry to 0.32.

* Move Kokkos_Sparse module to SparseLinAlg. Keep single apply_Sparse_Matrix interface for SpMV.

* Rename header inclusions.

* Reformat cpp.

---------

Co-authored-by: Dev version update bot <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Amintor Dusko <[email protected]>
  • Loading branch information
3 people authored Jul 6, 2023
1 parent d702423 commit 8608a6e
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 260 deletions.
5 changes: 5 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

### New features since last release

* Add native support to sparse Hamiltonians in the absence of Kokkos & Kokkos-kernels.
[(#465)] (https://github.com/PennyLaneAI/pennylane-lightning/pull/465)

### Breaking changes

### Improvements
Expand All @@ -14,6 +17,8 @@

This release contains contributions from (in alphabetical order):

Vincent Michaud-Rioux

---

# Release 0.31.0
Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/_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-dev2"
__version__ = "0.32.0-dev3"
40 changes: 14 additions & 26 deletions pennylane_lightning/lightning_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,19 +875,13 @@ def expval(self, observable, shot_range=None, bin_size=None):
state_vector = StateVectorC64(ket) if self.use_csingle else StateVectorC128(ket)
M = MeasuresC64(state_vector) if self.use_csingle else MeasuresC128(state_vector)
if observable.name == "SparseHamiltonian":
if Kokkos_info()["USE_KOKKOS"] == True:
# ensuring CSR sparse representation.

CSR_SparseHamiltonian = observable.sparse_matrix(wire_order=self.wires).tocsr(
copy=False
)
return M.expval(
CSR_SparseHamiltonian.indptr,
CSR_SparseHamiltonian.indices,
CSR_SparseHamiltonian.data,
)
raise NotImplementedError(
"The expval of a SparseHamiltonian requires Kokkos and Kokkos Kernels."
CSR_SparseHamiltonian = observable.sparse_matrix(wire_order=self.wires).tocsr(
copy=False
)
return M.expval(
CSR_SparseHamiltonian.indptr,
CSR_SparseHamiltonian.indices,
CSR_SparseHamiltonian.data,
)

if (
Expand Down Expand Up @@ -936,19 +930,13 @@ def var(self, observable, shot_range=None, bin_size=None):
M = MeasuresC64(state_vector) if self.use_csingle else MeasuresC128(state_vector)

if observable.name == "SparseHamiltonian":
if Kokkos_info()["USE_KOKKOS"] == True:
# ensuring CSR sparse representation.

CSR_SparseHamiltonian = observable.sparse_matrix(wire_order=self.wires).tocsr(
copy=False
)
return M.var(
CSR_SparseHamiltonian.indptr,
CSR_SparseHamiltonian.indices,
CSR_SparseHamiltonian.data,
)
raise NotImplementedError(
"The expval of a SparseHamiltonian requires Kokkos and Kokkos Kernels."
CSR_SparseHamiltonian = observable.sparse_matrix(wire_order=self.wires).tocsr(
copy=False
)
return M.var(
CSR_SparseHamiltonian.indptr,
CSR_SparseHamiltonian.indices,
CSR_SparseHamiltonian.data,
)

if (
Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/src/bindings/Bindings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
#pragma once
#include "AdjointDiff.hpp"
#include "CPUMemoryModel.hpp"
#include "Kokkos_Sparse.hpp"
#include "Macros.hpp"
#include "Measures.hpp"
#include "Memory.hpp"
#include "OpToMemberFuncPtr.hpp"
#include "RuntimeInfo.hpp"
#include "SparseLinAlg.hpp"
#include "StateVectorManagedCPU.hpp"

#include "pybind11/complex.h"
Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/src/simulator/Measures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
#include <unordered_map>
#include <vector>

#include "Kokkos_Sparse.hpp"
#include "LinearAlgebra.hpp"
#include "Observables.hpp"
#include "SparseLinAlg.hpp"
#include "StateVectorManagedCPU.hpp"
#include "StateVectorRawCPU.hpp"
#include "TransitionKernels.hpp"
Expand Down
99 changes: 10 additions & 89 deletions pennylane_lightning/src/tests/Test_Kokkos_Sparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <cstdio>
#include <vector>

#include "Kokkos_Sparse.hpp"
#include "SparseLinAlg.hpp"

#include "TestHelpers.hpp"
#include <catch2/catch.hpp>
Expand All @@ -21,70 +21,6 @@ using std::string;
using std::vector;
}; // namespace

TEMPLATE_TEST_CASE("apply_Sparse_Matrix_Kokkos", "[Kokkos Sparse]", float,
double) {
long num_qubits = 3;
long data_size = Util::exp2(num_qubits);

std::vector<std::vector<complex<TestType>>> vectors = {
{0.33160916, 0.90944626, 0.81097291, 0.46112135, 0.42801563, 0.38077181,
0.23550137, 0.57416324},
{{0.26752544, 0.00484225},
{0.49189265, 0.21231633},
{0.28691029, 0.87552205},
{0.13499786, 0.63862517},
{0.31748372, 0.25701515},
{0.96968437, 0.69821151},
{0.53674213, 0.58564544},
{0.02213429, 0.3050882}}};

const std::vector<std::vector<complex<TestType>>> result_refs = {
{-1.15200034, -0.23313581, -0.5595947, -0.7778672, -0.41387753,
-0.28274519, -0.71943368, 0.00705271},
{{-0.24650151, -0.51256229},
{-0.06254307, -0.66804797},
{-0.33998022, 0.02458055},
{-0.46939616, -0.49391203},
{-0.7871985, -1.07982153},
{0.11545852, -0.14444908},
{-0.45507653, -0.41765428},
{-0.78213328, -0.28539948}}};

std::vector<long> row_map;
std::vector<long> entries;
std::vector<complex<TestType>> values;
write_CSR_vectors(row_map, entries, values, data_size);

if constexpr (USE_KOKKOS) {
SECTION("Testing sparse matrix dense vector product:") {
for (size_t vec = 0; vec < vectors.size(); vec++) {
std::vector<complex<TestType>> result;
apply_Sparse_Matrix_Kokkos(
vectors[vec].data(), static_cast<long>(vectors[vec].size()),
row_map.data(), static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size()), result);
REQUIRE(result_refs[vec] == approx(result).margin(1e-6));
};
}
} else {
SECTION(
"Testing if apply_Sparse_Matrix_Kokkos is throwing an exception:") {
size_t vec = 0;
std::vector<complex<TestType>> result;
PL_CHECK_THROWS_MATCHES(
apply_Sparse_Matrix_Kokkos(
vectors[vec].data(), static_cast<long>(vectors[vec].size()),
row_map.data(), static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size()), result),
LightningException,
"Executing the product of a Sparse matrix and a vector "
"needs Kokkos and Kokkos Kernels installation.");
}
}
}

TEMPLATE_TEST_CASE("apply_Sparse_Matrix", "[Kokkos Sparse]", float, double) {
long num_qubits = 3;
long data_size = Util::exp2(num_qubits);
Expand Down Expand Up @@ -118,29 +54,14 @@ TEMPLATE_TEST_CASE("apply_Sparse_Matrix", "[Kokkos Sparse]", float, double) {
std::vector<complex<TestType>> values;
write_CSR_vectors(row_map, entries, values, data_size);

if constexpr (USE_KOKKOS) {
SECTION("Testing sparse matrix dense vector product:") {
for (size_t vec = 0; vec < vectors.size(); vec++) {
std::vector<complex<TestType>> result = apply_Sparse_Matrix(
vectors[vec].data(), static_cast<long>(vectors[vec].size()),
row_map.data(), static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size()));
REQUIRE(result_refs[vec] == approx(result).margin(1e-6));
};
}
} else {
SECTION("Testing if apply_Sparse_Matrix is throwing an exception:") {
size_t vec = 0;
PL_CHECK_THROWS_MATCHES(
apply_Sparse_Matrix(
vectors[vec].data(), static_cast<long>(vectors[vec].size()),
row_map.data(), static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size())),
LightningException,
"Executing the product of a Sparse matrix and a vector "
"needs Kokkos and Kokkos Kernels installation.");
}
SECTION("Testing sparse matrix dense vector product:") {
for (size_t vec = 0; vec < vectors.size(); vec++) {
std::vector<complex<TestType>> result = apply_Sparse_Matrix(
vectors[vec].data(), static_cast<long>(vectors[vec].size()),
row_map.data(), static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size()));
REQUIRE(result_refs[vec] == approx(result).margin(1e-6));
};
}
}
1 change: 0 additions & 1 deletion pennylane_lightning/src/tests/Test_Measures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include <cstdio>
#include <vector>

#include "Kokkos_Sparse.hpp"
#include "Measures.hpp"
#include "StateVectorManagedCPU.hpp"
#include "Util.hpp"
Expand Down
77 changes: 27 additions & 50 deletions pennylane_lightning/src/tests/Test_Measures_Sparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
#include <cstdio>
#include <vector>

#include "Kokkos_Sparse.hpp"
#include "Measures.hpp"
#include "SparseLinAlg.hpp"
#include "StateVectorManagedCPU.hpp"
#include "StateVectorRawCPU.hpp"
#include "Util.hpp"
Expand Down Expand Up @@ -36,59 +36,36 @@ TEMPLATE_TEST_CASE("Expected Values - Sparse Hamiltonian [Kokkos]",
Measures<TestType, StateVectorManagedCPU<TestType>> Measurer(
Measured_StateVector);

if constexpr (USE_KOKKOS) {
SECTION("Testing Sparse Hamiltonian:") {
long num_qubits = 3;
long data_size = Util::exp2(num_qubits);
SECTION("Testing Sparse Hamiltonian:") {
long num_qubits = 3;
long data_size = Util::exp2(num_qubits);

std::vector<long> row_map;
std::vector<long> entries;
std::vector<complex<TestType>> values;
write_CSR_vectors(row_map, entries, values, data_size);
std::vector<long> row_map;
std::vector<long> entries;
std::vector<complex<TestType>> values;
write_CSR_vectors(row_map, entries, values, data_size);

TestType exp_values = Measurer.expval(
row_map.data(), static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size()));
TestType exp_values_ref = 0.5930885;
REQUIRE(exp_values == Approx(exp_values_ref).margin(1e-6));
}

SECTION("Testing Sparse Hamiltonian (incompatible sizes):") {
long num_qubits = 4;
long data_size = Util::exp2(num_qubits);

std::vector<long> row_map;
std::vector<long> entries;
std::vector<complex<TestType>> values;
write_CSR_vectors(row_map, entries, values, data_size);
TestType exp_values = Measurer.expval(
row_map.data(), static_cast<long>(row_map.size()), entries.data(),
values.data(), static_cast<long>(values.size()));
TestType exp_values_ref = 0.5930885;
REQUIRE(exp_values == Approx(exp_values_ref).margin(1e-6));
}

PL_CHECK_THROWS_MATCHES(
Measurer.expval(row_map.data(),
static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size())),
LightningException,
"Statevector and Hamiltonian have incompatible sizes.");
}
} else {
SECTION("Testing Sparse Hamiltonian:") {
long num_qubits = 3;
long data_size = Util::exp2(num_qubits);
SECTION("Testing Sparse Hamiltonian (incompatible sizes):") {
long num_qubits = 4;
long data_size = Util::exp2(num_qubits);

std::vector<long> row_map;
std::vector<long> entries;
std::vector<complex<TestType>> values;
write_CSR_vectors(row_map, entries, values, data_size);
std::vector<long> row_map;
std::vector<long> entries;
std::vector<complex<TestType>> values;
write_CSR_vectors(row_map, entries, values, data_size);

PL_CHECK_THROWS_MATCHES(
Measurer.expval(row_map.data(),
static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size())),
LightningException,
"Executing the product of a Sparse matrix and a vector needs "
"Kokkos and Kokkos Kernels installation.");
}
PL_CHECK_THROWS_MATCHES(
Measurer.expval(row_map.data(), static_cast<long>(row_map.size()),
entries.data(), values.data(),
static_cast<long>(values.size())),
LightningException,
"Statevector and Hamiltonian have incompatible sizes.");
}
}
12 changes: 6 additions & 6 deletions pennylane_lightning/src/util/LinearAlgebra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ inline static void
omp_innerProd(const std::complex<T> *v1, const std::complex<T> *v2,
std::complex<T> &result, const size_t data_size) {
#if defined(_OPENMP)
#pragma omp declare \
reduction (sm:std::complex<T>:omp_out=ConstSum(omp_out, omp_in)) \
initializer(omp_priv=std::complex<T> {0, 0})
#pragma omp declare reduction(sm : std::complex<T> : omp_out = \
ConstSum(omp_out, omp_in)) \
initializer(omp_priv = std::complex<T>{0, 0})

size_t nthreads = data_size / NTERMS;
if (nthreads < 1) {
Expand Down Expand Up @@ -149,9 +149,9 @@ inline static void
omp_innerProdC(const std::complex<T> *v1, const std::complex<T> *v2,
std::complex<T> &result, const size_t data_size) {
#if defined(_OPENMP)
#pragma omp declare \
reduction (sm:std::complex<T>:omp_out=ConstSum(omp_out, omp_in)) \
initializer(omp_priv=std::complex<T> {0, 0})
#pragma omp declare reduction(sm : std::complex<T> : omp_out = \
ConstSum(omp_out, omp_in)) \
initializer(omp_priv = std::complex<T>{0, 0})
#endif

#if defined(_OPENMP)
Expand Down
Loading

0 comments on commit 8608a6e

Please sign in to comment.