Skip to content

Commit

Permalink
Send backend-specific ops in respective modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentmr committed Oct 23, 2023
1 parent cc66546 commit dccfe3e
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 83 deletions.
88 changes: 5 additions & 83 deletions pennylane_lightning/core/src/bindings/Bindings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ void registerInfo(py::module_ &m) {
* @tparam StateVectorT
* @param m Pybind module
*/
template <class StateVectorT> void registerObservables(py::module_ &m) {
template <class StateVectorT>
void registerBackendAgnosticObservables(py::module_ &m) {
using PrecisionT =
typename StateVectorT::PrecisionT; // Statevector's precision.
using ComplexT =
Expand Down Expand Up @@ -406,87 +407,6 @@ template <class StateVectorT> void registerObservables(py::module_ &m) {
return self == other_cast;
},
"Compare two observables");

#ifdef _ENABLE_PLGPU
class_name = "SparseHamiltonianC" + bitsize;
using np_arr_sparse_ind = typename std::conditional<
std::is_same<ParamT, float>::value,
py::array_t<int32_t, py::array::c_style | py::array::forcecast>,
py::array_t<int64_t, py::array::c_style | py::array::forcecast>>::type;
using IdxT = typename SparseHamiltonian<StateVectorT>::IdxT;
py::class_<SparseHamiltonian<StateVectorT>,
std::shared_ptr<SparseHamiltonian<StateVectorT>>,
Observable<StateVectorT>>(m, class_name.c_str(),
py::module_local())
.def(py::init([](const np_arr_c &data, const np_arr_sparse_ind &indices,
const np_arr_sparse_ind &offsets,
const std::vector<std::size_t> &wires) {
const py::buffer_info buffer_data = data.request();
const auto *data_ptr = static_cast<ComplexT *>(buffer_data.ptr);

const py::buffer_info buffer_indices = indices.request();
const auto *indices_ptr =
static_cast<std::size_t *>(buffer_indices.ptr);

const py::buffer_info buffer_offsets = offsets.request();
const auto *offsets_ptr =
static_cast<std::size_t *>(buffer_offsets.ptr);

return SparseHamiltonian<StateVectorT>{
std::vector<ComplexT>({data_ptr, data_ptr + data.size()}),
std::vector<IdxT>({indices_ptr, indices_ptr + indices.size()}),
std::vector<IdxT>({offsets_ptr, offsets_ptr + offsets.size()}),
wires};
}))
.def("__repr__", &SparseHamiltonian<StateVectorT>::getObsName)
.def("get_wires", &SparseHamiltonian<StateVectorT>::getWires,
"Get wires of observables")
.def(
"__eq__",
[](const SparseHamiltonian<StateVectorT> &self,
py::handle other) -> bool {
if (!py::isinstance<SparseHamiltonian<StateVectorT>>(other)) {
return false;
}
auto other_cast = other.cast<SparseHamiltonian<StateVectorT>>();
return self == other_cast;
},
"Compare two observables");
#endif

#if _ENABLE_PLKOKKOS == 1
class_name = "SparseHamiltonianC" + bitsize;
py::class_<SparseHamiltonian<StateVectorT>,
std::shared_ptr<SparseHamiltonian<StateVectorT>>,
Observable<StateVectorT>>(m, class_name.c_str(),
py::module_local())
.def(py::init([](const np_arr_c &data,
const std::vector<std::size_t> &indices,
const std::vector<std::size_t> &indptr,
const std::vector<std::size_t> &wires) {
using ComplexT = typename StateVectorT::ComplexT;
const py::buffer_info buffer_data = data.request();
const auto *data_ptr = static_cast<ComplexT *>(buffer_data.ptr);

return SparseHamiltonian<StateVectorT>{
std::vector<ComplexT>({data_ptr, data_ptr + data.size()}),
indices, indptr, wires};
}))
.def("__repr__", &SparseHamiltonian<StateVectorT>::getObsName)
.def("get_wires", &SparseHamiltonian<StateVectorT>::getWires,
"Get wires of observables")
.def(
"__eq__",
[](const SparseHamiltonian<StateVectorT> &self,
py::handle other) -> bool {
if (!py::isinstance<SparseHamiltonian<StateVectorT>>(other)) {
return false;
}
auto other_cast = other.cast<SparseHamiltonian<StateVectorT>>();
return self == other_cast;
},
"Compare two observables");
#endif
}

/**
Expand Down Expand Up @@ -708,7 +628,9 @@ template <class StateVectorT> void lightningClassBindings(py::module_ &m) {
/* Observables submodule */
py::module_ obs_submodule =
m.def_submodule("observables", "Submodule for observables classes.");
registerObservables<StateVectorT>(obs_submodule);
// registerBackendAgnosticObservables<StateVectorT>(obs_submodule);
registerBackendAgnosticObservables<StateVectorT>(obs_submodule);
registerBackendSpecificObservables<StateVectorT>(obs_submodule);

//***********************************************************************//
// Measurements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,73 @@ void registerBackendSpecificMeasurements(PyClass &pyclass) {
"Variance of a sparse Hamiltonian.");
}

/**
* @brief Register backend specific observables.
*
* @tparam StateVectorT
* @param m Pybind module
*/
template <class StateVectorT>
void registerBackendSpecificObservables(py::module_ &m) {
using PrecisionT =
typename StateVectorT::PrecisionT; // Statevector's precision.
using ComplexT =
typename StateVectorT::ComplexT; // Statevector's complex type.
using ParamT = PrecisionT; // Parameter's data precision

const std::string bitsize =
std::to_string(sizeof(std::complex<PrecisionT>) * 8);

using np_arr_c = py::array_t<std::complex<ParamT>, py::array::c_style>;

std::string class_name;

class_name = "SparseHamiltonianC" + bitsize;
using np_arr_sparse_ind = typename std::conditional<
std::is_same<ParamT, float>::value,
py::array_t<int32_t, py::array::c_style | py::array::forcecast>,
py::array_t<int64_t, py::array::c_style | py::array::forcecast>>::type;
using IdxT = typename SparseHamiltonian<StateVectorT>::IdxT;
py::class_<SparseHamiltonian<StateVectorT>,
std::shared_ptr<SparseHamiltonian<StateVectorT>>,
Observable<StateVectorT>>(m, class_name.c_str(),
py::module_local())
.def(py::init([](const np_arr_c &data, const np_arr_sparse_ind &indices,
const np_arr_sparse_ind &offsets,
const std::vector<std::size_t> &wires) {
const py::buffer_info buffer_data = data.request();
const auto *data_ptr = static_cast<ComplexT *>(buffer_data.ptr);

const py::buffer_info buffer_indices = indices.request();
const auto *indices_ptr =
static_cast<std::size_t *>(buffer_indices.ptr);

const py::buffer_info buffer_offsets = offsets.request();
const auto *offsets_ptr =
static_cast<std::size_t *>(buffer_offsets.ptr);

return SparseHamiltonian<StateVectorT>{
std::vector<ComplexT>({data_ptr, data_ptr + data.size()}),
std::vector<IdxT>({indices_ptr, indices_ptr + indices.size()}),
std::vector<IdxT>({offsets_ptr, offsets_ptr + offsets.size()}),
wires};
}))
.def("__repr__", &SparseHamiltonian<StateVectorT>::getObsName)
.def("get_wires", &SparseHamiltonian<StateVectorT>::getWires,
"Get wires of observables")
.def(
"__eq__",
[](const SparseHamiltonian<StateVectorT> &self,
py::handle other) -> bool {
if (!py::isinstance<SparseHamiltonian<StateVectorT>>(other)) {
return false;
}
auto other_cast = other.cast<SparseHamiltonian<StateVectorT>>();
return self == other_cast;
},
"Compare two observables");
}

/**
* @brief Register backend specific adjoint Jacobian methods.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "ConstantUtil.hpp" // lookup
#include "GateOperation.hpp"
#include "MeasurementsKokkos.hpp"
#include "ObservablesKokkos.hpp"
#include "StateVectorKokkos.hpp"
#include "TypeList.hpp"
#include "Util.hpp" // exp2
Expand All @@ -33,6 +34,7 @@ namespace {
using namespace Pennylane::Bindings;
using namespace Pennylane::LightningKokkos::Algorithms;
using namespace Pennylane::LightningKokkos::Measures;
using namespace Pennylane::LightningKokkos::Observables;
using Kokkos::InitializationSettings;
using Pennylane::LightningKokkos::StateVectorKokkos;
using Pennylane::Util::exp2;
Expand Down Expand Up @@ -214,6 +216,58 @@ void registerBackendSpecificMeasurements(PyClass &pyclass) {
"Variance of a sparse Hamiltonian.");
}

/**
* @brief Register observable classes.
*
* @tparam StateVectorT
* @param m Pybind module
*/
template <class StateVectorT>
void registerBackendSpecificObservables(py::module_ &m) {
using PrecisionT =
typename StateVectorT::PrecisionT; // Statevector's precision.
using ParamT = PrecisionT; // Parameter's data precision

const std::string bitsize =
std::to_string(sizeof(std::complex<PrecisionT>) * 8);

using np_arr_c = py::array_t<std::complex<ParamT>, py::array::c_style>;

std::string class_name;

class_name = "SparseHamiltonianC" + bitsize;
py::class_<SparseHamiltonian<StateVectorT>,
std::shared_ptr<SparseHamiltonian<StateVectorT>>,
Observable<StateVectorT>>(m, class_name.c_str(),
py::module_local())
.def(py::init([](const np_arr_c &data,
const std::vector<std::size_t> &indices,
const std::vector<std::size_t> &indptr,
const std::vector<std::size_t> &wires) {
using ComplexT = typename StateVectorT::ComplexT;
const py::buffer_info buffer_data = data.request();
const auto *data_ptr = static_cast<ComplexT *>(buffer_data.ptr);

return SparseHamiltonian<StateVectorT>{
std::vector<ComplexT>({data_ptr, data_ptr + data.size()}),
indices, indptr, wires};
}))
.def("__repr__", &SparseHamiltonian<StateVectorT>::getObsName)
.def("get_wires", &SparseHamiltonian<StateVectorT>::getWires,
"Get wires of observables")
.def(
"__eq__",
[](const SparseHamiltonian<StateVectorT> &self,
py::handle other) -> bool {
if (!py::isinstance<SparseHamiltonian<StateVectorT>>(other)) {
return false;
}
auto other_cast = other.cast<SparseHamiltonian<StateVectorT>>();
return self == other_cast;
},
"Compare two observables");
}

/**
* @brief Register backend specific adjoint Jacobian methods.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ void registerBackendSpecificMeasurements(PyClass &pyclass) {
});
}

/**
* @brief Register backend specific observables.
*
* @tparam StateVectorT
* @param m Pybind module
*/
template <class StateVectorT>
void registerBackendSpecificObservables([[maybe_unused]] py::module_ &m) {}

/**
* @brief Register Vector Jacobian Product.
*/
Expand Down

0 comments on commit dccfe3e

Please sign in to comment.