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

Patch Measurements.probs(wires) to Measurements.probs() when called with all wires #744

Merged
merged 9 commits into from
May 29, 2024
4 changes: 4 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
* Changed the name of `lightning.tensor` to `default.tensor` with the `quimb` backend.
[(#719)](https://github.com/PennyLaneAI/pennylane-lightning/pull/719)

* Patch the C++ `Measurements.probs(wires)` method in Lightning-Qubit and Lighnting-Kokkos to `Measurements.probs()` when called with all wires.
vincentmr marked this conversation as resolved.
Show resolved Hide resolved
This will trigger a more optimized implementation for calculating the probabilities of the entire system.
[(#744)](https://github.com/PennyLaneAI/pennylane-lightning/pull/744)

### Documentation

### Bug fixes
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.37.0-dev20"
__version__ = "0.37.0-dev21"
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ class Measurements final
* observables.
*
* @tparam functor_t Expectation value functor class for Kokkos dispatcher.
* @tparam nqubits Number of wires.
* @tparam num_wires Number of wires.
* @param wires Wires to apply the observable to.
*/
template <template <class> class functor_t, int num_wires>
PrecisionT applyExpValNamedFunctor(const std::vector<std::size_t> &wires) {
auto applyExpValNamedFunctor(const std::vector<std::size_t> &wires)
-> PrecisionT {
vincentmr marked this conversation as resolved.
Show resolved Hide resolved
if constexpr (num_wires > 0)
PL_ASSERT(wires.size() == num_wires);

Expand All @@ -101,13 +102,14 @@ class Measurements final
* matrix-valued operator.
*
* @tparam functor_t Expectation value functor class for Kokkos dispatcher.
* @tparam nqubits Number of wires.
* @tparam num_wires Number of wires.
* @param matrix Matrix (linearized into a KokkosVector).
* @param wires Wires to apply the observable to.
*/
template <template <class> class functor_t, int num_wires>
PrecisionT applyExpValFunctor(const KokkosVector matrix,
const std::vector<std::size_t> &wires) {
auto applyExpValFunctor(const KokkosVector matrix,
const std::vector<std::size_t> &wires)
-> PrecisionT {
PL_ASSERT(wires.size() == num_wires);
const std::size_t num_qubits = this->_statevector.getNumQubits();
Kokkos::View<ComplexT *> arr_data = this->_statevector.getView();
Expand Down Expand Up @@ -178,26 +180,25 @@ class Measurements final
/**
* @brief Calculate expectation value for a general Observable.
*
* @param ob Observable.
* @param obs An Observable object.
* @return Expectation value with respect to the given observable.
*/
PrecisionT expval(const Observable<StateVectorT> &ob) {
auto expval(const Observable<StateVectorT> &obs) -> PrecisionT {
StateVectorT ob_sv{this->_statevector};
ob.applyInPlace(ob_sv);
obs.applyInPlace(ob_sv);
return getRealOfComplexInnerProduct(this->_statevector.getView(),
ob_sv.getView());
}

/**
* @brief Calculate expectation value for a HermitianObs.
*
* @param ob HermitianObs.
* @param obs A HermitianObs object.
* @return Expectation value with respect to the given observable.
*/
PrecisionT
expval(const Pennylane::LightningKokkos::Observables::HermitianObs<
StateVectorT> &ob) {
return expval(ob.getMatrix(), ob.getWires());
auto expval(const Pennylane::LightningKokkos::Observables::HermitianObs<
StateVectorT> &obs) -> PrecisionT {
return expval(obs.getMatrix(), obs.getWires());
}

/**
Expand All @@ -207,8 +208,8 @@ class Measurements final
* @param wires Wires where to apply the operator.
* @return Floating point expected value of the observable.
*/
PrecisionT expval(const std::vector<ComplexT> &matrix_,
const std::vector<std::size_t> &wires) {
auto expval(const std::vector<ComplexT> &matrix_,
const std::vector<std::size_t> &wires) -> PrecisionT {
PL_ABORT_IF(matrix_.size() != exp2(2 * wires.size()),
"The size of matrix does not match with the given "
"number of wires");
Expand All @@ -225,8 +226,8 @@ class Measurements final
* @param wires Wires where to apply the operator.
* @return Floating point expected value of the observable.
*/
PrecisionT expval(const std::string &operation,
const std::vector<std::size_t> &wires) {
auto expval(const std::string &operation,
const std::vector<std::size_t> &wires) -> PrecisionT {
switch (expval_funcs_[operation]) {
case ExpValFunc::Identity:
return applyExpValNamedFunctor<getExpectationValueIdentityFunctor,
Expand Down Expand Up @@ -260,9 +261,9 @@ class Measurements final
* observables.
*/
template <typename op_type>
std::vector<PrecisionT>
expval(const std::vector<op_type> &operations_list,
const std::vector<std::vector<std::size_t>> &wires_list) {
auto expval(const std::vector<op_type> &operations_list,
const std::vector<std::vector<std::size_t>> &wires_list)
-> std::vector<PrecisionT> {
PL_ABORT_IF(
(operations_list.size() != wires_list.size()),
"The lengths of the list of operations and wires do not match.");
Expand All @@ -279,9 +280,9 @@ class Measurements final
/**
* @brief Expectation value for a Observable with shots
*
* @param obs Observable.
* @param obs An Observable object.
* @param num_shots Number of shots.
* @param shots_range Vector of shot number to measurement.
* @param shot_range Vector of shot number to measurement.
* @return Floating point expected value of the observable.
*/

Expand Down Expand Up @@ -335,12 +336,12 @@ class Measurements final
/**
* @brief Calculate variance of a general Observable.
*
* @param ob Observable.
* @param obs An Observable object.
* @return Variance with respect to the given observable.
*/
auto var(const Observable<StateVectorT> &ob) -> PrecisionT {
auto var(const Observable<StateVectorT> &obs) -> PrecisionT {
StateVectorT ob_sv{this->_statevector};
ob.applyInPlace(ob_sv);
obs.applyInPlace(ob_sv);

const PrecisionT mean_square =
getRealOfComplexInnerProduct(ob_sv.getView(), ob_sv.getView());
Expand All @@ -358,8 +359,8 @@ class Measurements final
* @param wires Wires where to apply the operator.
* @return Floating point with the variance of the observable.
*/
PrecisionT var(const std::string &operation,
const std::vector<std::size_t> &wires) {
auto var(const std::string &operation,
const std::vector<std::size_t> &wires) -> PrecisionT {
StateVectorT ob_sv{this->_statevector};
ob_sv.applyOperation(operation, wires);

Expand All @@ -373,14 +374,14 @@ class Measurements final
};

/**
* @brief Variance of an observable.
* @brief Variance of a Hermitian matrix.
*
* @param matrix Square matrix in row-major order.
* @param wires Wires where to apply the operator.
* @return Floating point with the variance of the observable.
*/
PrecisionT var(const std::vector<ComplexT> &matrix,
const std::vector<std::size_t> &wires) {
auto var(const std::vector<ComplexT> &matrix,
const std::vector<std::size_t> &wires) -> PrecisionT {
StateVectorT ob_sv{this->_statevector};
ob_sv.applyMatrix(matrix, wires);

Expand All @@ -404,9 +405,9 @@ class Measurements final
observables.
*/
template <typename op_type>
std::vector<PrecisionT>
var(const std::vector<op_type> &operations_list,
const std::vector<std::vector<std::size_t>> &wires_list) {
auto var(const std::vector<op_type> &operations_list,
const std::vector<std::vector<std::size_t>> &wires_list)
-> std::vector<PrecisionT> {
PL_ABORT_IF(
(operations_list.size() != wires_list.size()),
"The lengths of the list of operations and wires do not match.");
Expand Down Expand Up @@ -437,9 +438,9 @@ class Measurements final
* @return Floating point with the variance of the sparse Hamiltonian.
*/
template <class index_type>
PrecisionT var(const index_type *row_map_ptr, const index_type row_map_size,
const index_type *entries_ptr, const ComplexT *values_ptr,
const index_type numNNZ) {
auto var(const index_type *row_map_ptr, const index_type row_map_size,
const index_type *entries_ptr, const ComplexT *values_ptr,
const index_type numNNZ) -> PrecisionT {
PL_ABORT_IF(
(this->_statevector.getLength() != (std::size_t(row_map_size) - 1)),
"Statevector and Hamiltonian have incompatible sizes.");
Expand Down Expand Up @@ -506,11 +507,18 @@ class Measurements final
* @return Floating point std::vector with probabilities.
* The basis columns are rearranged according to wires.
*/
std::vector<PrecisionT> probs(const std::vector<std::size_t> &wires) {
auto probs(const std::vector<std::size_t> &wires)
-> std::vector<PrecisionT> {
PL_ABORT_IF_NOT(
std::is_sorted(wires.cbegin(), wires.cend()),
"LightningKokkos does not currently support out-of-order wire "
"indices with probability calculations");

// If all wires are requested, dispatch to `this->probs()`
if (wires.size() == this->_statevector.getNumQubits()) {
maliasadi marked this conversation as resolved.
Show resolved Hide resolved
return this->probs();
}

maliasadi marked this conversation as resolved.
Show resolved Hide resolved
using MDPolicyType_2D =
Kokkos::MDRangePolicy<Kokkos::Rank<2, Kokkos::Iterate::Left>>;

Expand Down Expand Up @@ -624,8 +632,8 @@ class Measurements final
* @return Floating point std::vector with probabilities
* in lexicographic order.
*/
std::vector<PrecisionT> probs(const Observable<StateVectorT> &obs,
std::size_t num_shots = 0) {
auto probs(const Observable<StateVectorT> &obs, std::size_t num_shots = 0)
-> std::vector<PrecisionT> {
return BaseType::probs(obs, num_shots);
}

Expand All @@ -636,22 +644,22 @@ class Measurements final
*
* @return Floating point std::vector with probabilities.
*/
std::vector<PrecisionT> probs(std::size_t num_shots) {
auto probs(std::size_t num_shots) -> std::vector<PrecisionT> {
return BaseType::probs(num_shots);
}

/**
* @brief Probabilities with shot-noise for a subset of the full system.
*
* @param num_shots Number of shots.
* @param wires Wires will restrict probabilities to a subset
* of the full system.
* @param num_shots Number of shots.
*
* @return Floating point std::vector with probabilities.
*/

std::vector<PrecisionT> probs(const std::vector<std::size_t> &wires,
std::size_t num_shots) {
auto probs(const std::vector<std::size_t> &wires, std::size_t num_shots)
-> std::vector<PrecisionT> {
PL_ABORT_IF_NOT(
std::is_sorted(wires.cbegin(), wires.cend()),
"LightningKokkos does not currently support out-of-order wire "
Expand Down
Loading
Loading