From c659ba5518d479ba9962b8c11051c86d2e7c3bfa Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 07:58:16 -0400 Subject: [PATCH 01/34] move catalyst files as is --- .../catalyst/LightningKokkosObsManager.hpp | 196 +++++++ .../catalyst/LightningKokkosSimulator.cpp | 542 ++++++++++++++++++ .../catalyst/LightningKokkosSimulator.hpp | 97 ++++ 3 files changed, 835 insertions(+) create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp new file mode 100644 index 0000000000..0a7079e5c8 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp @@ -0,0 +1,196 @@ +// Copyright 2023 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include "Types.h" +#include "Utils.hpp" + +#include "ObservablesKokkos.hpp" + +namespace Catalyst::Runtime::Simulator { + +/** + * @brief The LightningKokkosObsManager caches observables of a program at runtime + * and maps each one to a const unique index (`int64_t`) in the scope + * of the global context manager. + */ +template class LightningKokkosObsManager { + private: + using VectorStateT = Pennylane::LightningKokkos::StateVectorKokkos; + using ObservableClassName = Pennylane::Observables::Observable; + using ObservablePairType = std::pair, ObsType>; + std::vector observables_{}; + + public: + LightningKokkosObsManager() = default; + ~LightningKokkosObsManager() = default; + + LightningKokkosObsManager(const LightningKokkosObsManager &) = delete; + LightningKokkosObsManager &operator=(const LightningKokkosObsManager &) = delete; + LightningKokkosObsManager(LightningKokkosObsManager &&) = delete; + LightningKokkosObsManager &operator=(LightningKokkosObsManager &&) = delete; + + /** + * @brief A helper function to clear constructed observables in the program. + */ + void clear() { this->observables_.clear(); } + + /** + * @brief Check the validity of observable keys. + * + * @param obsKeys The vector of observable keys + * @return bool + */ + [[nodiscard]] auto isValidObservables(const std::vector &obsKeys) const -> bool + { + return std::all_of(obsKeys.begin(), obsKeys.end(), [this](auto i) { + return (i >= 0 && static_cast(i) < this->observables_.size()); + }); + } + + /** + * @brief Get the constructed observable instance. + * + * @param key The observable key + * @return std::shared_ptr + */ + [[nodiscard]] auto getObservable(ObsIdType key) -> std::shared_ptr + { + RT_FAIL_IF(!this->isValidObservables({key}), "Invalid observable key"); + return std::get<0>(this->observables_[key]); + } + + /** + * @brief Get the number of observables. + * + * @return size_t + */ + [[nodiscard]] auto numObservables() const -> size_t { return this->observables_.size(); } + + /** + * @brief Create and cache a new NamedObs instance. + * + * @param obsId The named observable id of type ObsId + * @param wires The vector of wires the observable acts on + * @return ObsIdType + */ + [[nodiscard]] auto createNamedObs(ObsId obsId, const std::vector &wires) -> ObsIdType + { + auto &&obs_str = + std::string(Lightning::lookup_obs( + Lightning::simulator_observable_support, obsId)); + + this->observables_.push_back(std::make_pair( + std::make_shared>( + obs_str, wires), + ObsType::Basic)); + return static_cast(this->observables_.size() - 1); + } + + /** + * @brief Create and cache a new HermitianObs instance. + * + * @param matrix The row-wise Hermitian matrix + * @param wires The vector of wires the observable acts on + * @return ObsIdType + */ + [[nodiscard]] auto createHermitianObs(const std::vector> &matrix, + const std::vector &wires) -> ObsIdType + { + std::vector> matrix_k; + matrix_k.reserve(matrix.size()); + for (const auto &elem : matrix) { + matrix_k.push_back(static_cast>(elem)); + } + + this->observables_.push_back(std::make_pair( + std::make_shared>( + Pennylane::LightningKokkos::Observables::HermitianObs{matrix_k, + wires}), + ObsType::Basic)); + + return static_cast(this->observables_.size() - 1); + } + + /** + * @brief Create and cache a new TensorProd instance. + * + * @param obsKeys The vector of observable keys + * @return ObsIdType + */ + [[nodiscard]] auto createTensorProdObs(const std::vector &obsKeys) -> ObsIdType + { + const auto key_size = obsKeys.size(); + const auto obs_size = this->observables_.size(); + + std::vector> obs_vec; + obs_vec.reserve(key_size); + + for (const auto &key : obsKeys) { + RT_FAIL_IF(static_cast(key) >= obs_size || key < 0, "Invalid observable key"); + + auto &&[obs, type] = this->observables_[key]; + obs_vec.push_back(obs); + } + + this->observables_.push_back(std::make_pair( + Pennylane::LightningKokkos::Observables::TensorProdObs::create(obs_vec), + ObsType::TensorProd)); + + return static_cast(obs_size); + } + + /** + * @brief Create and cache a new HamiltonianObs instance. + * + * @param coeffs The vector of coefficients + * @param obsKeys The vector of observable keys + * @return ObsIdType + */ + [[nodiscard]] auto createHamiltonianObs(const std::vector &coeffs, + const std::vector &obsKeys) -> ObsIdType + { + const auto key_size = obsKeys.size(); + const auto obs_size = this->observables_.size(); + + RT_FAIL_IF(key_size != coeffs.size(), + "Incompatible list of observables and coefficients; " + "Number of observables and number of coefficients must be equal"); + + std::vector> obs_vec; + obs_vec.reserve(key_size); + + for (auto key : obsKeys) { + RT_FAIL_IF(static_cast(key) >= obs_size || key < 0, "Invalid observable key"); + + auto &&[obs, type] = this->observables_[key]; + obs_vec.push_back(obs); + } + + this->observables_.push_back(std::make_pair( + std::make_shared>( + Pennylane::LightningKokkos::Observables::Hamiltonian( + coeffs, std::move(obs_vec))), + ObsType::Hamiltonian)); + + return static_cast(obs_size); + } +}; +} // namespace Catalyst::Runtime::Simulator diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp new file mode 100644 index 0000000000..036ef79b6b --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp @@ -0,0 +1,542 @@ +// Copyright 2022-2023 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "LightningKokkosSimulator.hpp" + +namespace Catalyst::Runtime::Simulator { + +auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType +{ + const size_t num_qubits = this->device_sv->getNumQubits(); + + if (!num_qubits) { + this->device_sv = std::make_unique(1); + return this->qubit_manager.Allocate(num_qubits); + } + + std::vector> data = this->device_sv->getDataVector(); + const size_t dsize = data.size(); + data.resize(dsize << 1UL); + + auto src = data.begin(); + std::advance(src, dsize - 1); + + for (auto dst = data.end() - 2; src != data.begin(); + std::advance(src, -1), std::advance(dst, -2)) { + *dst = std::move(*src); + *src = Kokkos::complex(.0, .0); + } + + this->device_sv = std::make_unique(data); + return this->qubit_manager.Allocate(num_qubits); +} + +auto LightningKokkosSimulator::AllocateQubits(size_t num_qubits) -> std::vector +{ + if (!num_qubits) { + return {}; + } + + // at the first call when num_qubits == 0 + if (!this->GetNumQubits()) { + this->device_sv = std::make_unique(num_qubits); + return this->qubit_manager.AllocateRange(0, num_qubits); + } + + std::vector result(num_qubits); + std::generate_n(result.begin(), num_qubits, [this]() { return AllocateQubit(); }); + return result; +} + +void LightningKokkosSimulator::ReleaseQubit(QubitIdType q) { this->qubit_manager.Release(q); } + +void LightningKokkosSimulator::ReleaseAllQubits() +{ + this->qubit_manager.ReleaseAll(); + this->device_sv = std::make_unique(0); // reset the device +} + +auto LightningKokkosSimulator::GetNumQubits() const -> size_t +{ + return this->device_sv->getNumQubits(); +} + +void LightningKokkosSimulator::StartTapeRecording() +{ + RT_FAIL_IF(this->tape_recording, "Cannot re-activate the cache manager"); + this->tape_recording = true; + this->cache_manager.Reset(); +} + +void LightningKokkosSimulator::StopTapeRecording() +{ + RT_FAIL_IF(!this->tape_recording, "Cannot stop an already stopped cache manager"); + this->tape_recording = false; +} + +auto LightningKokkosSimulator::CacheManagerInfo() + -> std::tuple, std::vector> +{ + return {this->cache_manager.getNumOperations(), this->cache_manager.getNumObservables(), + this->cache_manager.getNumParams(), this->cache_manager.getOperationsNames(), + this->cache_manager.getObservablesKeys()}; +} + +void LightningKokkosSimulator::SetDeviceShots(size_t shots) { this->device_shots = shots; } + +auto LightningKokkosSimulator::GetDeviceShots() const -> size_t { return this->device_shots; } + +void LightningKokkosSimulator::PrintState() +{ + using std::cout; + using std::endl; + using UnmanagedComplexHostView = Kokkos::View *, Kokkos::HostSpace, + Kokkos::MemoryTraits>; + + const size_t num_qubits = this->device_sv->getNumQubits(); + const size_t size = Pennylane::Util::exp2(num_qubits); + + std::vector> state(size, {0.0, 0.0}); + auto *state_kptr = reinterpret_cast *>(state.data()); + auto device_data = this->device_sv->getView(); + Kokkos::deep_copy(UnmanagedComplexHostView(state_kptr, size), device_data); + + size_t idx = 0; + cout << "*** State-Vector of Size " << size << " ***" << endl; + cout << "["; + for (; idx < size - 1; idx++) { + cout << state[idx] << ", "; + } + cout << state[idx] << "]" << endl; +} + +auto LightningKokkosSimulator::Zero() const -> Result +{ + return const_cast(&GLOBAL_RESULT_FALSE_CONST); +} + +auto LightningKokkosSimulator::One() const -> Result +{ + return const_cast(&GLOBAL_RESULT_TRUE_CONST); +} + +void LightningKokkosSimulator::NamedOperation(const std::string &name, + const std::vector ¶ms, + const std::vector &wires, bool inverse, + const std::vector &controlled_wires, + const std::vector &controlled_values) +{ + RT_FAIL_IF(!controlled_wires.empty() || !controlled_values.empty(), + "LightningKokkos does not support native quantum control."); + + // Check the validity of number of qubits and parameters + RT_FAIL_IF(!isValidQubits(wires), "Given wires do not refer to qubits"); + RT_FAIL_IF(!isValidQubits(controlled_wires), "Given controlled wires do not refer to qubits"); + + // Convert wires to device wires + auto &&dev_wires = getDeviceWires(wires); + + // Update the state-vector + this->device_sv->applyOperation(name, dev_wires, inverse, params); + + // Update tape caching if required + if (this->tape_recording) { + this->cache_manager.addOperation(name, params, dev_wires, inverse, {}, + {/*controlled_wires*/}, {/*controlled_values*/}); + } +} + +void LightningKokkosSimulator::MatrixOperation(const std::vector> &matrix, + const std::vector &wires, bool inverse, + const std::vector &controlled_wires, + const std::vector &controlled_values) +{ + using UnmanagedComplexHostView = Kokkos::View *, Kokkos::HostSpace, + Kokkos::MemoryTraits>; + + // TODO: Remove when controlled wires API is supported + RT_FAIL_IF(!controlled_wires.empty() || !controlled_values.empty(), + "LightningKokkos device does not support native quantum control."); + RT_FAIL_IF(!isValidQubits(wires), "Given wires do not refer to qubits"); + RT_FAIL_IF(!isValidQubits(controlled_wires), "Given controlled wires do not refer to qubits"); + + // Convert wires to device wires + auto &&dev_wires = getDeviceWires(wires); + + std::vector> matrix_kok; + matrix_kok.resize(matrix.size()); + std::transform(matrix.begin(), matrix.end(), matrix_kok.begin(), + [](auto c) { return static_cast>(c); }); + + Kokkos::View *> gate_matrix("gate_matrix", matrix_kok.size()); + Kokkos::deep_copy(gate_matrix, UnmanagedComplexHostView(matrix_kok.data(), matrix_kok.size())); + + // Update the state-vector + this->device_sv->applyMultiQubitOp(gate_matrix, dev_wires, inverse); + + // Update tape caching if required + if (this->tape_recording) { + this->cache_manager.addOperation("QubitUnitary", {}, dev_wires, inverse, matrix_kok, + {/*controlled_wires*/}, {/*controlled_values*/}); + } +} + +auto LightningKokkosSimulator::Observable(ObsId id, const std::vector> &matrix, + const std::vector &wires) -> ObsIdType +{ + RT_FAIL_IF(wires.size() > this->GetNumQubits(), "Invalid number of wires"); + RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires"); + + auto &&dev_wires = getDeviceWires(wires); + + if (id == ObsId::Hermitian) { + return this->obs_manager.createHermitianObs(matrix, dev_wires); + } + + return this->obs_manager.createNamedObs(id, dev_wires); +} + +auto LightningKokkosSimulator::TensorObservable(const std::vector &obs) -> ObsIdType +{ + return this->obs_manager.createTensorProdObs(obs); +} + +auto LightningKokkosSimulator::HamiltonianObservable(const std::vector &coeffs, + const std::vector &obs) -> ObsIdType +{ + return this->obs_manager.createHamiltonianObs(coeffs, obs); +} + +auto LightningKokkosSimulator::Expval(ObsIdType obsKey) -> double +{ + RT_FAIL_IF(!this->obs_manager.isValidObservables({obsKey}), + "Invalid key for cached observables"); + + // update tape caching + if (this->tape_recording) { + cache_manager.addObservable(obsKey, MeasurementsT::Expval); + } + + auto &&obs = this->obs_manager.getObservable(obsKey); + + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + + return device_shots ? m.expval(*obs, device_shots, {}) : m.expval(*obs); +} + +auto LightningKokkosSimulator::Var(ObsIdType obsKey) -> double +{ + RT_FAIL_IF(!this->obs_manager.isValidObservables({obsKey}), + "Invalid key for cached observables"); + + // update tape caching + if (this->tape_recording) { + this->cache_manager.addObservable(obsKey, MeasurementsT::Var); + } + + auto &&obs = this->obs_manager.getObservable(obsKey); + + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + + return device_shots ? m.var(*obs, device_shots) : m.var(*obs); +} + +void LightningKokkosSimulator::State(DataView, 1> &state) +{ + using UnmanagedComplexHostView = Kokkos::View *, Kokkos::HostSpace, + Kokkos::MemoryTraits>; + + const size_t num_qubits = this->device_sv->getNumQubits(); + const size_t size = Pennylane::Util::exp2(num_qubits); + RT_FAIL_IF(state.size() != size, "Invalid size for the pre-allocated state vector"); + + // create a temporary buffer to copy the underlying state-vector to + std::vector> buffer(size); + auto *state_kptr = reinterpret_cast *>(buffer.data()); + + // copy data from device to host + auto device_data = this->device_sv->getView(); + Kokkos::deep_copy(UnmanagedComplexHostView(state_kptr, size), device_data); + + // move data to state leveraging MemRefIter + std::move(buffer.begin(), buffer.end(), state.begin()); +} + +void LightningKokkosSimulator::Probs(DataView &probs) +{ + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + auto &&dv_probs = device_shots ? m.probs(device_shots) : m.probs(); + + RT_FAIL_IF(probs.size() != dv_probs.size(), "Invalid size for the pre-allocated probabilities"); + + std::move(dv_probs.begin(), dv_probs.end(), probs.begin()); +} + +void LightningKokkosSimulator::PartialProbs(DataView &probs, + const std::vector &wires) +{ + const size_t numWires = wires.size(); + const size_t numQubits = this->GetNumQubits(); + + RT_FAIL_IF(numWires > numQubits, "Invalid number of wires"); + RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); + + auto dev_wires = getDeviceWires(wires); + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + auto &&dv_probs = device_shots ? m.probs(dev_wires, device_shots) : m.probs(dev_wires); + + RT_FAIL_IF(probs.size() != dv_probs.size(), + "Invalid size for the pre-allocated partial-probabilities"); + + std::move(dv_probs.begin(), dv_probs.end(), probs.begin()); +} + +void LightningKokkosSimulator::Sample(DataView &samples, size_t shots) +{ + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + // PL-Lightning-Kokkos generates samples using the alias method. + // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling + auto li_samples = m.generate_samples(shots); + + RT_FAIL_IF(samples.size() != li_samples.size(), "Invalid size for the pre-allocated samples"); + + const size_t numQubits = this->GetNumQubits(); + + // The lightning samples are layed out as a single vector of size + // shots*qubits, where each element represents a single bit. The + // corresponding shape is (shots, qubits). Gather the desired bits + // corresponding to the input wires into a bitstring. + auto samplesIter = samples.begin(); + for (size_t shot = 0; shot < shots; shot++) { + for (size_t wire = 0; wire < numQubits; wire++) { + *(samplesIter++) = static_cast(li_samples[shot * numQubits + wire]); + } + } +} +void LightningKokkosSimulator::PartialSample(DataView &samples, + const std::vector &wires, size_t shots) +{ + const size_t numWires = wires.size(); + const size_t numQubits = this->GetNumQubits(); + + RT_FAIL_IF(numWires > numQubits, "Invalid number of wires"); + RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); + RT_FAIL_IF(samples.size() != shots * numWires, + "Invalid size for the pre-allocated partial-samples"); + + // get device wires + auto &&dev_wires = getDeviceWires(wires); + + // generate_samples is a member function of the MeasuresKokkos class. + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + + // PL-Lightning-Kokkos generates samples using the alias method. + // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling + auto li_samples = m.generate_samples(shots); + + // The lightning samples are layed out as a single vector of size + // shots*qubits, where each element represents a single bit. The + // corresponding shape is (shots, qubits). Gather the desired bits + // corresponding to the input wires into a bitstring. + auto samplesIter = samples.begin(); + for (size_t shot = 0; shot < shots; shot++) { + for (auto wire : dev_wires) { + *(samplesIter++) = static_cast(li_samples[shot * numQubits + wire]); + } + } +} + +void LightningKokkosSimulator::Counts(DataView &eigvals, DataView &counts, + size_t shots) +{ + const size_t numQubits = this->GetNumQubits(); + const size_t numElements = 1U << numQubits; + + RT_FAIL_IF(eigvals.size() != numElements || counts.size() != numElements, + "Invalid size for the pre-allocated counts"); + + // generate_samples is a member function of the MeasuresKokkos class. + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + + // PL-Lightning-Kokkos generates samples using the alias method. + // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling + auto li_samples = m.generate_samples(shots); + + // Fill the eigenvalues with the integer representation of the corresponding + // computational basis bitstring. In the future, eigenvalues can also be + // obtained from an observable, hence the bitstring integer is stored as a + // double. + std::iota(eigvals.begin(), eigvals.end(), 0); + std::fill(counts.begin(), counts.end(), 0); + + // The lightning samples are layed out as a single vector of size + // shots*qubits, where each element represents a single bit. The + // corresponding shape is (shots, qubits). Gather the bits of all qubits + // into a bitstring. + for (size_t shot = 0; shot < shots; shot++) { + std::bitset basisState; + size_t idx = numQubits; + for (size_t wire = 0; wire < numQubits; wire++) { + basisState[--idx] = li_samples[shot * numQubits + wire]; + } + counts(static_cast(basisState.to_ulong())) += 1; + } +} + +void LightningKokkosSimulator::PartialCounts(DataView &eigvals, + DataView &counts, + const std::vector &wires, size_t shots) +{ + const size_t numWires = wires.size(); + const size_t numQubits = this->GetNumQubits(); + const size_t numElements = 1U << numWires; + + RT_FAIL_IF(numWires > numQubits, "Invalid number of wires"); + RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); + RT_FAIL_IF((eigvals.size() != numElements || counts.size() != numElements), + "Invalid size for the pre-allocated partial-counts"); + + // get device wires + auto &&dev_wires = getDeviceWires(wires); + + // generate_samples is a member function of the MeasuresKokkos class. + Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + + // PL-Lightning-Kokkos generates samples using the alias method. + // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling + auto li_samples = m.generate_samples(shots); + + // Fill the eigenvalues with the integer representation of the corresponding + // computational basis bitstring. In the future, eigenvalues can also be + // obtained from an observable, hence the bitstring integer is stored as a + // double. + std::iota(eigvals.begin(), eigvals.end(), 0); + std::fill(counts.begin(), counts.end(), 0); + + // The lightning samples are layed out as a single vector of size + // shots*qubits, where each element represents a single bit. The + // corresponding shape is (shots, qubits). Gather the desired bits + // corresponding to the input wires into a bitstring. + for (size_t shot = 0; shot < shots; shot++) { + std::bitset basisState; + size_t idx = dev_wires.size(); + for (auto wire : dev_wires) { + basisState[--idx] = li_samples[shot * numQubits + wire]; + } + counts(static_cast(basisState.to_ulong())) += 1; + } +} + +auto LightningKokkosSimulator::Measure(QubitIdType wire, std::optional postselect) + -> Result +{ + // get a measurement + std::vector wires = {reinterpret_cast(wire)}; + + std::vector probs(1U << wires.size()); + DataView buffer_view(probs); + auto device_shots = GetDeviceShots(); + SetDeviceShots(0); + PartialProbs(buffer_view, wires); + SetDeviceShots(device_shots); + + // It represents the measured result, true for 1, false for 0 + bool mres = Lightning::simulateDraw(probs, postselect); + auto dev_wires = getDeviceWires(wires); + this->device_sv->collapse(dev_wires[0], mres ? 1 : 0); + return mres ? this->One() : this->Zero(); +} + +void LightningKokkosSimulator::Gradient(std::vector> &gradients, + const std::vector &trainParams) +{ + const bool tp_empty = trainParams.empty(); + const size_t num_observables = this->cache_manager.getNumObservables(); + const size_t num_params = this->cache_manager.getNumParams(); + const size_t num_train_params = tp_empty ? num_params : trainParams.size(); + const size_t jac_size = num_train_params * this->cache_manager.getNumObservables(); + + if (!jac_size) { + return; + } + + RT_FAIL_IF(gradients.size() != num_observables, "Invalid number of pre-allocated gradients"); + + auto &&obs_callees = this->cache_manager.getObservablesCallees(); + bool is_valid_measurements = + std::all_of(obs_callees.begin(), obs_callees.end(), + [](const auto &m) { return m == MeasurementsT::Expval; }); + RT_FAIL_IF(!is_valid_measurements, + "Unsupported measurements to compute gradient; " + "Adjoint differentiation method only supports expectation return type"); + + // Create OpsData + auto &&ops_names = this->cache_manager.getOperationsNames(); + auto &&ops_params = this->cache_manager.getOperationsParameters(); + auto &&ops_wires = this->cache_manager.getOperationsWires(); + auto &&ops_inverses = this->cache_manager.getOperationsInverses(); + auto &&ops_matrices = this->cache_manager.getOperationsMatrices(); + auto &&ops_controlled_wires = this->cache_manager.getOperationsControlledWires(); + auto &&ops_controlled_values = this->cache_manager.getOperationsControlledValues(); + + const auto &&ops = Pennylane::Algorithms::OpsData( + ops_names, ops_params, ops_wires, ops_inverses, ops_matrices, ops_controlled_wires, + ops_controlled_values); + + // Create the vector of observables + auto &&obs_keys = this->cache_manager.getObservablesKeys(); + std::vector>> obs_vec; + obs_vec.reserve(obs_keys.size()); + for (auto idx : obs_keys) { + obs_vec.emplace_back(this->obs_manager.getObservable(idx)); + } + + std::vector all_params; + if (tp_empty) { + all_params.reserve(num_params); + for (size_t i = 0; i < num_params; i++) { + all_params.push_back(i); + } + } + + auto &&state = this->device_sv->getDataVector(); + + // construct the Jacobian data + Pennylane::Algorithms::JacobianData tape{ + num_params, state.size(), state.data(), obs_vec, ops, tp_empty ? all_params : trainParams}; + + Pennylane::LightningKokkos::Algorithms::AdjointJacobian adj; + std::vector jacobian(jac_size, 0); + adj.adjointJacobian(std::span{jacobian}, tape, + /* ref_data */ *this->device_sv, + /* apply_operations */ false); + + std::vector cur_buffer(num_train_params); + auto begin_loc_iter = jacobian.begin(); + for (size_t obs_idx = 0; obs_idx < num_observables; obs_idx++) { + RT_ASSERT(begin_loc_iter != jacobian.end()); + RT_ASSERT(num_train_params <= gradients[obs_idx].size()); + std::move(begin_loc_iter, begin_loc_iter + num_train_params, cur_buffer.begin()); + std::move(cur_buffer.begin(), cur_buffer.end(), gradients[obs_idx].begin()); + begin_loc_iter += num_train_params; + } +} + +} // namespace Catalyst::Runtime::Simulator + +GENERATE_DEVICE_FACTORY(LightningKokkosSimulator, + Catalyst::Runtime::Simulator::LightningKokkosSimulator); diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp new file mode 100644 index 0000000000..2abf8bc847 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp @@ -0,0 +1,97 @@ +// Copyright 2022-2023 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#define __device_lightning_kokkos + +#include +#include +#include +#include +#include +#include +#include + +#include "AdjointJacobianKokkos.hpp" +#include "MeasurementsKokkos.hpp" +#include "StateVectorKokkos.hpp" + +#include "CacheManager.hpp" +#include "Exception.hpp" +#include "LightningKokkosObsManager.hpp" +#include "QuantumDevice.hpp" +#include "QubitManager.hpp" +#include "Utils.hpp" + +namespace Catalyst::Runtime::Simulator { +class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { + private: + using StateVectorT = Pennylane::LightningKokkos::StateVectorKokkos; + + // static constants for RESULT values + static constexpr bool GLOBAL_RESULT_TRUE_CONST = true; + static constexpr bool GLOBAL_RESULT_FALSE_CONST = false; + + Catalyst::Runtime::QubitManager qubit_manager{}; + Catalyst::Runtime::CacheManager> cache_manager{}; + bool tape_recording{false}; + + size_t device_shots; + + std::unique_ptr device_sv = std::make_unique(0); + LightningKokkosObsManager obs_manager{}; + + inline auto isValidQubit(QubitIdType wire) -> bool + { + return this->qubit_manager.isValidQubitId(wire); + } + + inline auto isValidQubits(const std::vector &wires) -> bool + { + return std::all_of(wires.begin(), wires.end(), + [this](QubitIdType w) { return this->isValidQubit(w); }); + } + + inline auto isValidQubits(size_t numWires, const QubitIdType *wires) -> bool + { + return std::all_of(wires, wires + numWires, + [this](QubitIdType w) { return this->isValidQubit(w); }); + } + + inline auto getDeviceWires(const std::vector &wires) -> std::vector + { + std::vector res; + res.reserve(wires.size()); + std::transform(wires.begin(), wires.end(), std::back_inserter(res), + [this](auto w) { return this->qubit_manager.getDeviceId(w); }); + return res; + } + + public: + explicit LightningKokkosSimulator(const std::string &kwargs = "{}") + { + auto &&args = Catalyst::Runtime::parse_kwargs(kwargs); + device_shots = args.contains("shots") ? static_cast(std::stoll(args["shots"])) : 0; + } + ~LightningKokkosSimulator() = default; + + QUANTUM_DEVICE_DEL_DECLARATIONS(LightningKokkosSimulator); + + QUANTUM_DEVICE_RT_DECLARATIONS; + QUANTUM_DEVICE_QIS_DECLARATIONS; + + auto CacheManagerInfo() + -> std::tuple, std::vector>; +}; +} // namespace Catalyst::Runtime::Simulator From f1d99b3658c31ab5e3e227b906ad858004eab1a8 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:32:53 -0400 Subject: [PATCH 02/34] update year --- .../lightning_kokkos/catalyst/LightningKokkosObsManager.hpp | 2 +- .../lightning_kokkos/catalyst/LightningKokkosSimulator.cpp | 2 +- .../lightning_kokkos/catalyst/LightningKokkosSimulator.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp index 0a7079e5c8..34f008d7a6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp @@ -1,4 +1,4 @@ -// Copyright 2023 Xanadu Quantum Technologies Inc. +// Copyright 2023-2024 Xanadu Quantum Technologies Inc. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp index 036ef79b6b..2e31d917be 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Xanadu Quantum Technologies Inc. +// Copyright 2022-2024 Xanadu Quantum Technologies Inc. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp index 2abf8bc847..eeef798095 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Xanadu Quantum Technologies Inc. +// Copyright 2022-2024 Xanadu Quantum Technologies Inc. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From b384b86edbeeda3f64057d1cfbaad78ecffdf48c Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:34:15 -0400 Subject: [PATCH 03/34] add a CMakeLists file to build against local and GH catalyst TAG --- .../core/src/simulators/lightning_kokkos/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/CMakeLists.txt index 0f8b60c909..76f4874b2c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/CMakeLists.txt @@ -70,6 +70,7 @@ endif() ############################################################################### set(COMPONENT_SUBDIRS algorithms bindings + catalyst gates measurements observables From 84036a44aa07bc88483438d2819210f7d66ecc3c Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:34:42 -0400 Subject: [PATCH 04/34] add the new catalyst directory to the build system --- .../lightning_kokkos/catalyst/CMakeLists.txt | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt new file mode 100644 index 0000000000..db6ba68a5c --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.20) + +project(lightning_kokkos_catalyst LANGUAGES CXX) + +set(CATALYST_FILES LightningKokkosSimulator.cpp CACHE INTERNAL "" FORCE) +add_library(lightning_kokkos_catalyst SHARED ${CATALYST_FILES}) + +include(FetchContent) + +if(CATALYST_SRC_PATH) + if(NOT IS_ABSOLUTE ${CATALYST_SRC_PATH}) + message(FATAL_ERROR " CATALYST_SRC_PATH=${CATALYST_SRC_PATH} must be set to an absolute path") + endif() + if(CATALYST_GIT_TAG) + message(WARN " Setting `CATALYST_SRC_PATH=${CATALYST_SRC_PATH}` overrides `CATALYST_GIT_TAG=${CATALYST_GIT_TAG}`") + endif() + + # Acquire local git hash and use for CATALYST_GIT_TAG + execute_process(COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${CATALYST_SRC_PATH} + OUTPUT_VARIABLE CATALYST_GIT_TAG + ) + message(INFO " Building against local Catalyst - path: ${CATALYST_SRC_PATH} - GIT TAG: ${CATALYST_GIT_TAG}") + + target_include_directories(lightning_kokkos_catalyst PRIVATE ${CATALYST_SRC_PATH}/runtime/lib/backend/common) + target_include_directories(lightning_kokkos_catalyst PRIVATE ${CATALYST_SRC_PATH}/runtime/include) + +else() + if(NOT CATALYST_GIT_TAG) + set(CATALYST_GIT_TAG "main" CACHE STRING "GIT_TAG value to build Catalyst") + endif() + message(INFO " Building against Catalyst GIT TAG ${CATALYST_GIT_TAG}") + + # Fetching /lib/backend/common hpp headers + set(LIB_BACKEND_COMMON_HEADERS CacheManager.hpp + QubitManager.hpp + Utils.hpp + ) + + foreach(HEADER ${LIB_BACKEND_COMMON_HEADERS}) + string(REGEX REPLACE "\\.[^.]*$" "" HEADER_NAME ${HEADER}) + FetchContent_Declare( + ${HEADER_NAME} + URL https://raw.githubusercontent.com/PennyLaneAI/catalyst/${CATALYST_GIT_TAG}/runtime/lib/backend/common/${HEADER} + DOWNLOAD_NO_EXTRACT True + SOURCE_DIR include + ) + + FetchContent_MakeAvailable(${HEADER_NAME}) + endforeach() + + # Fetching include hpp headers + set(INCLUDE_HEADERS DataView.hpp + Exception.hpp + QuantumDevice.hpp + RuntimeCAPI.h + Types.h + ) + + foreach(HEADER ${INCLUDE_HEADERS}) + string(REGEX REPLACE "\\.[^.]*$" "" HEADER_NAME ${HEADER}) + FetchContent_Declare( + ${HEADER_NAME} + URL https://raw.githubusercontent.com/PennyLaneAI/catalyst/${CATALYST_GIT_TAG}/runtime/include/${HEADER} + DOWNLOAD_NO_EXTRACT True + SOURCE_DIR include + ) + + FetchContent_MakeAvailable(${HEADER_NAME}) + endforeach() + + target_include_directories(lightning_kokkos_catalyst PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) + +endif() + +target_link_libraries(lightning_kokkos_catalyst PUBLIC lightning_compile_options + lightning_external_libs + lightning_base + lightning_gates + lightning_utils + lightning_kokkos + lightning_kokkos_algorithms + lightning_kokkos_gates + lightning_kokkos_measurements + lightning_kokkos_utils +) + +if (BUILD_TESTS) + enable_testing() + add_subdirectory("tests") +endif() \ No newline at end of file From 0f363c9068705ccffb07577e20dec395ad0c6190 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:36:06 -0400 Subject: [PATCH 05/34] not today Ringo --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 054ae191d1..46f1c1e8ff 100644 --- a/pennylane_lightning/core/_version.py +++ b/pennylane_lightning/core/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.37.0-dev43" +__version__ = "0.37.0-dev44" From 03b5b8e02b99797985e02c9bc7eab95515bfacf6 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:44:06 -0400 Subject: [PATCH 06/34] empty commit From 55b50dd4b066b6be92c1949f39a2b5421e49861c Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:48:02 -0400 Subject: [PATCH 07/34] update changelog --- .github/CHANGELOG.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 9fe7cf5066..31e517f3b4 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,10 +2,10 @@ ### New features since last release * Implement Python interface to the `lightning.tensor` device. - [(#748)](https://github.com/PennyLaneAI/pennylane-lightning/pull/748) + [(#748)](https://github.com/PennyLaneAI/pennylane-lightning/pull/748) * Add `inverse` support for gate operations in `lightning.tensor` in the C++ layer. - [(#753)](https://github.com/PennyLaneAI/pennylane-lightning/pull/753) + [(#753)](https://github.com/PennyLaneAI/pennylane-lightning/pull/753) * Add `observable` and `expval` support to `cutensornet` backed `lightning.tensor` C++ layer. [(#728)](https://github.com/PennyLaneAI/pennylane-lightning/pull/728) @@ -19,6 +19,9 @@ * Add support for `C(BlockEncode)` to Lightning devices. [(#743)](https://github.com/PennyLaneAI/pennylane-lightning/pull/743) +* Add a Catalyst-specific wrapping class for Lightning Kokkos. + [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) + ### Breaking changes * Removed the `QuimbMPS` class and the corresponding interface/backend from `lightning.tensor`. @@ -42,17 +45,17 @@ [(#763)](https://github.com/PennyLaneAI/pennylane-lightning/pull/763) * Change the type of tensor network objects passed to `ObservablesTNCuda` and `MeasurementsTNCuda` class from `StateTensorT` to `TensorNetT`. - [(#759)](https://github.com/PennyLaneAI/pennylane-lightning/pull/759) - + [(#759)](https://github.com/PennyLaneAI/pennylane-lightning/pull/759) + * Rationalize MCM tests, removing most end-to-end tests from the native MCM test file, but keeping one that validates multiple mid-circuit measurements with any allowed return. [(#754)](https://github.com/PennyLaneAI/pennylane/pull/754) * Refactor C++ library names for `lightning.tensor`. - [(#755)](https://github.com/PennyLaneAI/pennylane-lightning/pull/755) + [(#755)](https://github.com/PennyLaneAI/pennylane-lightning/pull/755) * Set `state_tensor` as `const` for the `MeasurementTNCuda` class. - [(#753)](https://github.com/PennyLaneAI/pennylane-lightning/pull/753) + [(#753)](https://github.com/PennyLaneAI/pennylane-lightning/pull/753) * Updated Kokkos version and support to 4.3.01. [(#725)](https://github.com/PennyLaneAI/pennylane-lightning/pull/725) From 4f1f2793ea6e4a78202b836ab25c974c2bba1605 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:51:18 -0400 Subject: [PATCH 08/34] format catalyst files --- .../catalyst/LightningKokkosObsManager.hpp | 92 +++--- .../catalyst/LightningKokkosSimulator.cpp | 277 ++++++++++-------- .../catalyst/LightningKokkosSimulator.hpp | 39 +-- 3 files changed, 229 insertions(+), 179 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp index 34f008d7a6..fb20866c25 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp @@ -27,15 +27,18 @@ namespace Catalyst::Runtime::Simulator { /** - * @brief The LightningKokkosObsManager caches observables of a program at runtime - * and maps each one to a const unique index (`int64_t`) in the scope - * of the global context manager. + * @brief The LightningKokkosObsManager caches observables of a program at + * runtime and maps each one to a const unique index (`int64_t`) in the scope of + * the global context manager. */ template class LightningKokkosObsManager { private: - using VectorStateT = Pennylane::LightningKokkos::StateVectorKokkos; - using ObservableClassName = Pennylane::Observables::Observable; - using ObservablePairType = std::pair, ObsType>; + using VectorStateT = + Pennylane::LightningKokkos::StateVectorKokkos; + using ObservableClassName = + Pennylane::Observables::Observable; + using ObservablePairType = + std::pair, ObsType>; std::vector observables_{}; public: @@ -43,7 +46,8 @@ template class LightningKokkosObsManager { ~LightningKokkosObsManager() = default; LightningKokkosObsManager(const LightningKokkosObsManager &) = delete; - LightningKokkosObsManager &operator=(const LightningKokkosObsManager &) = delete; + LightningKokkosObsManager & + operator=(const LightningKokkosObsManager &) = delete; LightningKokkosObsManager(LightningKokkosObsManager &&) = delete; LightningKokkosObsManager &operator=(LightningKokkosObsManager &&) = delete; @@ -58,10 +62,11 @@ template class LightningKokkosObsManager { * @param obsKeys The vector of observable keys * @return bool */ - [[nodiscard]] auto isValidObservables(const std::vector &obsKeys) const -> bool - { + [[nodiscard]] auto + isValidObservables(const std::vector &obsKeys) const -> bool { return std::all_of(obsKeys.begin(), obsKeys.end(), [this](auto i) { - return (i >= 0 && static_cast(i) < this->observables_.size()); + return (i >= 0 && + static_cast(i) < this->observables_.size()); }); } @@ -71,8 +76,8 @@ template class LightningKokkosObsManager { * @param key The observable key * @return std::shared_ptr */ - [[nodiscard]] auto getObservable(ObsIdType key) -> std::shared_ptr - { + [[nodiscard]] auto getObservable(ObsIdType key) + -> std::shared_ptr { RT_FAIL_IF(!this->isValidObservables({key}), "Invalid observable key"); return std::get<0>(this->observables_[key]); } @@ -82,7 +87,9 @@ template class LightningKokkosObsManager { * * @return size_t */ - [[nodiscard]] auto numObservables() const -> size_t { return this->observables_.size(); } + [[nodiscard]] auto numObservables() const -> size_t { + return this->observables_.size(); + } /** * @brief Create and cache a new NamedObs instance. @@ -91,15 +98,16 @@ template class LightningKokkosObsManager { * @param wires The vector of wires the observable acts on * @return ObsIdType */ - [[nodiscard]] auto createNamedObs(ObsId obsId, const std::vector &wires) -> ObsIdType - { - auto &&obs_str = - std::string(Lightning::lookup_obs( + [[nodiscard]] auto createNamedObs(ObsId obsId, + const std::vector &wires) + -> ObsIdType { + auto &&obs_str = std::string( + Lightning::lookup_obs( Lightning::simulator_observable_support, obsId)); this->observables_.push_back(std::make_pair( - std::make_shared>( - obs_str, wires), + std::make_shared>(obs_str, wires), ObsType::Basic)); return static_cast(this->observables_.size() - 1); } @@ -111,9 +119,9 @@ template class LightningKokkosObsManager { * @param wires The vector of wires the observable acts on * @return ObsIdType */ - [[nodiscard]] auto createHermitianObs(const std::vector> &matrix, - const std::vector &wires) -> ObsIdType - { + [[nodiscard]] auto + createHermitianObs(const std::vector> &matrix, + const std::vector &wires) -> ObsIdType { std::vector> matrix_k; matrix_k.reserve(matrix.size()); for (const auto &elem : matrix) { @@ -121,9 +129,10 @@ template class LightningKokkosObsManager { } this->observables_.push_back(std::make_pair( - std::make_shared>( - Pennylane::LightningKokkos::Observables::HermitianObs{matrix_k, - wires}), + std::make_shared>( + Pennylane::LightningKokkos::Observables::HermitianObs< + VectorStateT>{matrix_k, wires}), ObsType::Basic)); return static_cast(this->observables_.size() - 1); @@ -135,8 +144,8 @@ template class LightningKokkosObsManager { * @param obsKeys The vector of observable keys * @return ObsIdType */ - [[nodiscard]] auto createTensorProdObs(const std::vector &obsKeys) -> ObsIdType - { + [[nodiscard]] auto + createTensorProdObs(const std::vector &obsKeys) -> ObsIdType { const auto key_size = obsKeys.size(); const auto obs_size = this->observables_.size(); @@ -144,14 +153,16 @@ template class LightningKokkosObsManager { obs_vec.reserve(key_size); for (const auto &key : obsKeys) { - RT_FAIL_IF(static_cast(key) >= obs_size || key < 0, "Invalid observable key"); + RT_FAIL_IF(static_cast(key) >= obs_size || key < 0, + "Invalid observable key"); auto &&[obs, type] = this->observables_[key]; obs_vec.push_back(obs); } this->observables_.push_back(std::make_pair( - Pennylane::LightningKokkos::Observables::TensorProdObs::create(obs_vec), + Pennylane::LightningKokkos::Observables::TensorProdObs< + VectorStateT>::create(obs_vec), ObsType::TensorProd)); return static_cast(obs_size); @@ -164,30 +175,33 @@ template class LightningKokkosObsManager { * @param obsKeys The vector of observable keys * @return ObsIdType */ - [[nodiscard]] auto createHamiltonianObs(const std::vector &coeffs, - const std::vector &obsKeys) -> ObsIdType - { + [[nodiscard]] auto + createHamiltonianObs(const std::vector &coeffs, + const std::vector &obsKeys) -> ObsIdType { const auto key_size = obsKeys.size(); const auto obs_size = this->observables_.size(); - RT_FAIL_IF(key_size != coeffs.size(), - "Incompatible list of observables and coefficients; " - "Number of observables and number of coefficients must be equal"); + RT_FAIL_IF( + key_size != coeffs.size(), + "Incompatible list of observables and coefficients; " + "Number of observables and number of coefficients must be equal"); std::vector> obs_vec; obs_vec.reserve(key_size); for (auto key : obsKeys) { - RT_FAIL_IF(static_cast(key) >= obs_size || key < 0, "Invalid observable key"); + RT_FAIL_IF(static_cast(key) >= obs_size || key < 0, + "Invalid observable key"); auto &&[obs, type] = this->observables_[key]; obs_vec.push_back(obs); } this->observables_.push_back(std::make_pair( - std::make_shared>( - Pennylane::LightningKokkos::Observables::Hamiltonian( - coeffs, std::move(obs_vec))), + std::make_shared>( + Pennylane::LightningKokkos::Observables::Hamiltonian< + VectorStateT>(coeffs, std::move(obs_vec))), ObsType::Hamiltonian)); return static_cast(obs_size); diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp index 2e31d917be..810a9439fd 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp @@ -19,8 +19,7 @@ namespace Catalyst::Runtime::Simulator { -auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType -{ +auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType { const size_t num_qubits = this->device_sv->getNumQubits(); if (!num_qubits) { @@ -28,7 +27,8 @@ auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType return this->qubit_manager.Allocate(num_qubits); } - std::vector> data = this->device_sv->getDataVector(); + std::vector> data = + this->device_sv->getDataVector(); const size_t dsize = data.size(); data.resize(dsize << 1UL); @@ -45,8 +45,8 @@ auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType return this->qubit_manager.Allocate(num_qubits); } -auto LightningKokkosSimulator::AllocateQubits(size_t num_qubits) -> std::vector -{ +auto LightningKokkosSimulator::AllocateQubits(size_t num_qubits) + -> std::vector { if (!num_qubits) { return {}; } @@ -58,60 +58,67 @@ auto LightningKokkosSimulator::AllocateQubits(size_t num_qubits) -> std::vector< } std::vector result(num_qubits); - std::generate_n(result.begin(), num_qubits, [this]() { return AllocateQubit(); }); + std::generate_n(result.begin(), num_qubits, + [this]() { return AllocateQubit(); }); return result; } -void LightningKokkosSimulator::ReleaseQubit(QubitIdType q) { this->qubit_manager.Release(q); } +void LightningKokkosSimulator::ReleaseQubit(QubitIdType q) { + this->qubit_manager.Release(q); +} -void LightningKokkosSimulator::ReleaseAllQubits() -{ +void LightningKokkosSimulator::ReleaseAllQubits() { this->qubit_manager.ReleaseAll(); this->device_sv = std::make_unique(0); // reset the device } -auto LightningKokkosSimulator::GetNumQubits() const -> size_t -{ +auto LightningKokkosSimulator::GetNumQubits() const -> size_t { return this->device_sv->getNumQubits(); } -void LightningKokkosSimulator::StartTapeRecording() -{ +void LightningKokkosSimulator::StartTapeRecording() { RT_FAIL_IF(this->tape_recording, "Cannot re-activate the cache manager"); this->tape_recording = true; this->cache_manager.Reset(); } -void LightningKokkosSimulator::StopTapeRecording() -{ - RT_FAIL_IF(!this->tape_recording, "Cannot stop an already stopped cache manager"); +void LightningKokkosSimulator::StopTapeRecording() { + RT_FAIL_IF(!this->tape_recording, + "Cannot stop an already stopped cache manager"); this->tape_recording = false; } auto LightningKokkosSimulator::CacheManagerInfo() - -> std::tuple, std::vector> -{ - return {this->cache_manager.getNumOperations(), this->cache_manager.getNumObservables(), - this->cache_manager.getNumParams(), this->cache_manager.getOperationsNames(), + -> std::tuple, + std::vector> { + return {this->cache_manager.getNumOperations(), + this->cache_manager.getNumObservables(), + this->cache_manager.getNumParams(), + this->cache_manager.getOperationsNames(), this->cache_manager.getObservablesKeys()}; } -void LightningKokkosSimulator::SetDeviceShots(size_t shots) { this->device_shots = shots; } +void LightningKokkosSimulator::SetDeviceShots(size_t shots) { + this->device_shots = shots; +} -auto LightningKokkosSimulator::GetDeviceShots() const -> size_t { return this->device_shots; } +auto LightningKokkosSimulator::GetDeviceShots() const -> size_t { + return this->device_shots; +} -void LightningKokkosSimulator::PrintState() -{ +void LightningKokkosSimulator::PrintState() { using std::cout; using std::endl; - using UnmanagedComplexHostView = Kokkos::View *, Kokkos::HostSpace, - Kokkos::MemoryTraits>; + using UnmanagedComplexHostView = + Kokkos::View *, Kokkos::HostSpace, + Kokkos::MemoryTraits>; const size_t num_qubits = this->device_sv->getNumQubits(); const size_t size = Pennylane::Util::exp2(num_qubits); std::vector> state(size, {0.0, 0.0}); - auto *state_kptr = reinterpret_cast *>(state.data()); + auto *state_kptr = + reinterpret_cast *>(state.data()); auto device_data = this->device_sv->getView(); Kokkos::deep_copy(UnmanagedComplexHostView(state_kptr, size), device_data); @@ -124,28 +131,26 @@ void LightningKokkosSimulator::PrintState() cout << state[idx] << "]" << endl; } -auto LightningKokkosSimulator::Zero() const -> Result -{ +auto LightningKokkosSimulator::Zero() const -> Result { return const_cast(&GLOBAL_RESULT_FALSE_CONST); } -auto LightningKokkosSimulator::One() const -> Result -{ +auto LightningKokkosSimulator::One() const -> Result { return const_cast(&GLOBAL_RESULT_TRUE_CONST); } -void LightningKokkosSimulator::NamedOperation(const std::string &name, - const std::vector ¶ms, - const std::vector &wires, bool inverse, - const std::vector &controlled_wires, - const std::vector &controlled_values) -{ +void LightningKokkosSimulator::NamedOperation( + const std::string &name, const std::vector ¶ms, + const std::vector &wires, bool inverse, + const std::vector &controlled_wires, + const std::vector &controlled_values) { RT_FAIL_IF(!controlled_wires.empty() || !controlled_values.empty(), "LightningKokkos does not support native quantum control."); // Check the validity of number of qubits and parameters RT_FAIL_IF(!isValidQubits(wires), "Given wires do not refer to qubits"); - RT_FAIL_IF(!isValidQubits(controlled_wires), "Given controlled wires do not refer to qubits"); + RT_FAIL_IF(!isValidQubits(controlled_wires), + "Given controlled wires do not refer to qubits"); // Convert wires to device wires auto &&dev_wires = getDeviceWires(wires); @@ -156,48 +161,56 @@ void LightningKokkosSimulator::NamedOperation(const std::string &name, // Update tape caching if required if (this->tape_recording) { this->cache_manager.addOperation(name, params, dev_wires, inverse, {}, - {/*controlled_wires*/}, {/*controlled_values*/}); + {/*controlled_wires*/}, + {/*controlled_values*/}); } } -void LightningKokkosSimulator::MatrixOperation(const std::vector> &matrix, - const std::vector &wires, bool inverse, - const std::vector &controlled_wires, - const std::vector &controlled_values) -{ - using UnmanagedComplexHostView = Kokkos::View *, Kokkos::HostSpace, - Kokkos::MemoryTraits>; +void LightningKokkosSimulator::MatrixOperation( + const std::vector> &matrix, + const std::vector &wires, bool inverse, + const std::vector &controlled_wires, + const std::vector &controlled_values) { + using UnmanagedComplexHostView = + Kokkos::View *, Kokkos::HostSpace, + Kokkos::MemoryTraits>; // TODO: Remove when controlled wires API is supported - RT_FAIL_IF(!controlled_wires.empty() || !controlled_values.empty(), - "LightningKokkos device does not support native quantum control."); + RT_FAIL_IF( + !controlled_wires.empty() || !controlled_values.empty(), + "LightningKokkos device does not support native quantum control."); RT_FAIL_IF(!isValidQubits(wires), "Given wires do not refer to qubits"); - RT_FAIL_IF(!isValidQubits(controlled_wires), "Given controlled wires do not refer to qubits"); + RT_FAIL_IF(!isValidQubits(controlled_wires), + "Given controlled wires do not refer to qubits"); // Convert wires to device wires auto &&dev_wires = getDeviceWires(wires); std::vector> matrix_kok; matrix_kok.resize(matrix.size()); - std::transform(matrix.begin(), matrix.end(), matrix_kok.begin(), - [](auto c) { return static_cast>(c); }); + std::transform( + matrix.begin(), matrix.end(), matrix_kok.begin(), + [](auto c) { return static_cast>(c); }); - Kokkos::View *> gate_matrix("gate_matrix", matrix_kok.size()); - Kokkos::deep_copy(gate_matrix, UnmanagedComplexHostView(matrix_kok.data(), matrix_kok.size())); + Kokkos::View *> gate_matrix("gate_matrix", + matrix_kok.size()); + Kokkos::deep_copy(gate_matrix, UnmanagedComplexHostView(matrix_kok.data(), + matrix_kok.size())); // Update the state-vector this->device_sv->applyMultiQubitOp(gate_matrix, dev_wires, inverse); // Update tape caching if required if (this->tape_recording) { - this->cache_manager.addOperation("QubitUnitary", {}, dev_wires, inverse, matrix_kok, - {/*controlled_wires*/}, {/*controlled_values*/}); + this->cache_manager.addOperation("QubitUnitary", {}, dev_wires, inverse, + matrix_kok, {/*controlled_wires*/}, + {/*controlled_values*/}); } } -auto LightningKokkosSimulator::Observable(ObsId id, const std::vector> &matrix, - const std::vector &wires) -> ObsIdType -{ +auto LightningKokkosSimulator::Observable( + ObsId id, const std::vector> &matrix, + const std::vector &wires) -> ObsIdType { RT_FAIL_IF(wires.size() > this->GetNumQubits(), "Invalid number of wires"); RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires"); @@ -210,19 +223,18 @@ auto LightningKokkosSimulator::Observable(ObsId id, const std::vectorobs_manager.createNamedObs(id, dev_wires); } -auto LightningKokkosSimulator::TensorObservable(const std::vector &obs) -> ObsIdType -{ +auto LightningKokkosSimulator::TensorObservable( + const std::vector &obs) -> ObsIdType { return this->obs_manager.createTensorProdObs(obs); } -auto LightningKokkosSimulator::HamiltonianObservable(const std::vector &coeffs, - const std::vector &obs) -> ObsIdType -{ +auto LightningKokkosSimulator::HamiltonianObservable( + const std::vector &coeffs, const std::vector &obs) + -> ObsIdType { return this->obs_manager.createHamiltonianObs(coeffs, obs); } -auto LightningKokkosSimulator::Expval(ObsIdType obsKey) -> double -{ +auto LightningKokkosSimulator::Expval(ObsIdType obsKey) -> double { RT_FAIL_IF(!this->obs_manager.isValidObservables({obsKey}), "Invalid key for cached observables"); @@ -233,13 +245,13 @@ auto LightningKokkosSimulator::Expval(ObsIdType obsKey) -> double auto &&obs = this->obs_manager.getObservable(obsKey); - Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; return device_shots ? m.expval(*obs, device_shots, {}) : m.expval(*obs); } -auto LightningKokkosSimulator::Var(ObsIdType obsKey) -> double -{ +auto LightningKokkosSimulator::Var(ObsIdType obsKey) -> double { RT_FAIL_IF(!this->obs_manager.isValidObservables({obsKey}), "Invalid key for cached observables"); @@ -250,23 +262,26 @@ auto LightningKokkosSimulator::Var(ObsIdType obsKey) -> double auto &&obs = this->obs_manager.getObservable(obsKey); - Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; return device_shots ? m.var(*obs, device_shots) : m.var(*obs); } -void LightningKokkosSimulator::State(DataView, 1> &state) -{ - using UnmanagedComplexHostView = Kokkos::View *, Kokkos::HostSpace, - Kokkos::MemoryTraits>; +void LightningKokkosSimulator::State(DataView, 1> &state) { + using UnmanagedComplexHostView = + Kokkos::View *, Kokkos::HostSpace, + Kokkos::MemoryTraits>; const size_t num_qubits = this->device_sv->getNumQubits(); const size_t size = Pennylane::Util::exp2(num_qubits); - RT_FAIL_IF(state.size() != size, "Invalid size for the pre-allocated state vector"); + RT_FAIL_IF(state.size() != size, + "Invalid size for the pre-allocated state vector"); // create a temporary buffer to copy the underlying state-vector to std::vector> buffer(size); - auto *state_kptr = reinterpret_cast *>(buffer.data()); + auto *state_kptr = + reinterpret_cast *>(buffer.data()); // copy data from device to host auto device_data = this->device_sv->getView(); @@ -276,19 +291,19 @@ void LightningKokkosSimulator::State(DataView, 1> &state) std::move(buffer.begin(), buffer.end(), state.begin()); } -void LightningKokkosSimulator::Probs(DataView &probs) -{ - Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; +void LightningKokkosSimulator::Probs(DataView &probs) { + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; auto &&dv_probs = device_shots ? m.probs(device_shots) : m.probs(); - RT_FAIL_IF(probs.size() != dv_probs.size(), "Invalid size for the pre-allocated probabilities"); + RT_FAIL_IF(probs.size() != dv_probs.size(), + "Invalid size for the pre-allocated probabilities"); std::move(dv_probs.begin(), dv_probs.end(), probs.begin()); } -void LightningKokkosSimulator::PartialProbs(DataView &probs, - const std::vector &wires) -{ +void LightningKokkosSimulator::PartialProbs( + DataView &probs, const std::vector &wires) { const size_t numWires = wires.size(); const size_t numQubits = this->GetNumQubits(); @@ -296,8 +311,10 @@ void LightningKokkosSimulator::PartialProbs(DataView &probs, RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); auto dev_wires = getDeviceWires(wires); - Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; - auto &&dv_probs = device_shots ? m.probs(dev_wires, device_shots) : m.probs(dev_wires); + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; + auto &&dv_probs = + device_shots ? m.probs(dev_wires, device_shots) : m.probs(dev_wires); RT_FAIL_IF(probs.size() != dv_probs.size(), "Invalid size for the pre-allocated partial-probabilities"); @@ -305,14 +322,16 @@ void LightningKokkosSimulator::PartialProbs(DataView &probs, std::move(dv_probs.begin(), dv_probs.end(), probs.begin()); } -void LightningKokkosSimulator::Sample(DataView &samples, size_t shots) -{ - Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; +void LightningKokkosSimulator::Sample(DataView &samples, + size_t shots) { + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; // PL-Lightning-Kokkos generates samples using the alias method. // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling auto li_samples = m.generate_samples(shots); - RT_FAIL_IF(samples.size() != li_samples.size(), "Invalid size for the pre-allocated samples"); + RT_FAIL_IF(samples.size() != li_samples.size(), + "Invalid size for the pre-allocated samples"); const size_t numQubits = this->GetNumQubits(); @@ -323,13 +342,14 @@ void LightningKokkosSimulator::Sample(DataView &samples, size_t shots auto samplesIter = samples.begin(); for (size_t shot = 0; shot < shots; shot++) { for (size_t wire = 0; wire < numQubits; wire++) { - *(samplesIter++) = static_cast(li_samples[shot * numQubits + wire]); + *(samplesIter++) = + static_cast(li_samples[shot * numQubits + wire]); } } } -void LightningKokkosSimulator::PartialSample(DataView &samples, - const std::vector &wires, size_t shots) -{ +void LightningKokkosSimulator::PartialSample( + DataView &samples, const std::vector &wires, + size_t shots) { const size_t numWires = wires.size(); const size_t numQubits = this->GetNumQubits(); @@ -342,7 +362,8 @@ void LightningKokkosSimulator::PartialSample(DataView &samples, auto &&dev_wires = getDeviceWires(wires); // generate_samples is a member function of the MeasuresKokkos class. - Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; // PL-Lightning-Kokkos generates samples using the alias method. // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling @@ -355,14 +376,15 @@ void LightningKokkosSimulator::PartialSample(DataView &samples, auto samplesIter = samples.begin(); for (size_t shot = 0; shot < shots; shot++) { for (auto wire : dev_wires) { - *(samplesIter++) = static_cast(li_samples[shot * numQubits + wire]); + *(samplesIter++) = + static_cast(li_samples[shot * numQubits + wire]); } } } -void LightningKokkosSimulator::Counts(DataView &eigvals, DataView &counts, - size_t shots) -{ +void LightningKokkosSimulator::Counts(DataView &eigvals, + DataView &counts, + size_t shots) { const size_t numQubits = this->GetNumQubits(); const size_t numElements = 1U << numQubits; @@ -370,7 +392,8 @@ void LightningKokkosSimulator::Counts(DataView &eigvals, DataView m{*(this->device_sv)}; + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; // PL-Lightning-Kokkos generates samples using the alias method. // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling @@ -397,10 +420,9 @@ void LightningKokkosSimulator::Counts(DataView &eigvals, DataView &eigvals, - DataView &counts, - const std::vector &wires, size_t shots) -{ +void LightningKokkosSimulator::PartialCounts( + DataView &eigvals, DataView &counts, + const std::vector &wires, size_t shots) { const size_t numWires = wires.size(); const size_t numQubits = this->GetNumQubits(); const size_t numElements = 1U << numWires; @@ -414,7 +436,8 @@ void LightningKokkosSimulator::PartialCounts(DataView &eigvals, auto &&dev_wires = getDeviceWires(wires); // generate_samples is a member function of the MeasuresKokkos class. - Pennylane::LightningKokkos::Measures::Measurements m{*(this->device_sv)}; + Pennylane::LightningKokkos::Measures::Measurements m{ + *(this->device_sv)}; // PL-Lightning-Kokkos generates samples using the alias method. // Reference: https://en.wikipedia.org/wiki/Inverse_transform_sampling @@ -441,9 +464,9 @@ void LightningKokkosSimulator::PartialCounts(DataView &eigvals, } } -auto LightningKokkosSimulator::Measure(QubitIdType wire, std::optional postselect) - -> Result -{ +auto LightningKokkosSimulator::Measure(QubitIdType wire, + std::optional postselect) + -> Result { // get a measurement std::vector wires = {reinterpret_cast(wire)}; @@ -461,28 +484,31 @@ auto LightningKokkosSimulator::Measure(QubitIdType wire, std::optional return mres ? this->One() : this->Zero(); } -void LightningKokkosSimulator::Gradient(std::vector> &gradients, - const std::vector &trainParams) -{ +void LightningKokkosSimulator::Gradient( + std::vector> &gradients, + const std::vector &trainParams) { const bool tp_empty = trainParams.empty(); const size_t num_observables = this->cache_manager.getNumObservables(); const size_t num_params = this->cache_manager.getNumParams(); const size_t num_train_params = tp_empty ? num_params : trainParams.size(); - const size_t jac_size = num_train_params * this->cache_manager.getNumObservables(); + const size_t jac_size = + num_train_params * this->cache_manager.getNumObservables(); if (!jac_size) { return; } - RT_FAIL_IF(gradients.size() != num_observables, "Invalid number of pre-allocated gradients"); + RT_FAIL_IF(gradients.size() != num_observables, + "Invalid number of pre-allocated gradients"); auto &&obs_callees = this->cache_manager.getObservablesCallees(); bool is_valid_measurements = std::all_of(obs_callees.begin(), obs_callees.end(), [](const auto &m) { return m == MeasurementsT::Expval; }); - RT_FAIL_IF(!is_valid_measurements, - "Unsupported measurements to compute gradient; " - "Adjoint differentiation method only supports expectation return type"); + RT_FAIL_IF( + !is_valid_measurements, + "Unsupported measurements to compute gradient; " + "Adjoint differentiation method only supports expectation return type"); // Create OpsData auto &&ops_names = this->cache_manager.getOperationsNames(); @@ -490,16 +516,20 @@ void LightningKokkosSimulator::Gradient(std::vector> &gradie auto &&ops_wires = this->cache_manager.getOperationsWires(); auto &&ops_inverses = this->cache_manager.getOperationsInverses(); auto &&ops_matrices = this->cache_manager.getOperationsMatrices(); - auto &&ops_controlled_wires = this->cache_manager.getOperationsControlledWires(); - auto &&ops_controlled_values = this->cache_manager.getOperationsControlledValues(); + auto &&ops_controlled_wires = + this->cache_manager.getOperationsControlledWires(); + auto &&ops_controlled_values = + this->cache_manager.getOperationsControlledValues(); const auto &&ops = Pennylane::Algorithms::OpsData( - ops_names, ops_params, ops_wires, ops_inverses, ops_matrices, ops_controlled_wires, - ops_controlled_values); + ops_names, ops_params, ops_wires, ops_inverses, ops_matrices, + ops_controlled_wires, ops_controlled_values); // Create the vector of observables auto &&obs_keys = this->cache_manager.getObservablesKeys(); - std::vector>> obs_vec; + std::vector< + std::shared_ptr>> + obs_vec; obs_vec.reserve(obs_keys.size()); for (auto idx : obs_keys) { obs_vec.emplace_back(this->obs_manager.getObservable(idx)); @@ -517,7 +547,8 @@ void LightningKokkosSimulator::Gradient(std::vector> &gradie // construct the Jacobian data Pennylane::Algorithms::JacobianData tape{ - num_params, state.size(), state.data(), obs_vec, ops, tp_empty ? all_params : trainParams}; + num_params, state.size(), state.data(), + obs_vec, ops, tp_empty ? all_params : trainParams}; Pennylane::LightningKokkos::Algorithms::AdjointJacobian adj; std::vector jacobian(jac_size, 0); @@ -530,8 +561,10 @@ void LightningKokkosSimulator::Gradient(std::vector> &gradie for (size_t obs_idx = 0; obs_idx < num_observables; obs_idx++) { RT_ASSERT(begin_loc_iter != jacobian.end()); RT_ASSERT(num_train_params <= gradients[obs_idx].size()); - std::move(begin_loc_iter, begin_loc_iter + num_train_params, cur_buffer.begin()); - std::move(cur_buffer.begin(), cur_buffer.end(), gradients[obs_idx].begin()); + std::move(begin_loc_iter, begin_loc_iter + num_train_params, + cur_buffer.begin()); + std::move(cur_buffer.begin(), cur_buffer.end(), + gradients[obs_idx].begin()); begin_loc_iter += num_train_params; } } diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp index eeef798095..ef5148edf8 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp @@ -52,37 +52,39 @@ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { std::unique_ptr device_sv = std::make_unique(0); LightningKokkosObsManager obs_manager{}; - inline auto isValidQubit(QubitIdType wire) -> bool - { + inline auto isValidQubit(QubitIdType wire) -> bool { return this->qubit_manager.isValidQubitId(wire); } - inline auto isValidQubits(const std::vector &wires) -> bool - { - return std::all_of(wires.begin(), wires.end(), - [this](QubitIdType w) { return this->isValidQubit(w); }); + inline auto isValidQubits(const std::vector &wires) -> bool { + return std::all_of(wires.begin(), wires.end(), [this](QubitIdType w) { + return this->isValidQubit(w); + }); } - inline auto isValidQubits(size_t numWires, const QubitIdType *wires) -> bool - { - return std::all_of(wires, wires + numWires, - [this](QubitIdType w) { return this->isValidQubit(w); }); + inline auto isValidQubits(size_t numWires, const QubitIdType *wires) + -> bool { + return std::all_of(wires, wires + numWires, [this](QubitIdType w) { + return this->isValidQubit(w); + }); } - inline auto getDeviceWires(const std::vector &wires) -> std::vector - { + inline auto getDeviceWires(const std::vector &wires) + -> std::vector { std::vector res; res.reserve(wires.size()); - std::transform(wires.begin(), wires.end(), std::back_inserter(res), - [this](auto w) { return this->qubit_manager.getDeviceId(w); }); + std::transform( + wires.begin(), wires.end(), std::back_inserter(res), + [this](auto w) { return this->qubit_manager.getDeviceId(w); }); return res; } public: - explicit LightningKokkosSimulator(const std::string &kwargs = "{}") - { + explicit LightningKokkosSimulator(const std::string &kwargs = "{}") { auto &&args = Catalyst::Runtime::parse_kwargs(kwargs); - device_shots = args.contains("shots") ? static_cast(std::stoll(args["shots"])) : 0; + device_shots = args.contains("shots") + ? static_cast(std::stoll(args["shots"])) + : 0; } ~LightningKokkosSimulator() = default; @@ -92,6 +94,7 @@ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { QUANTUM_DEVICE_QIS_DECLARATIONS; auto CacheManagerInfo() - -> std::tuple, std::vector>; + -> std::tuple, + std::vector>; }; } // namespace Catalyst::Runtime::Simulator From 48c0a2d35494125e2a4c951a62cf40d91f3f06d4 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 19 Jun 2024 08:56:29 -0400 Subject: [PATCH 09/34] comment out add subdir tests --- .../simulators/lightning_kokkos/catalyst/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt index db6ba68a5c..2ad8dd08ec 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt @@ -85,7 +85,7 @@ target_link_libraries(lightning_kokkos_catalyst PUBLIC lightning_compile_option lightning_kokkos_utils ) -if (BUILD_TESTS) - enable_testing() - add_subdirectory("tests") -endif() \ No newline at end of file +# if (BUILD_TESTS) +# enable_testing() +# add_subdirectory("tests") +# endif() \ No newline at end of file From eb75e3401167fe3ade7ce8a2cc9e510ddb1e2eb8 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 20 Jun 2024 16:20:43 -0400 Subject: [PATCH 10/34] update LKokkos catalyst build to make its include directories public --- .../lightning_kokkos/catalyst/CMakeLists.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt index 2ad8dd08ec..dd0acf3aea 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt @@ -22,8 +22,8 @@ if(CATALYST_SRC_PATH) ) message(INFO " Building against local Catalyst - path: ${CATALYST_SRC_PATH} - GIT TAG: ${CATALYST_GIT_TAG}") - target_include_directories(lightning_kokkos_catalyst PRIVATE ${CATALYST_SRC_PATH}/runtime/lib/backend/common) - target_include_directories(lightning_kokkos_catalyst PRIVATE ${CATALYST_SRC_PATH}/runtime/include) + target_include_directories(lightning_kokkos_catalyst PUBLIC ${CATALYST_SRC_PATH}/runtime/lib/backend/common) + target_include_directories(lightning_kokkos_catalyst PUBLIC ${CATALYST_SRC_PATH}/runtime/include) else() if(NOT CATALYST_GIT_TAG) @@ -69,10 +69,11 @@ else() FetchContent_MakeAvailable(${HEADER_NAME}) endforeach() - target_include_directories(lightning_kokkos_catalyst PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) + target_include_directories(lightning_kokkos_catalyst PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include) endif() +target_include_directories(lightning_kokkos_catalyst INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(lightning_kokkos_catalyst PUBLIC lightning_compile_options lightning_external_libs lightning_base @@ -85,7 +86,7 @@ target_link_libraries(lightning_kokkos_catalyst PUBLIC lightning_compile_option lightning_kokkos_utils ) -# if (BUILD_TESTS) -# enable_testing() -# add_subdirectory("tests") -# endif() \ No newline at end of file +if (BUILD_TESTS) + enable_testing() + add_subdirectory("tests") +endif() \ No newline at end of file From ade18834f91dd31a176b133455b6eddc9f96c804 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 20 Jun 2024 16:22:22 -0400 Subject: [PATCH 11/34] add cmake build file for LKokkos catalyst tests --- .../catalyst/tests/CMakeLists.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt new file mode 100644 index 0000000000..5ca9ef9b01 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.20) + +project(lightning_kokkos_catalyst_tests) + +# Default build type for test code is Debug +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug) +endif() + +include("${pennylane_lightning_SOURCE_DIR}/cmake/support_tests.cmake") +FetchAndIncludeCatch() + +################################################################################ +# Define library +################################################################################ + +add_library(lightning_kokkos_catalyst_tests INTERFACE) +target_link_libraries(lightning_kokkos_catalyst_tests INTERFACE Catch2::Catch2 + lightning_kokkos_catalyst +) + +ProcessTestOptions(lightning_kokkos_catalyst_tests) + +target_sources(lightning_kokkos_catalyst_tests INTERFACE runner_lightning_kokkos_catalyst.cpp) + +################################################################################ +# Define targets +################################################################################ +set(TEST_SOURCES Test_LightningKokkosSimulator.cpp) + +add_executable(lightning_kokkos_catalyst_tests_runner ${TEST_SOURCES}) +target_link_libraries(lightning_kokkos_catalyst_tests_runner PRIVATE lightning_kokkos_catalyst_tests) + +catch_discover_tests(lightning_kokkos_catalyst_tests_runner) + +install(TARGETS lightning_kokkos_catalyst_tests_runner DESTINATION bin) From 8109f4ea1234c6ab967eeeb2cb5f1ecb52574c22 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 20 Jun 2024 16:22:48 -0400 Subject: [PATCH 12/34] add runner_lightning_kokkos_catalyst --- .../catalyst/tests/runner_lightning_kokkos_catalyst.cpp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/runner_lightning_kokkos_catalyst.cpp diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/runner_lightning_kokkos_catalyst.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/runner_lightning_kokkos_catalyst.cpp new file mode 100644 index 0000000000..4ed06df1f7 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/runner_lightning_kokkos_catalyst.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include From b8a8c716c867cb8a70b9cfd178469845c04dff46 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 20 Jun 2024 16:24:01 -0400 Subject: [PATCH 13/34] add constructibility and gates tests for LightningKokkosSimulator --- .../tests/Test_LightningKokkosSimulator.cpp | 607 ++++++++++++++++++ 1 file changed, 607 insertions(+) create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp new file mode 100644 index 0000000000..3f19be4334 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp @@ -0,0 +1,607 @@ +// Copyright 2018-2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "LightningKokkosSimulator.hpp" +#include "RuntimeCAPI.h" +#include "TestHelpers.hpp" + +/// @cond DEV +namespace { +using namespace Catalyst::Runtime::Simulator; +using namespace Pennylane::Util; +using LKSimulator = LightningKokkosSimulator; +} // namespace +/// @endcond + +/** + * @brief Tests the LightningKokkosSimulator class. + * + */ +TEST_CASE("LightningKokkosSimulator", "[constructibility]") { + SECTION("LightningKokkosSimulator") { + REQUIRE(std::is_constructible::value); + } + SECTION("LightningKokkosSimulator(string))") { + REQUIRE(std::is_constructible::value); + } +} + +TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { + SECTION("Identity gate") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 10; + std::vector Qs; + Qs.reserve(n_qubits); + for (size_t ind = 0; ind < n_qubits; ind++) { + Qs[ind] = LKsim->AllocateQubit(); + } + + for (size_t ind = 0; ind < n_qubits; ind += 2) { + LKsim->NamedOperation("Identity", {}, {Qs[ind]}, false); + } + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state.at(0) == std::complex{1, 0}); + + std::complex sum{0, 0}; + for (size_t ind = 1; ind < state.size(); ind++) { + sum += state[ind]; + } + + CHECK(sum == std::complex{0, 0}); + } + + SECTION("PauliX gate") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 3; + std::vector Qs; + Qs.reserve(n_qubits); + for (size_t ind = 0; ind < n_qubits; ind++) { + Qs[ind] = LKsim->AllocateQubit(); + } + + for (size_t ind = 0; ind < n_qubits; ind++) { + LKsim->NamedOperation("PauliX", {}, {Qs[ind]}, false); + } + for (size_t ind = n_qubits; ind > 0; ind--) { + LKsim->NamedOperation("PauliX", {}, {Qs[ind - 1]}, false); + } + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state.at(0) == std::complex{1, 0}); + + std::complex sum{0, 0}; + for (size_t ind = 1; ind < state.size(); ind++) { + sum += state[ind]; + } + + CHECK(sum == std::complex{0, 0}); + } + + SECTION("PauliY gate") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs; + Qs.reserve(n_qubits); + for (size_t ind = 0; ind < n_qubits; ind++) { + Qs[ind] = LKsim->AllocateQubit(); + } + + for (size_t ind = 0; ind < n_qubits; ind++) { + LKsim->NamedOperation("PauliY", {}, {Qs[ind]}, false); + } + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state.at(0) == std::complex{0, 0}); + CHECK(state.at(1) == std::complex{0, 0}); + CHECK(state.at(2) == std::complex{0, 0}); + CHECK(state.at(3) == std::complex{-1, 0}); + } + + SECTION("PauliY and PauliZ gates") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs; + Qs.reserve(n_qubits); + for (size_t ind = 0; ind < n_qubits; ind++) { + Qs[ind] = LKsim->AllocateQubit(); + } + + LKsim->NamedOperation("PauliY", {}, {Qs[0]}, false); + LKsim->NamedOperation("PauliZ", {}, {Qs[1]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state.at(0) == std::complex{0, 0}); + CHECK(state.at(1) == std::complex{0, 0}); + CHECK(state.at(2) == std::complex{0, 1}); + CHECK(state.at(3) == std::complex{0, 0}); + } + + SECTION("Hadamard gate") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs; + Qs.reserve(n_qubits); + for (size_t ind = 0; ind < n_qubits; ind++) { + Qs[ind] = LKsim->AllocateQubit(); + } + + for (size_t ind = 0; ind < n_qubits; ind++) { + LKsim->NamedOperation("Hadamard", {}, {Qs[ind]}, false); + } + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state[0] == + PLApproxComplex(std::complex{0.5, 0}).epsilon(1e-5)); + CHECK(state.at(1) == state.at(0)); + CHECK(state.at(2) == state.at(0)); + CHECK(state.at(3) == state.at(0)); + } + + SECTION("R(X, Y, Z) and PauliX gates") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 4; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("PauliX", {}, {Qs[0]}, false); + + LKsim->NamedOperation("RX", {0.123}, {Qs[1]}, false); + LKsim->NamedOperation("RY", {0.456}, {Qs[2]}, false); + LKsim->NamedOperation("RZ", {0.789}, {Qs[3]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + // calculated by pennylane. + CHECK(state.at(0) == std::complex{0, 0}); + CHECK(state.at(1) == std::complex{0, 0}); + CHECK(state.at(2) == std::complex{0, 0}); + CHECK(state.at(3) == std::complex{0, 0}); + CHECK(state.at(4) == std::complex{0, 0}); + CHECK(state.at(5) == std::complex{0, 0}); + CHECK(state.at(6) == std::complex{0, 0}); + CHECK(state.at(7) == std::complex{0, 0}); + CHECK(state[8] == + PLApproxComplex( + std::complex{0.8975969498074641, -0.3736920921192206}) + .epsilon(1e-5)); + CHECK(state.at(9) == std::complex{0, 0}); + CHECK(state[10] == + PLApproxComplex(std::complex{0.20827363966052723, + -0.08670953277495183}) + .epsilon(1e-5)); + CHECK(state.at(11) == std::complex{0, 0}); + CHECK(state[12] == + PLApproxComplex(std::complex{-0.023011082205037697, + -0.055271914055973925}) + .epsilon(1e-5)); + CHECK(state.at(13) == std::complex{0, 0}); + CHECK(state[14] == + PLApproxComplex(std::complex{-0.005339369573836912, + -0.012825002038956146}) + .epsilon(1e-5)); + CHECK(state.at(15) == std::complex{0, 0}); + } + + SECTION("Hadamard, RX, PhaseShift") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs; + Qs.reserve(n_qubits); + + Qs[0] = LKsim->AllocateQubit(); + Qs[1] = LKsim->AllocateQubit(); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("RX", {0.123}, {Qs[1]}, false); + LKsim->NamedOperation("PhaseShift", {0.456}, {Qs[0]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + // calculated by pennylane. + CHECK(state[0] == PLApproxComplex(std::complex{0.7057699753, 0}) + .epsilon(1e-5)); + CHECK(state[1] == PLApproxComplex(std::complex{0, -0.04345966}) + .epsilon(1e-5)); + CHECK(state[2] == + PLApproxComplex(std::complex{0.63365519, 0.31079312}) + .epsilon(1e-5)); + CHECK(state[3] == + PLApproxComplex(std::complex{0.01913791, -0.039019}) + .epsilon(1e-5)); + } + + // ============= 2-qubit operations ============= + + SECTION("PauliX and CNOT") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs; + Qs.reserve(n_qubits); + + for (size_t i = 0; i < n_qubits; i++) { + Qs[i] = LKsim->AllocateQubit(); + } + + LKsim->NamedOperation("PauliX", {}, {Qs[0]}, false); + LKsim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state.at(0) == std::complex{0, 0}); + CHECK(state.at(1) == std::complex{0, 0}); + CHECK(state.at(2) == std::complex{0, 0}); + CHECK(state.at(3) == std::complex{1, 0}); + } + + SECTION("Hadamard and CR(X, Y, Z)") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 4; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("CRX", {0.123}, {Qs[0], Qs[1]}, false); + LKsim->NamedOperation("CRY", {0.456}, {Qs[0], Qs[2]}, false); + LKsim->NamedOperation("CRZ", {0.789}, {Qs[0], Qs[3]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + // calculated by pennylane. + CHECK( + state[0] == + PLApproxComplex(std::complex{M_SQRT1_2, 0}).epsilon(1e-5)); + CHECK(state.at(1) == std::complex{0, 0}); + CHECK(state.at(2) == std::complex{0, 0}); + CHECK(state.at(3) == std::complex{0, 0}); + CHECK(state.at(4) == std::complex{0, 0}); + CHECK(state.at(5) == std::complex{0, 0}); + CHECK(state.at(6) == std::complex{0, 0}); + CHECK(state.at(7) == std::complex{0, 0}); + CHECK(state[8] == + PLApproxComplex( + std::complex{0.6346968899812189, -0.2642402124132889}) + .epsilon(1e-5)); + CHECK(state.at(9) == std::complex{0, 0}); + CHECK(state[10] == + PLApproxComplex(std::complex{0.14727170294636227, + -0.061312898618685635}) + .epsilon(1e-5)); + CHECK(state.at(11) == std::complex{0, 0}); + CHECK(state[12] == + PLApproxComplex(std::complex{-0.016271292269623247, + -0.03908314523813921}) + .epsilon(1e-5)); + CHECK(state.at(13) == std::complex{0, 0}); + CHECK(state[14] == + PLApproxComplex(std::complex{-0.0037755044329212074, + -0.009068645910477189}) + .epsilon(1e-5)); + CHECK(state.at(15) == std::complex{0, 0}); + } + + SECTION("Hadamard and CRot") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("CRot", {M_PI, M_PI_2, 0.5}, {Qs[0], Qs[1]}, + false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK( + state[0] == + PLApproxComplex(std::complex{M_SQRT1_2, 0}).epsilon(1e-5)); + + CHECK(state[1] == + PLApproxComplex(std::complex{0, 0}).epsilon(1e-5)); + + CHECK(state[2] == PLApproxComplex(std::complex{-0.1237019796, + -0.4844562109}) + .epsilon(1e-5)); + CHECK(state[3] == + PLApproxComplex(std::complex{0.1237019796, -0.4844562109}) + .epsilon(1e-5)); + } + + SECTION("Hadamard, PauliZ, IsingXY, SWAP") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("PauliZ", {}, {Qs[0]}, false); + LKsim->NamedOperation("IsingXY", {0.2}, {Qs[1], Qs[0]}, false); + LKsim->NamedOperation("SWAP", {}, {Qs[0], Qs[1]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK( + state[0] == + PLApproxComplex(std::complex{M_SQRT1_2, 0}).epsilon(1e-5)); + CHECK(state[1] == PLApproxComplex(std::complex{-0.70357419, 0}) + .epsilon(1e-5)); + CHECK(state[2] == PLApproxComplex(std::complex{0, -0.07059289}) + .epsilon(1e-5)); + CHECK(state[3] == + PLApproxComplex(std::complex{0, 0}).epsilon(1e-5)); + } + + SECTION("Hadamard, PauliX and Toffoli") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 3; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("PauliX", {}, {Qs[1]}, false); + LKsim->NamedOperation("Toffoli", {}, {Qs[0], Qs[1], Qs[2]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state.at(0) == std::complex{0, 0}); + CHECK(state.at(1) == std::complex{0, 0}); + CHECK( + state[2] == + PLApproxComplex(std::complex{M_SQRT1_2, 0}).epsilon(1e-5)); + CHECK(state.at(3) == std::complex{0, 0}); + CHECK(state.at(4) == std::complex{0, 0}); + CHECK(state.at(5) == std::complex{0, 0}); + CHECK(state.at(6) == std::complex{0, 0}); + CHECK( + state[7] == + PLApproxComplex(std::complex{M_SQRT1_2, 0}).epsilon(1e-5)); + } + + SECTION("RX, Hadamard and MultiRZ") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("RX", {M_PI}, {Qs[1]}, false); + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("Hadamard", {}, {Qs[1]}, false); + LKsim->NamedOperation("MultiRZ", {M_PI}, {Qs[0], Qs[1]}, false); + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("Hadamard", {}, {Qs[1]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state[2] == + PLApproxComplex(std::complex{-1, 0}).epsilon(1e-5)); + } + + SECTION("Hadamard, CNOT and Matrix") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); + + const std::vector wires = {Qs[0]}; + std::vector> matrix{ + {-0.6709485262524046, -0.6304426335363695}, + {-0.14885403153998722, 0.3608498832392019}, + {-0.2376311670004963, 0.3096798175687841}, + {-0.8818365947322423, -0.26456390390903695}, + }; + LKsim->MatrixOperation(matrix, wires, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state[0] == + PLApproxComplex(std::complex{-0.474432, -0.44579}) + .epsilon(1e-5)); + CHECK(state[1] == + PLApproxComplex(std::complex{-0.105256, 0.255159}) + .epsilon(1e-5)); + CHECK(state[2] == + PLApproxComplex(std::complex{-0.168031, 0.218977}) + .epsilon(1e-5)); + CHECK(state[3] == + PLApproxComplex(std::complex{-0.623553, -0.187075}) + .epsilon(1e-5)); + } + + SECTION("Hadamard, CR(X, Y, Z) and Matrix") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 4; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("CRX", {0.123}, {Qs[0], Qs[1]}, false); + LKsim->NamedOperation("CRY", {0.456}, {Qs[0], Qs[2]}, false); + LKsim->NamedOperation("CRZ", {0.789}, {Qs[0], Qs[3]}, false); + + const std::vector wires = {Qs[0], Qs[1], Qs[2]}; + std::vector> matrix{ + {-0.14601911598243822, -0.18655250647340088}, + {-0.03917826201290317, -0.031161687050443518}, + {0.11497626236175404, 0.38310733543366354}, + {-0.0929691815340695, 0.1219804125497268}, + {0.07306514883467692, 0.017445444816725875}, + {-0.27330866098918355, -0.6007032759764033}, + {0.4530754397715841, -0.08267189625512258}, + {0.32125201986075, -0.036845158875036116}, + {0.032317572838307884, 0.02292755555300329}, + {-0.18775945295623664, -0.060215004737844156}, + {-0.3093351335745536, -0.2061961962889725}, + {0.4216087567144761, 0.010534488410902099}, + {0.2769943541718527, -0.26016137877135465}, + {0.18727884147867532, 0.02830415812286322}, + {0.3367562196770689, -0.5250999173939218}, + {0.05770014289220745, 0.26595514845958573}, + {0.37885720163317027, 0.3110931426403546}, + {0.13436510737129648, -0.4083415934958021}, + {-0.5443665467635203, 0.2458343977310266}, + {-0.050346912365833024, 0.08709833123617361}, + {0.11505259829552131, 0.010155858056939438}, + {-0.2930849061531229, 0.019339259194141145}, + {0.011825409829453282, 0.011597907736881019}, + {-0.10565527258356637, -0.3113689446440079}, + {0.0273191284561944, -0.2479498526173881}, + {-0.5528072425836249, -0.06114469689935285}, + {-0.20560364740746587, -0.3800208994544297}, + {-0.008236143958221483, 0.3017421511504845}, + {0.04817188123334976, 0.08550951191632741}, + {-0.24081054643565586, -0.3412671345149831}, + {-0.38913538197001885, 0.09288402897806938}, + {-0.07937578245883717, 0.013979426755633685}, + {0.22246583652015395, -0.18276674810033927}, + {0.22376666162382491, 0.2995723155125488}, + {-0.1727191441070097, -0.03880522034607489}, + {0.075780203819001, 0.2818783673816625}, + {-0.6161322400651016, 0.26067347179217193}, + {-0.021161519614267765, -0.08430919051054794}, + {0.1676500381348944, -0.30645601624407504}, + {-0.28858251997285883, 0.018089595494883842}, + {-0.19590767481842053, -0.12844366632033652}, + {0.18707834504831794, -0.1363932722670649}, + {-0.07224221779769334, -0.11267803536286894}, + {-0.23897684826459387, -0.39609971967853685}, + {-0.0032110880452929555, -0.29294331305690136}, + {-0.3188741682462722, -0.17338979346647143}, + {0.08194395032821632, -0.002944814673179825}, + {-0.5695791830944521, 0.33299548924055095}, + {-0.4983660307441444, -0.4222358493977972}, + {0.05533914327048402, -0.42575842134560576}, + {-0.2187623521182678, -0.03087596187054778}, + {0.11278255885846857, 0.07075886163492914}, + {-0.3054684775292515, -0.1739796870866232}, + {0.14151567663565712, 0.20399935744127418}, + {0.06720165377364941, 0.07543463072363207}, + {0.08019665306716581, -0.3473013434358584}, + {-0.2600167605995786, -0.08795704036197827}, + {0.125680477777759, 0.266342700305046}, + {-0.1586772594600269, 0.187360909108502}, + {-0.4653314704208982, 0.4048609954619629}, + {0.39992560380733094, -0.10029244177901954}, + {0.2533527906886461, 0.05222114898540775}, + {-0.15840033949128557, -0.2727320427534386}, + {-0.21590866323269536, -0.1191163626522938}, + }; + LKsim->MatrixOperation(matrix, wires, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + CHECK(state[0] == + PLApproxComplex(std::complex{-0.141499, -0.230993}) + .epsilon(1e-5)); + CHECK(state[2] == + PLApproxComplex(std::complex{0.135423, -0.235563}) + .epsilon(1e-5)); + CHECK(state[4] == + PLApproxComplex(std::complex{0.299458, 0.218321}) + .epsilon(1e-5)); + CHECK(state[6] == + PLApproxComplex(std::complex{0.0264869, -0.154913}) + .epsilon(1e-5)); + CHECK(state[8] == + PLApproxComplex(std::complex{-0.186607, 0.188884}) + .epsilon(1e-5)); + CHECK(state[10] == + PLApproxComplex(std::complex{-0.271843, -0.281136}) + .epsilon(1e-5)); + CHECK(state[12] == + PLApproxComplex(std::complex{-0.560499, -0.310176}) + .epsilon(1e-5)); + CHECK(state[14] == + PLApproxComplex(std::complex{0.0756372, -0.226334}) + .epsilon(1e-5)); + } + + SECTION("Hadamard and IsingZZ") { + std::unique_ptr LKsim = std::make_unique(); + + constexpr size_t n_qubits = 2; + std::vector Qs = LKsim->AllocateQubits(n_qubits); + + LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + LKsim->NamedOperation("Hadamard", {}, {Qs[1]}, false); + LKsim->NamedOperation("IsingZZ", {M_PI_4}, {Qs[0], Qs[1]}, false); + + std::vector> state(1U << LKsim->GetNumQubits()); + DataView, 1> view(state); + LKsim->State(view); + + std::complex c1{0.4619397663, -0.1913417162}; + std::complex c2{0.4619397663, 0.1913417162}; + + CHECK(state[0] == PLApproxComplex(c1).epsilon(1e-5)); + CHECK(state[1] == PLApproxComplex(c2).epsilon(1e-5)); + CHECK(state[2] == PLApproxComplex(c2).epsilon(1e-5)); + CHECK(state[3] == PLApproxComplex(c1).epsilon(1e-5)); + } +} \ No newline at end of file From cec3ced201a5690dbb259402f897f17de81450c5 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 20 Jun 2024 20:26:31 +0000 Subject: [PATCH 14/34] Auto update version from '0.37.0-dev44' to '0.37.0-dev46' --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 46f1c1e8ff..8a46df66d0 100644 --- a/pennylane_lightning/core/_version.py +++ b/pennylane_lightning/core/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.37.0-dev44" +__version__ = "0.37.0-dev46" From 70f3658b9e38216df997632ef31588da7ee4c97d Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 21 Jun 2024 09:30:01 -0400 Subject: [PATCH 15/34] expand coverage --- .../tests/Test_LightningKokkosSimulator.cpp | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp index 3f19be4334..3e5bea4039 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp @@ -39,7 +39,7 @@ using LKSimulator = LightningKokkosSimulator; * @brief Tests the LightningKokkosSimulator class. * */ -TEST_CASE("LightningKokkosSimulator", "[constructibility]") { +TEST_CASE("LightningKokkosSimulator::constructor", "[constructibility]") { SECTION("LightningKokkosSimulator") { REQUIRE(std::is_constructible::value); } @@ -48,6 +48,36 @@ TEST_CASE("LightningKokkosSimulator", "[constructibility]") { } } +TEST_CASE("LightningKokkosSimulator::unit_tests", "[unit tests]") { + SECTION("Managing Qubits") { + std::unique_ptr LKsim = std::make_unique(); + std::vector Qs = LKsim->AllocateQubits(0); + REQUIRE(LKsim->GetNumQubits() == 0); + LKsim->AllocateQubits(4); + REQUIRE(LKsim->GetNumQubits() == 4); + LKsim->ReleaseQubit(0); + REQUIRE( + LKsim->GetNumQubits() == + 4); // releasing only one qubit does not change the total number. + LKsim->ReleaseAllQubits(); + REQUIRE(LKsim->GetNumQubits() == + 0); // releasing all qubits resets the simulator. + } + SECTION("Tape recording") { + std::unique_ptr LKsim = std::make_unique(); + std::vector Qs = LKsim->AllocateQubits(1); + REQUIRE_NOTHROW(LKsim->StartTapeRecording()); + REQUIRE_THROWS_WITH( + LKsim->StartTapeRecording(), + Catch::Matchers::Contains("Cannot re-activate the cache manager")); + REQUIRE_NOTHROW(LKsim->StopTapeRecording()); + REQUIRE_THROWS_WITH( + LKsim->StopTapeRecording(), + Catch::Matchers::Contains( + "Cannot stop an already stopped cache manager")); + } +} + TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Identity gate") { std::unique_ptr LKsim = std::make_unique(); @@ -227,7 +257,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { CHECK(state.at(15) == std::complex{0, 0}); } - SECTION("Hadamard, RX, PhaseShift") { + SECTION("Hadamard, RX, PhaseShift with cache manager") { std::unique_ptr LKsim = std::make_unique(); constexpr size_t n_qubits = 2; @@ -237,9 +267,11 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { Qs[0] = LKsim->AllocateQubit(); Qs[1] = LKsim->AllocateQubit(); + LKsim->StartTapeRecording(); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); LKsim->NamedOperation("RX", {0.123}, {Qs[1]}, false); LKsim->NamedOperation("PhaseShift", {0.456}, {Qs[0]}, false); + LKsim->StopTapeRecording(); std::vector> state(1U << LKsim->GetNumQubits()); DataView, 1> view(state); @@ -256,6 +288,11 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { CHECK(state[3] == PLApproxComplex(std::complex{0.01913791, -0.039019}) .epsilon(1e-5)); + + std::tuple, + std::vector> + expected{3, 0, 2, {"Hadamard", "RX", "PhaseShift"}, {}}; + REQUIRE(LKsim->CacheManagerInfo() == expected); } // ============= 2-qubit operations ============= @@ -582,15 +619,17 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { .epsilon(1e-5)); } - SECTION("Hadamard and IsingZZ") { + SECTION("Hadamard and IsingZZ and cache manager") { std::unique_ptr LKsim = std::make_unique(); constexpr size_t n_qubits = 2; std::vector Qs = LKsim->AllocateQubits(n_qubits); + LKsim->StartTapeRecording(); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); LKsim->NamedOperation("Hadamard", {}, {Qs[1]}, false); LKsim->NamedOperation("IsingZZ", {M_PI_4}, {Qs[0], Qs[1]}, false); + LKsim->StopTapeRecording(); std::vector> state(1U << LKsim->GetNumQubits()); DataView, 1> view(state); @@ -603,5 +642,9 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { CHECK(state[1] == PLApproxComplex(c2).epsilon(1e-5)); CHECK(state[2] == PLApproxComplex(c2).epsilon(1e-5)); CHECK(state[3] == PLApproxComplex(c1).epsilon(1e-5)); + + std::tuple, + std::vector> expected{3, 0, 1, {"Hadamard", "Hadamard", "IsingZZ"}, {}}; + REQUIRE(LKsim->CacheManagerInfo() == expected); } } \ No newline at end of file From d6ddd85cc5df04d775e0ec1d6bace26baf2c00c4 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 21 Jun 2024 09:43:38 -0400 Subject: [PATCH 16/34] format --- .../catalyst/tests/Test_LightningKokkosSimulator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp index 3e5bea4039..32a87d9e77 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp @@ -644,7 +644,8 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { CHECK(state[3] == PLApproxComplex(c1).epsilon(1e-5)); std::tuple, - std::vector> expected{3, 0, 1, {"Hadamard", "Hadamard", "IsingZZ"}, {}}; + std::vector> + expected{3, 0, 1, {"Hadamard", "Hadamard", "IsingZZ"}, {}}; REQUIRE(LKsim->CacheManagerInfo() == expected); } } \ No newline at end of file From cc8a855cd9e9f430c93e2b071439b8a2e50a64ae Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 21 Jun 2024 10:26:30 -0400 Subject: [PATCH 17/34] trigger cis From 2b59c49da5cd62f054b03061eff5cf01c2d607b8 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 21 Jun 2024 10:42:37 -0400 Subject: [PATCH 18/34] trigger cis From 6913d8a511fa80d57b0a33c18cac011d6623ab45 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 21 Jun 2024 13:18:44 -0400 Subject: [PATCH 19/34] add measurements tests --- .../catalyst/tests/CMakeLists.txt | 4 +- .../tests/Test_LightningKokkosMeasures.cpp | 1753 +++++++++++++++++ 2 files changed, 1756 insertions(+), 1 deletion(-) create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt index 5ca9ef9b01..d0ccb0234f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt @@ -26,7 +26,9 @@ target_sources(lightning_kokkos_catalyst_tests INTERFACE runner_lightning_kokkos ################################################################################ # Define targets ################################################################################ -set(TEST_SOURCES Test_LightningKokkosSimulator.cpp) +set(TEST_SOURCES Test_LightningKokkosSimulator.cpp + Test_LightningKokkosMeasures.cpp +) add_executable(lightning_kokkos_catalyst_tests_runner ${TEST_SOURCES}) target_link_libraries(lightning_kokkos_catalyst_tests_runner PRIVATE lightning_kokkos_catalyst_tests) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp new file mode 100644 index 0000000000..4266030822 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp @@ -0,0 +1,1753 @@ +// Copyright 2022-2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "CacheManager.hpp" +#include "LightningKokkosSimulator.hpp" +#include "QuantumDevice.hpp" +#include "RuntimeCAPI.h" +#include "Types.h" +#include "Utils.hpp" +#include "catch2/catch.hpp" +#include "cmath" + +/// @cond DEV +namespace { +// MemRef type definition (Helper) +template struct MemRefT { + T *data_allocated; + T *data_aligned; + size_t offset; + size_t sizes[R]; + size_t strides[R]; +}; +using namespace Catalyst::Runtime::Simulator; +using LKSimulator = LightningKokkosSimulator; +} // namespace +/// @endcond + +TEST_CASE("NameObs test with invalid number of wires", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + REQUIRE_THROWS_WITH(sim->Observable(ObsId::PauliX, {}, {1}), + Catch::Contains("Invalid number of wires")); +} + +TEST_CASE("NameObs test with invalid given wires for NamedObs", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + sim->AllocateQubit(); + + REQUIRE_THROWS_WITH(sim->Observable(ObsId::PauliX, {}, {1}), + Catch::Contains("Invalid given wires")); +} + +TEST_CASE("HermitianObs test with invalid number of wires", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + REQUIRE_THROWS_WITH(sim->Observable(ObsId::Hermitian, {}, {1}), + Catch::Contains("Invalid number of wires")); +} + +TEST_CASE("HermitianObs test with invalid given wires for HermitianObs", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + sim->AllocateQubit(); + + REQUIRE_THROWS_WITH(sim->Observable(ObsId::Hermitian, {}, {1}), + Catch::Contains("Invalid given wires")); +} + +TEST_CASE("Check an unsupported observable", "[Measures]") { + REQUIRE_THROWS_WITH( + Lightning::lookup_obs( + Lightning::simulator_observable_support, static_cast(10)), + Catch::Contains( + "The given observable is not supported by the simulator")); +} + +TEST_CASE("Measurement collapse test with 2 wires", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + constexpr size_t n = 2; + std::vector Qs = sim->AllocateQubits(n); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + auto m = sim->Measure(Qs[0]); + std::vector> state(1U << sim->GetNumQubits()); + DataView, 1> view(state); + sim->State(view); + + // LCOV_EXCL_START + // This is conditional over the measurement result + if (*m) { + CHECK(pow(std::abs(std::real(state[2])), 2) + + pow(std::abs(std::imag(state[2])), 2) == + Approx(1.0).margin(1e-5)); + } else { + CHECK(pow(std::abs(std::real(state[0])), 2) + + pow(std::abs(std::imag(state[0])), 2) == + Approx(1.0).margin(1e-5)); + } + // LCOV_EXCL_STOP +} + +TEST_CASE("Measurement collapse concrete logical qubit difference", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + constexpr size_t n = 1; + // The first time an array is allocated, logical and concrete qubits + // are the same. + std::vector Qs = sim->AllocateQubits(n); + sim->ReleaseAllQubits(); + + // Now in this the concrete qubits are shifted by n. + Qs = sim->AllocateQubits(n); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->Measure(Qs[0]); + std::vector> state(1U << sim->GetNumQubits()); + DataView, 1> view(state); + sim->State(view); + + // LCOV_EXCL_START + bool is_zero = pow(std::abs(std::real(state[0])), 2) + + pow(std::abs(std::imag(state[0])), 2) == + Approx(1.0).margin(1e-5); + bool is_one = pow(std::abs(std::real(state[1])), 2) + + pow(std::abs(std::imag(state[1])), 2) == + Approx(1.0).margin(1e-5); + bool is_valid = is_zero ^ is_one; + CHECK(is_valid); + // LCOV_EXCL_STOP +} + +TEST_CASE("Mid-circuit measurement naive test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + intptr_t q; + + q = sim->AllocateQubit(); + + sim->NamedOperation("PauliX", {}, {q}, false); + + auto m = sim->Measure(q); + + CHECK(*m); +} + +TEST_CASE("Mid-circuit measurement test with postselect = 0", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + intptr_t q; + + q = sim->AllocateQubit(); + + sim->NamedOperation("Hadamard", {}, {q}, false); + + auto m = sim->Measure(q, 0); + + CHECK(*m == 0); +} + +TEST_CASE("Mid-circuit measurement test with postselect = 1", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + intptr_t q; + + q = sim->AllocateQubit(); + + sim->NamedOperation("Hadamard", {}, {q}, false); + + auto m = sim->Measure(q, 1); + + CHECK(*m == 1); +} + +TEST_CASE("Mid-circuit measurement test with invalid postselect value", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + intptr_t q; + + q = sim->AllocateQubit(); + + sim->NamedOperation("Hadamard", {}, {q}, false); + + REQUIRE_THROWS_WITH(sim->Measure(q, 2), + Catch::Contains("Invalid postselect value")); +} + +TEST_CASE("Expval(ObsT) test with invalid key for cached observables", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + REQUIRE_THROWS_WITH(sim->Expval(0), + Catch::Contains("Invalid key for cached observables")); +} + +TEST_CASE("Expval(NamedObs) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + + CHECK(sim->Expval(px) == Approx(1.0).margin(1e-5)); + CHECK(sim->Expval(py) == Approx(.0).margin(1e-5)); + CHECK(sim->Expval(pz) == Approx(-1.0).margin(1e-5)); +} + +TEST_CASE("Expval(NamedObs) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + CHECK(sim->Expval(px) == Approx(0.0).margin(5e-2)); + CHECK(sim->Expval(py) == Approx(0.0).margin(5e-2)); + CHECK(sim->Expval(pz) == Approx(-1.0).margin(5e-2)); +} + +TEST_CASE("Expval(HermitianObs) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(16, {0, 0}); + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[0], Qs[1]}); + ObsIdType h2 = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + + CHECK(sim->Expval(h1) == Approx(.0).margin(1e-5)); + CHECK(sim->Expval(h2) == Approx(.0).margin(1e-5)); +} + +TEST_CASE("Expval(HermitianObs) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(16, {0, 0}); + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[0], Qs[1]}); + +#ifndef PL_USE_LAPACK + REQUIRE_THROWS_WITH( + sim->Expval(h1), + Catch::Contains( + "Hermitian observables with shot measurement are not supported")); +#else + CHECK(sim->Expval(h1) == Approx(0.0).margin(1e-5)); +#endif +} + +TEST_CASE("Var(HermitianObs) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(16, {0, 0}); + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[0], Qs[1]}); +#ifndef PL_USE_LAPACK + REQUIRE_THROWS_WITH( + sim->Var(h1), + Catch::Contains( + "Hermitian observables with shot measurement are not supported")); +#else + CHECK(sim->Var(h1) == Approx(0.0).margin(1e-5)); +#endif +} + +TEST_CASE("Expval(TensorProd(NamedObs)) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpx = sim->TensorObservable({px}); + ObsIdType tpy = sim->TensorObservable({py}); + ObsIdType tpz = sim->TensorObservable({pz}); + + CHECK(sim->Expval(tpx) == Approx(1.0).margin(1e-5)); + CHECK(sim->Expval(tpy) == Approx(.0).margin(1e-5)); + CHECK(sim->Expval(tpz) == Approx(-1.0).margin(1e-5)); +} + +TEST_CASE("Expval(TensorProd(NamedObs)) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpx = sim->TensorObservable({px}); + ObsIdType tpy = sim->TensorObservable({py}); + ObsIdType tpz = sim->TensorObservable({pz}); + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + CHECK(sim->Expval(tpx) == Approx(1.0).margin(5e-2)); + CHECK(sim->Expval(tpy) == Approx(.0).margin(5e-2)); + CHECK(sim->Expval(tpz) == Approx(-1.0).margin(5e-2)); +} + +TEST_CASE("Expval(TensorProd(NamedObs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpxy = sim->TensorObservable({px, py}); + ObsIdType tpxz = sim->TensorObservable({px, pz}); + + REQUIRE_THROWS_WITH( + sim->TensorObservable({px, py, pz}), + Catch::Contains("All wires in observables must be disjoint.")); + + CHECK(sim->Expval(tpxy) == Approx(0.0).margin(1e-5)); + CHECK(sim->Expval(tpxz) == Approx(-1.0).margin(1e-5)); +} + +TEST_CASE("Expval(TensorProd(NamedObs[])) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + std::unique_ptr sim0 = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + Qs.push_back(sim0->AllocateQubit()); + } + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + sim0->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim0->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim0->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType tpxy = sim->TensorObservable({px, py}); + + ObsIdType px0 = sim0->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py0 = sim0->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType tpxy0 = sim0->TensorObservable({px0, py0}); + + CHECK(sim->Expval(tpxy) == Approx(sim0->Expval(tpxy0)).margin(5e-2)); +} + +TEST_CASE("Expval(TensorProd(HermitianObs))", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(16, {0, 0}); + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[0], Qs[1]}); + ObsIdType h2 = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType tph1 = sim->TensorObservable({h1}); + ObsIdType tph2 = sim->TensorObservable({h2}); + + CHECK(sim->Expval(tph1) == Approx(.0).margin(1e-5)); + CHECK(sim->Expval(tph2) == Approx(.0).margin(1e-5)); +} + +TEST_CASE("Expval(TensorProd(HermitianObs[]))", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(4, {1.0, 0}); + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[1]}); + ObsIdType h2 = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType tp = sim->TensorObservable({h1, h2}); + + CHECK(sim->Expval(tp) == Approx(.0).margin(1e-5)); +} + +TEST_CASE("Expval(TensorProd(Obs[]))", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType tp = sim->TensorObservable({px, h, pz}); + + CHECK(sim->Expval(tp) == Approx(-3.0).margin(1e-5)); +} + +TEST_CASE("Expval(Tensor(Hamiltonian(NamedObs[]), NamedObs)) test", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[0]}); + ObsIdType hxy = sim->HamiltonianObservable({0.4, 0.8}, {px, py}); + ObsIdType thz = sim->TensorObservable({hxy, pz}); + + CHECK(sim->Expval(thz) == Approx(-0.4).margin(1e-5)); +} + +TEST_CASE("Expval(Tensor(HermitianObs, Hamiltonian()) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 3; + std::vector Qs = sim->AllocateQubits(n); + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType her = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[1]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[2]}); + ObsIdType hxy = sim->HamiltonianObservable({0.4, 0.8}, {px, py}); + ObsIdType ten = sim->TensorObservable({her, hxy}); + + CHECK(sim->Expval(ten) == Approx(0.0).margin(1e-5)); +} + +TEST_CASE("Expval(Hamiltonian(NamedObs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType hxyz = sim->HamiltonianObservable({0.4, 0.8, 0.2}, {px, py, pz}); + + CHECK(sim->Expval(hxyz) == Approx(0.2).margin(1e-5)); +} + +TEST_CASE("Expval(Hamiltonian(NamedObs[])) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType hxyz = sim->HamiltonianObservable({0.4, 0.8, 0.2}, {px, py, pz}); + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + CHECK(sim->Expval(hxyz) == Approx(0.2).margin(5e-2)); +} + +TEST_CASE("Expval(Hamiltonian(TensorObs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpxy = sim->TensorObservable({px, py}); + ObsIdType tpxz = sim->TensorObservable({px, pz}); + ObsIdType hxyz = sim->HamiltonianObservable({0.2, 0.6}, {tpxy, tpxz}); + + CHECK(sim->Expval(hxyz) == Approx(-.6).margin(1e-5)); +} + +TEST_CASE("Expval(Hamiltonian(Hermitian[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hxhz = sim->HamiltonianObservable({0.2, 0.3, 0.6}, {px, h, pz}); + + CHECK(sim->Expval(hxhz) == Approx(0.5).margin(1e-5)); +} + +TEST_CASE("Expval(Hamiltonian({TensorProd, Hermitian}[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tp = sim->TensorObservable({px, pz}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hhtp = sim->HamiltonianObservable({0.5, 0.3}, {h, tp}); + + CHECK(sim->Expval(hhtp) == Approx(1.2).margin(1e-5)); +} + +TEST_CASE("Expval(Hamiltonian({Hamiltonian, Hermitian}[])) test", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType hp = sim->HamiltonianObservable({0.2, 0.6}, {px, pz}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hhtp = sim->HamiltonianObservable({0.5, 0.3}, {h, hp}); + + CHECK(sim->Expval(hhtp) == Approx(1.38).margin(1e-5)); +} + +TEST_CASE("Expval(Hamiltonian({Hamiltonian(Hamiltonian), Hermitian}[])) test", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType hp = sim->HamiltonianObservable({0.2, 0.6}, {px, pz}); + ObsIdType hhp = sim->HamiltonianObservable({1}, {hp}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hhtp = sim->HamiltonianObservable({0.5, 0.3}, {hhp, h}); + + CHECK(sim->Expval(hhtp) == Approx(0.7).margin(1e-5)); +} + +TEST_CASE("Var(NamedObs) test with numWires=4", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[0]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[3]}); + + CHECK(sim->Var(px) == Approx(.0).margin(1e-5)); + CHECK(sim->Var(py) == Approx(1.0).margin(1e-5)); + CHECK(sim->Var(pz) == Approx(.0).margin(1e-5)); +} + +TEST_CASE("Var(NamedObs) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + constexpr size_t num_shots = 5000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[0]}); + + CHECK(sim->Var(py) == Approx(1.0).margin(5e-2)); +} + +TEST_CASE("Var(HermitianObs) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(16, {0, 0}); + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[0], Qs[1]}); + ObsIdType h2 = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + + CHECK(sim->Var(h1) == Approx(.0).margin(1e-5)); + CHECK(sim->Var(h2) == Approx(1.0).margin(1e-5)); +} + +TEST_CASE("Var(TensorProd(NamedObs)) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpx = sim->TensorObservable({px}); + ObsIdType tpy = sim->TensorObservable({py}); + ObsIdType tpz = sim->TensorObservable({pz}); + + CHECK(sim->Var(tpx) == Approx(.0).margin(1e-5)); + CHECK(sim->Var(tpy) == Approx(1.0).margin(1e-5)); + CHECK(sim->Var(tpz) == Approx(.0).margin(1e-5)); +} + +TEST_CASE("Var(TensorProd(NamedObs)) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpx = sim->TensorObservable({px}); + ObsIdType tpz = sim->TensorObservable({pz}); + + CHECK(sim->Var(tpx) == Approx(.0).margin(5e-2)); + CHECK(sim->Var(tpz) == Approx(.0).margin(5e-2)); +} + +TEST_CASE("Var(TensorProd(NamedObs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpxy = sim->TensorObservable({px, py}); + ObsIdType tpxz = sim->TensorObservable({px, pz}); + + CHECK(sim->Var(tpxy) == Approx(1.0).margin(1e-5)); + CHECK(sim->Var(tpxz) == Approx(0.0).margin(1e-5)); +} + +TEST_CASE("Var(TensorProd(HermitianObs)) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(16, {0, 0}); + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[0], Qs[1]}); + ObsIdType h2 = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType tph1 = sim->TensorObservable({h1}); + ObsIdType tph2 = sim->TensorObservable({h2}); + + CHECK(sim->Var(tph1) == Approx(.0).margin(1e-5)); + CHECK(sim->Var(tph2) == Approx(1.0).margin(1e-5)); +} + +TEST_CASE("Var(TensorProd(HermitianObs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 2; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat1(4, {1.0, 0}); + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType h1 = sim->Observable(ObsId::Hermitian, mat1, {Qs[1]}); + ObsIdType h2 = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType tp = sim->TensorObservable({h1, h2}); + + CHECK(sim->Var(tp) == Approx(2.0).margin(1e-5)); +} + +TEST_CASE("Var(TensorProd(Obs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType tp = sim->TensorObservable({px, h, pz}); + + CHECK(sim->Var(tp) == Approx(4.0).margin(1e-5)); +} + +TEST_CASE("Var(Tensor(Hamiltonian(NamedObs[]), NamedObs)) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[0]}); + ObsIdType hxy = sim->HamiltonianObservable({0.4, 0.8}, {px, py}); + ObsIdType thz = sim->TensorObservable({hxy, pz}); + + CHECK(sim->Var(thz) == Approx(0.64).margin(1e-5)); +} + +TEST_CASE("Var(Tensor(NamedObs[])) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + constexpr size_t num_shots = 5000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[0]}); + ObsIdType thz = sim->TensorObservable({px, py, pz}); + + CHECK(sim->Var(thz) == Approx(0.99998976).margin(5e-2)); +} + +TEST_CASE("Var(Tensor(NamedObs[])) shots test without gates " + "(influenced from a bug in Lightning)", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 3; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + constexpr size_t num_shots = 5000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[0]}); + ObsIdType thz = sim->TensorObservable({px, py, pz}); + + CHECK(sim->Var(thz) == Approx(0.99966144).margin(5e-2)); +} + +TEST_CASE("Var(Tensor(HermitianObs, Hamiltonian()) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 3; + std::vector Qs = sim->AllocateQubits(n); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + std::vector> mat2{ + {1.0, 0.0}, {0.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}}; + + ObsIdType her = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[1]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[2]}); + ObsIdType hxy = sim->HamiltonianObservable({0.4, 0.8}, {px, py}); + ObsIdType ten = sim->TensorObservable({her, hxy}); + + CHECK(sim->Var(ten) == Approx(0.8).margin(1e-5)); +} + +TEST_CASE("Var(Tensor(HermitianObs, Hamiltonian()) shots test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 3; + std::vector Qs = sim->AllocateQubits(n); + + constexpr size_t num_shots = 5000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[1]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[2]}); + ObsIdType hxy = sim->HamiltonianObservable({0.4, 0.8}, {px, py}); + + CHECK(sim->Var(hxy) == Approx(0.8).margin(5e-2)); +} + +TEST_CASE("Var(Hamiltonian(NamedObs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType hxyz = sim->HamiltonianObservable({0.4, 0.8, 0.2}, {px, py, pz}); + + CHECK(sim->Var(hxyz) == Approx(0.64).margin(1e-5)); +} + +TEST_CASE("Var(Hamiltonian(TensorObs[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tpxy = sim->TensorObservable({px, py}); + ObsIdType tpxz = sim->TensorObservable({px, pz}); + ObsIdType hxyz = sim->HamiltonianObservable({0.2, 0.6}, {tpxy, tpxz}); + + CHECK(sim->Var(hxyz) == Approx(0.04).margin(1e-5)); +} + +TEST_CASE("Var(Hamiltonian(Hermitian[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hxhz = sim->HamiltonianObservable({0.2, 0.3, 0.6}, {px, h, pz}); + + CHECK(sim->Var(hxhz) == Approx(0.36).margin(1e-5)); +} + +TEST_CASE("Var(Hamiltonian({TensorProd, Hermitian}[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType tp = sim->TensorObservable({px, pz}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hhtp = sim->HamiltonianObservable({0.5, 0.3}, {h, tp}); + + CHECK(sim->Var(hhtp) == Approx(1.0).margin(1e-5)); +} + +TEST_CASE("Var(Hamiltonian({Hamiltonian, Hermitian}[])) test", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType hp = sim->HamiltonianObservable({0.2, 0.6}, {px, pz}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hhtp = sim->HamiltonianObservable({0.5, 0.3}, {h, hp}); + + CHECK(sim->Var(hhtp) == Approx(1.0).margin(1e-5)); +} + +TEST_CASE("Var(Hamiltonian({Hamiltonian(Hamiltonian), Hermitian}[])) test", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("PauliX", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + ObsIdType px = sim->Observable(ObsId::PauliX, {}, {Qs[2]}); + ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + ObsIdType hp = sim->HamiltonianObservable({0.2, 0.6}, {px, pz}); + ObsIdType hhp = sim->HamiltonianObservable({1}, {hp}); + + std::vector> mat2{ + {1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {3.0, 0.0}}; + ObsIdType h = sim->Observable(ObsId::Hermitian, mat2, {Qs[0]}); + ObsIdType hhtp = sim->HamiltonianObservable({0.5, 0.3}, {hhp, h}); + + CHECK(sim->Var(hhtp) == Approx(0.36).margin(1e-5)); +} + +TEST_CASE("State test with incorrect size", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs = sim->AllocateQubits(n); + + std::vector> state(1U << (n - 1)); + DataView, 1> view(state); + REQUIRE_THROWS_WITH( + sim->State(view), + Catch::Contains("Invalid size for the pre-allocated state vector")); +} + +TEST_CASE("State test with numWires=4", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs = sim->AllocateQubits(n); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + std::vector> state(1U << sim->GetNumQubits()); + DataView, 1> view(state); + sim->State(view); + + for (size_t i = 0; i < 16; i++) { + if (i == 4 || i == 6 || i == 12 || i == 14) { + CHECK(std::real(state[i]) == Approx(0.).margin(1e-5)); + CHECK(std::imag(state[i]) == Approx(0.5).margin(1e-5)); + } else { + CHECK(std::real(state[i]) == Approx(0.).margin(1e-5)); + CHECK(std::imag(state[i]) == Approx(0.).margin(1e-5)); + } + } +} + +TEST_CASE("PartialProbs test with incorrect numWires and numAlloc", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + std::vector probs_vec(1); + DataView probs_view(probs_vec); + + REQUIRE_THROWS_WITH( + sim->PartialProbs(probs_view, {Qs[0], Qs[1], Qs[2], Qs[3], Qs[0]}), + Catch::Contains("Invalid number of wires")); + + REQUIRE_THROWS_WITH( + sim->PartialProbs(probs_view, {Qs[0]}), + Catch::Contains( + "Invalid size for the pre-allocated partial-probabilities")); + + REQUIRE_THROWS_WITH( + sim->Probs(probs_view), + Catch::Contains("Invalid size for the pre-allocated probabilities")); + + sim->ReleaseQubit(Qs[0]); + + REQUIRE_THROWS_WITH(sim->PartialProbs(probs_view, {Qs[0]}), + Catch::Contains("Invalid given wires to measure")); +} + +TEST_CASE("Probs and PartialProbs tests with numWires=0-4", "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + std::vector probs0(1); + DataView view0(probs0); + sim->PartialProbs(view0, std::vector{}); + + std::vector probs1(2); + DataView view1(probs1); + sim->PartialProbs(view1, std::vector{Qs[2]}); + + std::vector probs2(4); + DataView view2(probs2); + sim->PartialProbs(view2, std::vector{Qs[0], Qs[3]}); + + std::vector probs3(16); + DataView view3(probs3); + sim->PartialProbs(view3, Qs); + + std::vector probs4(16); + DataView view4(probs4); + sim->Probs(view4); + + CHECK(probs0.size() == 1); + CHECK(probs0[0] == Approx(1.0)); + CHECK(probs1[0] == Approx(0.5).margin(1e-5)); + CHECK(probs1[1] == Approx(0.5).margin(1e-5)); + for (size_t i = 0; i < 4; i++) { + if (i == 0 || i == 2) { + CHECK(probs2[i] == Approx(0.5).margin(1e-5)); + } else { + CHECK(probs2[i] == Approx(0.).margin(1e-5)); + } + } + for (size_t i = 0; i < 16; i++) { + if (i == 4 || i == 6 || i == 12 || i == 14) { + CHECK(probs3[i] == Approx(0.25).margin(1e-5)); + CHECK(probs4[i] == Approx(0.25).margin(1e-5)); + } else { + CHECK(probs3[i] == Approx(0.).margin(1e-5)); + CHECK(probs4[i] == Approx(0.).margin(1e-5)); + } + } +} + +TEST_CASE("Probs and PartialProbs shots tests with numWires=0-4", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + constexpr size_t num_shots = 10000; + sim->SetDeviceShots(num_shots); + + sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); + sim->NamedOperation("PauliY", {}, {Qs[1]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[2]}, false); + sim->NamedOperation("PauliZ", {}, {Qs[3]}, false); + + std::vector probs0(1); + DataView view0(probs0); + sim->PartialProbs(view0, std::vector{}); + + std::vector probs1(2); + DataView view1(probs1); + sim->PartialProbs(view1, std::vector{Qs[2]}); + + std::vector probs2(4); + DataView view2(probs2); + sim->PartialProbs(view2, std::vector{Qs[0], Qs[3]}); + + std::vector probs3(16); + DataView view3(probs3); + sim->PartialProbs(view3, Qs); + + std::vector probs4(16); + DataView view4(probs4); + sim->Probs(view4); + + CHECK(probs0.size() == 1); + CHECK(probs0[0] == Approx(1.0).margin(5e-2)); + CHECK(probs1[0] == Approx(0.5).margin(5e-2)); + CHECK(probs1[1] == Approx(0.5).margin(5e-2)); + for (size_t i = 0; i < 4; i++) { + if (i == 0 || i == 2) { + CHECK(probs2[i] == Approx(0.5).margin(5e-2)); + } else { + CHECK(probs2[i] == Approx(0.).margin(5e-2)); + } + } + for (size_t i = 0; i < 16; i++) { + if (i == 4 || i == 6 || i == 12 || i == 14) { + CHECK(probs3[i] == Approx(0.25).margin(5e-2)); + CHECK(probs4[i] == Approx(0.25).margin(5e-2)); + } else { + CHECK(probs3[i] == Approx(0.).margin(5e-2)); + CHECK(probs4[i] == Approx(0.).margin(5e-2)); + } + } +} + +TEST_CASE("PartialSample test with incorrect numWires and numAlloc", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + std::vector samples_vec(1); + MemRefT samples{samples_vec.data(), + samples_vec.data(), + 0, + {samples_vec.size(), 1}, + {1, 1}}; + DataView view(samples.data_aligned, samples.offset, + samples.sizes, samples.strides); + + REQUIRE_THROWS_WITH( + sim->PartialSample(view, {Qs[0], Qs[1], Qs[2], Qs[3], Qs[0]}, 4), + Catch::Contains("Invalid number of wires")); + + REQUIRE_THROWS_WITH( + sim->PartialSample(view, {Qs[0], Qs[1]}, 2), + Catch::Contains("Invalid size for the pre-allocated partial-samples")); + + REQUIRE_THROWS_WITH( + sim->Sample(view, 2), + Catch::Contains("Invalid size for the pre-allocated samples")); + + sim->ReleaseQubit(Qs[0]); + + REQUIRE_THROWS_WITH(sim->PartialSample(view, {Qs[0]}, 4), + Catch::Contains("Invalid given wires to measure")); +} + +TEST_CASE("PartialCounts test with incorrect numWires and numAlloc", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + std::vector eigvals_vec(1); + DataView eigvals_view(eigvals_vec); + + std::vector counts_vec(1); + DataView counts_view(counts_vec); + + REQUIRE_THROWS_WITH(sim->PartialCounts(eigvals_view, counts_view, + {Qs[0], Qs[1], Qs[2], Qs[3], Qs[0]}, + 4), + Catch::Contains("Invalid number of wires")); + + REQUIRE_THROWS_WITH( + sim->PartialCounts(eigvals_view, counts_view, {Qs[0]}, 1), + Catch::Contains("Invalid size for the pre-allocated partial-counts")); + + REQUIRE_THROWS_WITH( + sim->Counts(eigvals_view, counts_view, 1), + Catch::Contains("Invalid size for the pre-allocated counts")); + + sim->ReleaseQubit(Qs[0]); + + REQUIRE_THROWS_WITH( + sim->PartialCounts(eigvals_view, counts_view, {Qs[0]}, 4), + Catch::Contains("Invalid given wires to measure")); +} + +TEST_CASE("Sample and PartialSample tests with numWires=0-4 shots=100", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("RX", {0.5}, {Qs[0]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[1]}, false); + sim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); + + size_t shots = 100; + + std::vector samples1(shots * 1); + MemRefT buffer1{ + samples1.data(), samples1.data(), 0, {shots, 1}, {1, 1}}; + DataView view1(buffer1.data_aligned, buffer1.offset, + buffer1.sizes, buffer1.strides); + sim->PartialSample(view1, std::vector{Qs[2]}, shots); + + std::vector samples2(shots * 2); + MemRefT buffer2{ + samples2.data(), samples2.data(), 0, {shots, 2}, {1, 1}}; + DataView view2(buffer2.data_aligned, buffer2.offset, + buffer2.sizes, buffer2.strides); + sim->PartialSample(view2, std::vector{Qs[0], Qs[3]}, shots); + + std::vector samples3(shots * 4); + MemRefT buffer3{ + samples3.data(), samples3.data(), 0, {shots, 4}, {1, 1}}; + DataView view3(buffer3.data_aligned, buffer3.offset, + buffer3.sizes, buffer3.strides); + sim->PartialSample(view3, Qs, shots); + + std::vector samples4(shots * 4); + MemRefT buffer4{ + samples4.data(), samples4.data(), 0, {shots, 4}, {1, 1}}; + DataView view4(buffer4.data_aligned, buffer4.offset, + buffer4.sizes, buffer4.strides); + sim->Sample(view4, shots); + + for (size_t i = 0; i < shots * 1; i++) + CHECK((samples1[i] == 0. || samples1[i] == 1.)); + for (size_t i = 0; i < shots * 2; i++) + CHECK((samples2[i] == 0. || samples2[i] == 1.)); + for (size_t i = 0; i < shots * 4; i++) + CHECK((samples3[i] == 0. || samples3[i] == 1.)); + for (size_t i = 0; i < shots * 4; i++) + CHECK((samples4[i] == 0. || samples4[i] == 1.)); +} + +TEST_CASE("Sample and PartialSample tests with numWires=0-4 " + "shots=1000 mcmc=True num_burnin=200", + "[Measures]") { + std::unique_ptr sim = + std::make_unique("{mcmc : True, num_burnin : 200}"); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs; + Qs.reserve(n); + for (size_t i = 0; i < n; i++) { + Qs.push_back(sim->AllocateQubit()); + } + + sim->NamedOperation("RX", {0.5}, {Qs[0]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[1]}, false); + sim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); + + size_t shots = 100; + + std::vector samples1(shots * 1); + MemRefT buffer1{ + samples1.data(), samples1.data(), 0, {shots, 1}, {1, 1}}; + DataView view1(buffer1.data_aligned, buffer1.offset, + buffer1.sizes, buffer1.strides); + sim->PartialSample(view1, std::vector{Qs[2]}, shots); + + std::vector samples2(shots * 2); + MemRefT buffer2{ + samples2.data(), samples2.data(), 0, {shots, 2}, {1, 1}}; + DataView view2(buffer2.data_aligned, buffer2.offset, + buffer2.sizes, buffer2.strides); + sim->PartialSample(view2, std::vector{Qs[0], Qs[3]}, shots); + + std::vector samples3(shots * 4); + MemRefT buffer3{ + samples3.data(), samples3.data(), 0, {shots, 4}, {1, 1}}; + DataView view3(buffer3.data_aligned, buffer3.offset, + buffer3.sizes, buffer3.strides); + sim->PartialSample(view3, Qs, shots); + + std::vector samples4(shots * 4); + MemRefT buffer4{ + samples4.data(), samples4.data(), 0, {shots, 4}, {1, 1}}; + DataView view4(buffer4.data_aligned, buffer4.offset, + buffer4.sizes, buffer4.strides); + sim->Sample(view4, shots); + + for (size_t i = 0; i < shots * 1; i++) + CHECK((samples1[i] == 0. || samples1[i] == 1.)); + for (size_t i = 0; i < shots * 2; i++) + CHECK((samples2[i] == 0. || samples2[i] == 1.)); + for (size_t i = 0; i < shots * 4; i++) + CHECK((samples3[i] == 0. || samples3[i] == 1.)); + for (size_t i = 0; i < shots * 4; i++) + CHECK((samples4[i] == 0. || samples4[i] == 1.)); +} + +TEST_CASE("Counts and PartialCounts tests with numWires=0-4 shots=100", + "[Measures]") { + std::unique_ptr sim = std::make_unique(); + + // state-vector with #qubits = n + constexpr size_t n = 4; + std::vector Qs = sim->AllocateQubits(n); + + sim->NamedOperation("RX", {0.5}, {Qs[0]}, false); + sim->NamedOperation("Hadamard", {}, {Qs[1]}, false); + sim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); + + size_t shots = 100; + + std::vector eigvals0(1); + std::vector counts0(1); + DataView eview0(eigvals0); + DataView cview0(counts0); + sim->PartialCounts(eview0, cview0, std::vector{}, shots); + + std::vector eigvals1(2); + std::vector counts1(2); + DataView eview1(eigvals1); + DataView cview1(counts1); + sim->PartialCounts(eview1, cview1, std::vector{Qs[2]}, shots); + + std::vector eigvals2(4); + std::vector counts2(4); + DataView eview2(eigvals2); + DataView cview2(counts2); + sim->PartialCounts(eview2, cview2, std::vector{Qs[0], Qs[3]}, + shots); + + std::vector eigvals3(16); + std::vector counts3(16); + DataView eview3(eigvals3); + DataView cview3(counts3); + sim->PartialCounts(eview3, cview3, Qs, shots); + + std::vector eigvals4(16); + std::vector counts4(16); + DataView eview4(eigvals4); + DataView cview4(counts4); + sim->Counts(eview4, cview4, shots); + + CHECK(eigvals0.size() == 1); + CHECK(eigvals0[0] == 0.0); + CHECK(counts0.size() == 1); + CHECK(counts0[0] == static_cast(shots)); + CHECK((eigvals1[0] == 0. && eigvals1[1] == 1.)); + CHECK((eigvals2[0] == 0. && eigvals2[1] == 1. && eigvals2[2] == 2. && + eigvals2[3] == 3.)); + for (size_t i = 0; i < 16; i++) { + CHECK(eigvals3[i] == static_cast(i)); + CHECK(eigvals4[i] == static_cast(i)); + } + + CHECK(counts1[0] + counts1[1] == static_cast(shots)); + CHECK(counts2[0] + counts2[1] + counts2[2] + counts2[3] == + static_cast(shots)); + size_t sum3 = 0, sum4 = 0; + for (size_t i = 0; i < 16; i++) { + sum3 += counts3[i]; + sum4 += counts4[i]; + } + CHECK(sum3 == shots); + CHECK(sum4 == shots); +} \ No newline at end of file From 8a8da4bd3bdb05805851eb1c1c2b30dfcff736f1 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 21 Jun 2024 15:00:06 -0400 Subject: [PATCH 20/34] add structure for tests for gradients --- .../catalyst/tests/CMakeLists.txt | 1 + .../tests/Test_LightningKokkosGradient.cpp | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt index d0ccb0234f..636d8c10b6 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/CMakeLists.txt @@ -28,6 +28,7 @@ target_sources(lightning_kokkos_catalyst_tests INTERFACE runner_lightning_kokkos ################################################################################ set(TEST_SOURCES Test_LightningKokkosSimulator.cpp Test_LightningKokkosMeasures.cpp + Test_LightningKokkosGradient.cpp ) add_executable(lightning_kokkos_catalyst_tests_runner ${TEST_SOURCES}) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp new file mode 100644 index 0000000000..741f53e106 --- /dev/null +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp @@ -0,0 +1,31 @@ +// Copyright 2022-2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "LightningKokkosSimulator.hpp" +#include "catch2/catch.hpp" + +/// @cond DEV +namespace { +using namespace Catalyst::Runtime::Simulator; +using LKSimulator = LightningKokkosSimulator; +} // namespace +/// @endcond + +TEST_CASE("Zero qubits. Zero parameters", "[Gradient]") { + std::unique_ptr LKsim = std::make_unique(); + + std::vector> gradients; + std::vector Qs = LKsim->AllocateQubits(0); + REQUIRE_NOTHROW(LKsim->Gradient(gradients, {})); +} From 4a843417f56c4efc4c7d805c707043c86d494181 Mon Sep 17 00:00:00 2001 From: Ali Asadi <10773383+maliasadi@users.noreply.github.com> Date: Mon, 24 Jun 2024 12:55:36 -0400 Subject: [PATCH 21/34] Add gradient tests --- .../tests/Test_LightningKokkosGradient.cpp | 87 +++++++++++++++++++ pennylane_lightning/core/src/utils/config.h | 3 +- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp index 741f53e106..f23d26d3a0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp @@ -17,6 +17,14 @@ /// @cond DEV namespace { +// MemRef type definition (Helper) +template struct MemRefT { + T *data_allocated; + T *data_aligned; + size_t offset; + size_t sizes[R]; + size_t strides[R]; +}; using namespace Catalyst::Runtime::Simulator; using LKSimulator = LightningKokkosSimulator; } // namespace @@ -29,3 +37,82 @@ TEST_CASE("Zero qubits. Zero parameters", "[Gradient]") { std::vector Qs = LKsim->AllocateQubits(0); REQUIRE_NOTHROW(LKsim->Gradient(gradients, {})); } + +TEST_CASE("Test Gradient with zero number of obs", "[Gradient]") +{ + std::unique_ptr sim = std::make_unique(); + + std::vector buffer(1); + std::vector> gradients; + gradients.emplace_back(buffer); + + std::vector trainParams{0}; + + const auto q = sim->AllocateQubit(); + + sim->StartTapeRecording(); + + sim->NamedOperation("S", {}, {q}, false); + sim->NamedOperation("T", {}, {q}, false); + + REQUIRE_NOTHROW(sim->Gradient(gradients, trainParams)); + + sim->StopTapeRecording(); +} + +TEST_CASE("Test Gradient with Var", "[Gradient]") +{ + std::unique_ptr sim = std::make_unique(); + + std::vector buffer(1); + std::vector> gradients; + gradients.emplace_back(buffer); + + std::vector trainParams{0}; + + const auto q = sim->AllocateQubit(); + + sim->StartTapeRecording(); + + sim->NamedOperation("RX", {-M_PI / 7}, {q}, false); + auto pz = sim->Observable(ObsId::PauliZ, {}, {q}); + sim->Var(pz); + + REQUIRE_THROWS_WITH(sim->Gradient(gradients, trainParams), + Catch::Contains("Unsupported measurements to compute gradient")); + + REQUIRE_THROWS_WITH(sim->Gradient(gradients, {}), + Catch::Contains("Unsupported measurements to compute gradient")); + + sim->StopTapeRecording(); +} + +TEST_CASE("Test Gradient with Op=RX, Obs=Z", "[Gradient]") +{ + std::unique_ptr sim = std::make_unique(); + + std::vector buffer(1); + std::vector> gradients; + gradients.emplace_back(buffer); + + std::vector trainParams{0}; + + const auto q = sim->AllocateQubit(); + + sim->StartTapeRecording(); + + sim->NamedOperation("RX", {-M_PI / 7}, {q}, false); + auto pz = sim->Observable(ObsId::PauliZ, {}, {q}); + sim->Expval(pz); + + sim->Gradient(gradients, trainParams); + CHECK(-sin(-M_PI / 7) == Approx(buffer[0]).margin(1e-5)); + + + // Update buffer + buffer[0] = 0.0; + sim->Gradient(gradients, {}); + CHECK(-sin(-M_PI / 7) == Approx(buffer[0]).margin(1e-5)); + + sim->StopTapeRecording(); +} diff --git a/pennylane_lightning/core/src/utils/config.h b/pennylane_lightning/core/src/utils/config.h index d9c12fd532..384357892b 100644 --- a/pennylane_lightning/core/src/utils/config.h +++ b/pennylane_lightning/core/src/utils/config.h @@ -17,7 +17,8 @@ * Config file for the path to scipy.libs at compile time. */ + #ifndef CONFIG_H #define CONFIG_H -#define SCIPY_LIBS_PATH "" +#define SCIPY_LIBS_PATH "/home/ali/miniforge3/envs/cat/lib/python3.11/site-packages/scipy.libs" #endif From 43f17613d443feb07455f7f99b9280207b91f603 Mon Sep 17 00:00:00 2001 From: Ali Asadi <10773383+maliasadi@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:36:07 -0400 Subject: [PATCH 22/34] Update tests --- .../tests/Test_LightningKokkosGradient.cpp | 218 ++++++++++++++++-- pennylane_lightning/core/src/utils/config.h | 4 +- 2 files changed, 201 insertions(+), 21 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp index f23d26d3a0..1b924ebb7c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosGradient.cpp @@ -18,12 +18,12 @@ /// @cond DEV namespace { // MemRef type definition (Helper) -template struct MemRefT { +template struct MemRefT { T *data_allocated; T *data_aligned; - size_t offset; - size_t sizes[R]; - size_t strides[R]; + std::size_t offset; + std::size_t sizes[R]; + std::size_t strides[R]; }; using namespace Catalyst::Runtime::Simulator; using LKSimulator = LightningKokkosSimulator; @@ -38,15 +38,14 @@ TEST_CASE("Zero qubits. Zero parameters", "[Gradient]") { REQUIRE_NOTHROW(LKsim->Gradient(gradients, {})); } -TEST_CASE("Test Gradient with zero number of obs", "[Gradient]") -{ +TEST_CASE("Test Gradient with zero number of obs", "[Gradient]") { std::unique_ptr sim = std::make_unique(); std::vector buffer(1); std::vector> gradients; gradients.emplace_back(buffer); - std::vector trainParams{0}; + const std::vector trainParams{0}; const auto q = sim->AllocateQubit(); @@ -54,21 +53,20 @@ TEST_CASE("Test Gradient with zero number of obs", "[Gradient]") sim->NamedOperation("S", {}, {q}, false); sim->NamedOperation("T", {}, {q}, false); - + REQUIRE_NOTHROW(sim->Gradient(gradients, trainParams)); sim->StopTapeRecording(); } -TEST_CASE("Test Gradient with Var", "[Gradient]") -{ +TEST_CASE("Test Gradient with Var", "[Gradient]") { std::unique_ptr sim = std::make_unique(); std::vector buffer(1); std::vector> gradients; gradients.emplace_back(buffer); - std::vector trainParams{0}; + const std::vector trainParams{0}; const auto q = sim->AllocateQubit(); @@ -78,41 +76,223 @@ TEST_CASE("Test Gradient with Var", "[Gradient]") auto pz = sim->Observable(ObsId::PauliZ, {}, {q}); sim->Var(pz); - REQUIRE_THROWS_WITH(sim->Gradient(gradients, trainParams), + REQUIRE_THROWS_WITH( + sim->Gradient(gradients, trainParams), Catch::Contains("Unsupported measurements to compute gradient")); - REQUIRE_THROWS_WITH(sim->Gradient(gradients, {}), + REQUIRE_THROWS_WITH( + sim->Gradient(gradients, {}), Catch::Contains("Unsupported measurements to compute gradient")); sim->StopTapeRecording(); } -TEST_CASE("Test Gradient with Op=RX, Obs=Z", "[Gradient]") -{ +TEST_CASE("Test Gradient with Op=RX, Obs=Z", "[Gradient]") { std::unique_ptr sim = std::make_unique(); std::vector buffer(1); std::vector> gradients; gradients.emplace_back(buffer); - std::vector trainParams{0}; + const std::vector trainParams{0}; const auto q = sim->AllocateQubit(); sim->StartTapeRecording(); sim->NamedOperation("RX", {-M_PI / 7}, {q}, false); - auto pz = sim->Observable(ObsId::PauliZ, {}, {q}); - sim->Expval(pz); + auto obs = sim->Observable(ObsId::PauliZ, {}, {q}); + sim->Expval(obs); sim->Gradient(gradients, trainParams); CHECK(-sin(-M_PI / 7) == Approx(buffer[0]).margin(1e-5)); - // Update buffer buffer[0] = 0.0; + sim->Gradient(gradients, {}); CHECK(-sin(-M_PI / 7) == Approx(buffer[0]).margin(1e-5)); sim->StopTapeRecording(); } + +TEST_CASE("Test Gradient with Op=RX, Obs=Hermitian", "[Gradient]") { + std::unique_ptr sim = std::make_unique(); + + std::vector buffer(1); + std::vector> gradients; + gradients.emplace_back(buffer); + + const std::vector trainParams{0}; + + constexpr double expected{0.2169418696}; + + const auto q = sim->AllocateQubit(); + + sim->StartTapeRecording(); + + sim->NamedOperation("RX", {-M_PI / 7}, {q}, false); + + std::vector> mat{ + {1.0, 0.0}, {0.0, 0.0}, {2.0, 0.0}, {0.0, 0.0}}; + + auto obs = sim->Observable(ObsId::Hermitian, mat, {q}); + + sim->Expval(obs); + + sim->Gradient(gradients, trainParams); + CHECK(expected == Approx(buffer[0]).margin(1e-5)); + + // Update buffer + buffer[0] = 0.0; + + sim->Gradient(gradients, {}); + CHECK(expected == Approx(buffer[0]).margin(1e-5)); + + sim->StopTapeRecording(); +} + +TEST_CASE("Test Gradient with Op=[RX,RX,RX,CZ], Obs=[Z,Z,Z]", "[Gradient]") { + std::unique_ptr sim = std::make_unique(); + + constexpr std::size_t num_parms = 3; + + std::vector buffer_p0(num_parms); + std::vector buffer_p1(num_parms); + std::vector buffer_p2(num_parms); + std::vector> gradients; + gradients.emplace_back(buffer_p0); + gradients.emplace_back(buffer_p1); + gradients.emplace_back(buffer_p2); + + const std::vector trainParams{0, 1, 2}; + + const std::vector param{-M_PI / 7, M_PI / 5, 2 * M_PI / 3}; + const std::vector expected{-sin(param[0]), -sin(param[1]), + -sin(param[2])}; + + const auto Qs = sim->AllocateQubits(num_parms); + + sim->StartTapeRecording(); + + sim->NamedOperation("RX", {param[0]}, {Qs[0]}, false); + sim->NamedOperation("RX", {param[1]}, {Qs[1]}, false); + sim->NamedOperation("RX", {param[2]}, {Qs[2]}, false); + sim->NamedOperation("CZ", {}, {Qs[0], Qs[2]}, false); + + std::vector> mat{ + {1.0, 0.0}, {0.0, 0.0}, {2.0, 0.0}, {0.0, 0.0}}; + + auto obs0 = sim->Observable(ObsId::PauliZ, {}, {Qs[0]}); + auto obs1 = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + auto obs2 = sim->Observable(ObsId::PauliZ, {}, {Qs[2]}); + + sim->Expval(obs0); + sim->Expval(obs1); + sim->Expval(obs2); + + sim->Gradient(gradients, trainParams); + CHECK(expected[0] == Approx(buffer_p0[0]).margin(1e-5)); + CHECK(expected[1] == Approx(buffer_p1[1]).margin(1e-5)); + CHECK(expected[2] == Approx(buffer_p2[2]).margin(1e-5)); + + sim->StopTapeRecording(); +} + +TEST_CASE("Test Gradient with Op=Mixed, Obs=Hamiltonian([Z@Z, H], {0.2, 0.6})", + "[Gradient]") { + std::unique_ptr sim = std::make_unique(); + + constexpr std::size_t num_parms = 6; + + std::vector buffer(num_parms); + std::vector> gradients; + gradients.emplace_back(buffer); + + const std::vector trainParams{0, 1, 2, 3, 4, 5}; + + const std::vector param{-M_PI / 7, M_PI / 5, 2 * M_PI / 3}; + const std::vector expected{0.0, -0.2493761627, 0.0, + 0.0, -0.1175570505, 0.0}; + + const auto Qs = sim->AllocateQubits(3); + + sim->StartTapeRecording(); + + sim->NamedOperation("RZ", {param[0]}, {Qs[0]}, false); + sim->NamedOperation("RY", {param[1]}, {Qs[0]}, false); + sim->NamedOperation("RZ", {param[2]}, {Qs[0]}, false); + sim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); + sim->NamedOperation("CNOT", {}, {Qs[1], Qs[2]}, false); + sim->NamedOperation("RZ", {param[0]}, {Qs[1]}, false); + sim->NamedOperation("RY", {param[1]}, {Qs[1]}, false); + sim->NamedOperation("RZ", {param[2]}, {Qs[1]}, false); + + std::vector> mat{ + {1.0, 0.0}, {0.0, 0.0}, {2.0, 0.0}, {0.0, 0.0}}; + + auto obs0 = sim->Observable(ObsId::PauliZ, {}, {Qs[0]}); + auto obs1 = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); + auto obs2 = sim->TensorObservable({obs0, obs1}); + auto obs3 = sim->Observable(ObsId::Hadamard, {}, {Qs[2]}); + auto obs4 = sim->HamiltonianObservable({0.2, 0.6}, {obs2, obs3}); + + sim->Expval(obs4); + + sim->Gradient(gradients, trainParams); + + for (std::size_t i = 0; i < num_parms; i++) { + CAPTURE(i); + CHECK(expected[i] == Approx(buffer[i]).margin(1e-5)); + buffer[i] = 0.0; + } + + sim->Gradient(gradients, {}); + + for (std::size_t i = 0; i < num_parms; i++) { + CAPTURE(i); + CHECK(expected[i] == Approx(buffer[i]).margin(1e-5)); + } + + sim->StopTapeRecording(); +} + +TEST_CASE("Test Gradient with QubitUnitary", "[Gradient]") { + std::unique_ptr sim = std::make_unique(); + + std::vector buffer(1); + std::vector> gradients; + gradients.emplace_back(buffer); + + const std::vector trainParams{0}; + + constexpr double expected{-0.8611041863}; + + const std::vector> matrix{ + {-0.6709485262524046, -0.6304426335363695}, + {-0.14885403153998722, 0.3608498832392019}, + {-0.2376311670004963, 0.3096798175687841}, + {-0.8818365947322423, -0.26456390390903695}, + }; + + const auto Qs = sim->AllocateQubits(1); + + sim->StartTapeRecording(); + + sim->NamedOperation("RX", {-M_PI / 7}, {Qs[0]}, false); + sim->MatrixOperation(matrix, {Qs[0]}, false); + + auto obs = sim->Observable(ObsId::PauliY, {}, {Qs[0]}); + sim->Expval(obs); + + sim->Gradient(gradients, trainParams); + CHECK(expected == Approx(buffer[0]).margin(1e-5)); + + // Update buffer + buffer[0] = 0.0; + + sim->Gradient(gradients, {}); + CHECK(expected == Approx(buffer[0]).margin(1e-5)); + + sim->StopTapeRecording(); +} diff --git a/pennylane_lightning/core/src/utils/config.h b/pennylane_lightning/core/src/utils/config.h index 384357892b..20e4cf0a84 100644 --- a/pennylane_lightning/core/src/utils/config.h +++ b/pennylane_lightning/core/src/utils/config.h @@ -17,8 +17,8 @@ * Config file for the path to scipy.libs at compile time. */ - #ifndef CONFIG_H #define CONFIG_H -#define SCIPY_LIBS_PATH "/home/ali/miniforge3/envs/cat/lib/python3.11/site-packages/scipy.libs" +#define SCIPY_LIBS_PATH \ + "/home/ali/miniforge3/envs/cat/lib/python3.11/site-packages/scipy.libs" #endif From 4f57dbefc71eb7cda6e48f11a12586296d70e5ea Mon Sep 17 00:00:00 2001 From: Ali Asadi <10773383+maliasadi@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:46:26 -0400 Subject: [PATCH 23/34] Remove device declarations macros --- .../catalyst/LightningKokkosSimulator.cpp | 91 +++--- .../catalyst/LightningKokkosSimulator.hpp | 81 +++++- .../tests/Test_LightningKokkosMeasures.cpp | 266 +++++++++--------- .../tests/Test_LightningKokkosSimulator.cpp | 66 ++--- 4 files changed, 281 insertions(+), 223 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp index 810a9439fd..0e4b5e81a3 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp @@ -20,7 +20,7 @@ namespace Catalyst::Runtime::Simulator { auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType { - const size_t num_qubits = this->device_sv->getNumQubits(); + const std::size_t num_qubits = this->device_sv->getNumQubits(); if (!num_qubits) { this->device_sv = std::make_unique(1); @@ -29,7 +29,7 @@ auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType { std::vector> data = this->device_sv->getDataVector(); - const size_t dsize = data.size(); + const std::size_t dsize = data.size(); data.resize(dsize << 1UL); auto src = data.begin(); @@ -45,7 +45,7 @@ auto LightningKokkosSimulator::AllocateQubit() -> QubitIdType { return this->qubit_manager.Allocate(num_qubits); } -auto LightningKokkosSimulator::AllocateQubits(size_t num_qubits) +auto LightningKokkosSimulator::AllocateQubits(std::size_t num_qubits) -> std::vector { if (!num_qubits) { return {}; @@ -72,7 +72,7 @@ void LightningKokkosSimulator::ReleaseAllQubits() { this->device_sv = std::make_unique(0); // reset the device } -auto LightningKokkosSimulator::GetNumQubits() const -> size_t { +auto LightningKokkosSimulator::GetNumQubits() const -> std::size_t { return this->device_sv->getNumQubits(); } @@ -89,8 +89,8 @@ void LightningKokkosSimulator::StopTapeRecording() { } auto LightningKokkosSimulator::CacheManagerInfo() - -> std::tuple, - std::vector> { + -> std::tuple, std::vector> { return {this->cache_manager.getNumOperations(), this->cache_manager.getNumObservables(), this->cache_manager.getNumParams(), @@ -98,11 +98,11 @@ auto LightningKokkosSimulator::CacheManagerInfo() this->cache_manager.getObservablesKeys()}; } -void LightningKokkosSimulator::SetDeviceShots(size_t shots) { +void LightningKokkosSimulator::SetDeviceShots(std::size_t shots) { this->device_shots = shots; } -auto LightningKokkosSimulator::GetDeviceShots() const -> size_t { +auto LightningKokkosSimulator::GetDeviceShots() const -> std::size_t { return this->device_shots; } @@ -113,8 +113,8 @@ void LightningKokkosSimulator::PrintState() { Kokkos::View *, Kokkos::HostSpace, Kokkos::MemoryTraits>; - const size_t num_qubits = this->device_sv->getNumQubits(); - const size_t size = Pennylane::Util::exp2(num_qubits); + const std::size_t num_qubits = this->device_sv->getNumQubits(); + const std::size_t size = Pennylane::Util::exp2(num_qubits); std::vector> state(size, {0.0, 0.0}); auto *state_kptr = @@ -122,7 +122,7 @@ void LightningKokkosSimulator::PrintState() { auto device_data = this->device_sv->getView(); Kokkos::deep_copy(UnmanagedComplexHostView(state_kptr, size), device_data); - size_t idx = 0; + std::size_t idx = 0; cout << "*** State-Vector of Size " << size << " ***" << endl; cout << "["; for (; idx < size - 1; idx++) { @@ -273,8 +273,8 @@ void LightningKokkosSimulator::State(DataView, 1> &state) { Kokkos::View *, Kokkos::HostSpace, Kokkos::MemoryTraits>; - const size_t num_qubits = this->device_sv->getNumQubits(); - const size_t size = Pennylane::Util::exp2(num_qubits); + const std::size_t num_qubits = this->device_sv->getNumQubits(); + const std::size_t size = Pennylane::Util::exp2(num_qubits); RT_FAIL_IF(state.size() != size, "Invalid size for the pre-allocated state vector"); @@ -304,8 +304,8 @@ void LightningKokkosSimulator::Probs(DataView &probs) { void LightningKokkosSimulator::PartialProbs( DataView &probs, const std::vector &wires) { - const size_t numWires = wires.size(); - const size_t numQubits = this->GetNumQubits(); + const std::size_t numWires = wires.size(); + const std::size_t numQubits = this->GetNumQubits(); RT_FAIL_IF(numWires > numQubits, "Invalid number of wires"); RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); @@ -323,7 +323,7 @@ void LightningKokkosSimulator::PartialProbs( } void LightningKokkosSimulator::Sample(DataView &samples, - size_t shots) { + std::size_t shots) { Pennylane::LightningKokkos::Measures::Measurements m{ *(this->device_sv)}; // PL-Lightning-Kokkos generates samples using the alias method. @@ -333,15 +333,15 @@ void LightningKokkosSimulator::Sample(DataView &samples, RT_FAIL_IF(samples.size() != li_samples.size(), "Invalid size for the pre-allocated samples"); - const size_t numQubits = this->GetNumQubits(); + const std::size_t numQubits = this->GetNumQubits(); // The lightning samples are layed out as a single vector of size // shots*qubits, where each element represents a single bit. The // corresponding shape is (shots, qubits). Gather the desired bits // corresponding to the input wires into a bitstring. auto samplesIter = samples.begin(); - for (size_t shot = 0; shot < shots; shot++) { - for (size_t wire = 0; wire < numQubits; wire++) { + for (std::size_t shot = 0; shot < shots; shot++) { + for (std::size_t wire = 0; wire < numQubits; wire++) { *(samplesIter++) = static_cast(li_samples[shot * numQubits + wire]); } @@ -349,9 +349,9 @@ void LightningKokkosSimulator::Sample(DataView &samples, } void LightningKokkosSimulator::PartialSample( DataView &samples, const std::vector &wires, - size_t shots) { - const size_t numWires = wires.size(); - const size_t numQubits = this->GetNumQubits(); + std::size_t shots) { + const std::size_t numWires = wires.size(); + const std::size_t numQubits = this->GetNumQubits(); RT_FAIL_IF(numWires > numQubits, "Invalid number of wires"); RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); @@ -374,7 +374,7 @@ void LightningKokkosSimulator::PartialSample( // corresponding shape is (shots, qubits). Gather the desired bits // corresponding to the input wires into a bitstring. auto samplesIter = samples.begin(); - for (size_t shot = 0; shot < shots; shot++) { + for (std::size_t shot = 0; shot < shots; shot++) { for (auto wire : dev_wires) { *(samplesIter++) = static_cast(li_samples[shot * numQubits + wire]); @@ -384,9 +384,9 @@ void LightningKokkosSimulator::PartialSample( void LightningKokkosSimulator::Counts(DataView &eigvals, DataView &counts, - size_t shots) { - const size_t numQubits = this->GetNumQubits(); - const size_t numElements = 1U << numQubits; + std::size_t shots) { + const std::size_t numQubits = this->GetNumQubits(); + const std::size_t numElements = 1U << numQubits; RT_FAIL_IF(eigvals.size() != numElements || counts.size() != numElements, "Invalid size for the pre-allocated counts"); @@ -410,22 +410,22 @@ void LightningKokkosSimulator::Counts(DataView &eigvals, // shots*qubits, where each element represents a single bit. The // corresponding shape is (shots, qubits). Gather the bits of all qubits // into a bitstring. - for (size_t shot = 0; shot < shots; shot++) { + for (std::size_t shot = 0; shot < shots; shot++) { std::bitset basisState; - size_t idx = numQubits; - for (size_t wire = 0; wire < numQubits; wire++) { + std::size_t idx = numQubits; + for (std::size_t wire = 0; wire < numQubits; wire++) { basisState[--idx] = li_samples[shot * numQubits + wire]; } - counts(static_cast(basisState.to_ulong())) += 1; + counts(static_cast(basisState.to_ulong())) += 1; } } void LightningKokkosSimulator::PartialCounts( DataView &eigvals, DataView &counts, - const std::vector &wires, size_t shots) { - const size_t numWires = wires.size(); - const size_t numQubits = this->GetNumQubits(); - const size_t numElements = 1U << numWires; + const std::vector &wires, std::size_t shots) { + const std::size_t numWires = wires.size(); + const std::size_t numQubits = this->GetNumQubits(); + const std::size_t numElements = 1U << numWires; RT_FAIL_IF(numWires > numQubits, "Invalid number of wires"); RT_FAIL_IF(!isValidQubits(wires), "Invalid given wires to measure"); @@ -454,13 +454,13 @@ void LightningKokkosSimulator::PartialCounts( // shots*qubits, where each element represents a single bit. The // corresponding shape is (shots, qubits). Gather the desired bits // corresponding to the input wires into a bitstring. - for (size_t shot = 0; shot < shots; shot++) { + for (std::size_t shot = 0; shot < shots; shot++) { std::bitset basisState; - size_t idx = dev_wires.size(); + std::size_t idx = dev_wires.size(); for (auto wire : dev_wires) { basisState[--idx] = li_samples[shot * numQubits + wire]; } - counts(static_cast(basisState.to_ulong())) += 1; + counts(static_cast(basisState.to_ulong())) += 1; } } @@ -486,12 +486,13 @@ auto LightningKokkosSimulator::Measure(QubitIdType wire, void LightningKokkosSimulator::Gradient( std::vector> &gradients, - const std::vector &trainParams) { + const std::vector &trainParams) { const bool tp_empty = trainParams.empty(); - const size_t num_observables = this->cache_manager.getNumObservables(); - const size_t num_params = this->cache_manager.getNumParams(); - const size_t num_train_params = tp_empty ? num_params : trainParams.size(); - const size_t jac_size = + const std::size_t num_observables = this->cache_manager.getNumObservables(); + const std::size_t num_params = this->cache_manager.getNumParams(); + const std::size_t num_train_params = + tp_empty ? num_params : trainParams.size(); + const std::size_t jac_size = num_train_params * this->cache_manager.getNumObservables(); if (!jac_size) { @@ -535,10 +536,10 @@ void LightningKokkosSimulator::Gradient( obs_vec.emplace_back(this->obs_manager.getObservable(idx)); } - std::vector all_params; + std::vector all_params; if (tp_empty) { all_params.reserve(num_params); - for (size_t i = 0; i < num_params; i++) { + for (std::size_t i = 0; i < num_params; i++) { all_params.push_back(i); } } @@ -558,7 +559,7 @@ void LightningKokkosSimulator::Gradient( std::vector cur_buffer(num_train_params); auto begin_loc_iter = jacobian.begin(); - for (size_t obs_idx = 0; obs_idx < num_observables; obs_idx++) { + for (std::size_t obs_idx = 0; obs_idx < num_observables; obs_idx++) { RT_ASSERT(begin_loc_iter != jacobian.end()); RT_ASSERT(num_train_params <= gradients[obs_idx].size()); std::move(begin_loc_iter, begin_loc_iter + num_train_params, diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp index ef5148edf8..26e799615f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp @@ -20,8 +20,10 @@ #include #include #include +#include #include #include +#include #include "AdjointJacobianKokkos.hpp" #include "MeasurementsKokkos.hpp" @@ -43,11 +45,11 @@ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { static constexpr bool GLOBAL_RESULT_TRUE_CONST = true; static constexpr bool GLOBAL_RESULT_FALSE_CONST = false; - Catalyst::Runtime::QubitManager qubit_manager{}; + Catalyst::Runtime::QubitManager qubit_manager{}; Catalyst::Runtime::CacheManager> cache_manager{}; bool tape_recording{false}; - size_t device_shots; + std::size_t device_shots; std::unique_ptr device_sv = std::make_unique(0); LightningKokkosObsManager obs_manager{}; @@ -62,7 +64,7 @@ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { }); } - inline auto isValidQubits(size_t numWires, const QubitIdType *wires) + inline auto isValidQubits(std::size_t numWires, const QubitIdType *wires) -> bool { return std::all_of(wires, wires + numWires, [this](QubitIdType w) { return this->isValidQubit(w); @@ -70,8 +72,8 @@ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { } inline auto getDeviceWires(const std::vector &wires) - -> std::vector { - std::vector res; + -> std::vector { + std::vector res; res.reserve(wires.size()); std::transform( wires.begin(), wires.end(), std::back_inserter(res), @@ -83,18 +85,73 @@ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { explicit LightningKokkosSimulator(const std::string &kwargs = "{}") { auto &&args = Catalyst::Runtime::parse_kwargs(kwargs); device_shots = args.contains("shots") - ? static_cast(std::stoll(args["shots"])) + ? static_cast(std::stoll(args["shots"])) : 0; } ~LightningKokkosSimulator() = default; - QUANTUM_DEVICE_DEL_DECLARATIONS(LightningKokkosSimulator); - - QUANTUM_DEVICE_RT_DECLARATIONS; - QUANTUM_DEVICE_QIS_DECLARATIONS; + LightningKokkosSimulator(const LightningKokkosSimulator &) = delete; + LightningKokkosSimulator & + operator=(const LightningKokkosSimulator &) = delete; + LightningKokkosSimulator(LightningKokkosSimulator &&) = delete; + LightningKokkosSimulator &operator=(LightningKokkosSimulator &&) = delete; + + auto AllocateQubit() -> QubitIdType override; + auto AllocateQubits(size_t num_qubits) -> std::vector override; + void ReleaseQubit(QubitIdType q) override; + void ReleaseAllQubits() override; + [[nodiscard]] auto GetNumQubits() const -> size_t override; + void StartTapeRecording() override; + void StopTapeRecording() override; + void SetDeviceShots(size_t shots) override; + [[nodiscard]] auto GetDeviceShots() const -> size_t override; + void PrintState() override; + [[nodiscard]] auto Zero() const -> Result override; + [[nodiscard]] auto One() const -> Result override; + + void + NamedOperation(const std::string &name, const std::vector ¶ms, + const std::vector &wires, bool inverse = false, + const std::vector &controlled_wires = {}, + const std::vector &controlled_values = {}) override; + using Catalyst::Runtime::QuantumDevice::MatrixOperation; + void + MatrixOperation(const std::vector> &matrix, + const std::vector &wires, bool inverse = false, + const std::vector &controlled_wires = {}, + const std::vector &controlled_values = {}) override; + auto Observable(ObsId id, const std::vector> &matrix, + const std::vector &wires) + -> ObsIdType override; + auto TensorObservable(const std::vector &obs) + -> ObsIdType override; + auto HamiltonianObservable(const std::vector &coeffs, + const std::vector &obs) + -> ObsIdType override; + auto Expval(ObsIdType obsKey) -> double override; + auto Var(ObsIdType obsKey) -> double override; + void State(DataView, 1> &state) override; + void Probs(DataView &probs) override; + void PartialProbs(DataView &probs, + const std::vector &wires) override; + void Sample(DataView &samples, size_t shots) override; + void PartialSample(DataView &samples, + const std::vector &wires, + size_t shots) override; + void Counts(DataView &eigvals, DataView &counts, + size_t shots) override; + void PartialCounts(DataView &eigvals, + DataView &counts, + const std::vector &wires, + size_t shots) override; + auto Measure(QubitIdType wire, + std::optional postselect = std::nullopt) + -> Result override; + void Gradient(std::vector> &gradients, + const std::vector &trainParams) override; auto CacheManagerInfo() - -> std::tuple, - std::vector>; + -> std::tuple, std::vector>; }; } // namespace Catalyst::Runtime::Simulator diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp index 4266030822..bce2754c01 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp @@ -24,12 +24,12 @@ /// @cond DEV namespace { // MemRef type definition (Helper) -template struct MemRefT { +template struct MemRefT { T *data_allocated; T *data_aligned; - size_t offset; - size_t sizes[R]; - size_t strides[R]; + std::size_t offset; + std::size_t sizes[R]; + std::size_t strides[R]; }; using namespace Catalyst::Runtime::Simulator; using LKSimulator = LightningKokkosSimulator; @@ -79,7 +79,7 @@ TEST_CASE("Check an unsupported observable", "[Measures]") { TEST_CASE("Measurement collapse test with 2 wires", "[Measures]") { std::unique_ptr sim = std::make_unique(); - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs = sim->AllocateQubits(n); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -106,7 +106,7 @@ TEST_CASE("Measurement collapse concrete logical qubit difference", "[Measures]") { std::unique_ptr sim = std::make_unique(); - constexpr size_t n = 1; + constexpr std::size_t n = 1; // The first time an array is allocated, logical and concrete qubits // are the same. std::vector Qs = sim->AllocateQubits(n); @@ -201,10 +201,10 @@ TEST_CASE("Expval(NamedObs) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -226,10 +226,10 @@ TEST_CASE("Expval(NamedObs) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -241,7 +241,7 @@ TEST_CASE("Expval(NamedObs) shots test", "[Measures]") { ObsIdType py = sim->Observable(ObsId::PauliY, {}, {Qs[1]}); ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); CHECK(sim->Expval(px) == Approx(0.0).margin(5e-2)); @@ -253,10 +253,10 @@ TEST_CASE("Expval(HermitianObs) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -278,14 +278,14 @@ TEST_CASE("Expval(HermitianObs) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -309,14 +309,14 @@ TEST_CASE("Var(HermitianObs) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -339,10 +339,10 @@ TEST_CASE("Expval(TensorProd(NamedObs)) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -367,10 +367,10 @@ TEST_CASE("Expval(TensorProd(NamedObs)) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -386,7 +386,7 @@ TEST_CASE("Expval(TensorProd(NamedObs)) shots test", "[Measures]") { ObsIdType tpy = sim->TensorObservable({py}); ObsIdType tpz = sim->TensorObservable({pz}); - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); CHECK(sim->Expval(tpx) == Approx(1.0).margin(5e-2)); @@ -398,10 +398,10 @@ TEST_CASE("Expval(TensorProd(NamedObs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -429,15 +429,15 @@ TEST_CASE("Expval(TensorProd(NamedObs[])) shots test", "[Measures]") { std::unique_ptr sim0 = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); Qs.push_back(sim0->AllocateQubit()); } - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); sim->NamedOperation("PauliX", {}, {Qs[0]}, false); @@ -463,10 +463,10 @@ TEST_CASE("Expval(TensorProd(HermitianObs))", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -490,10 +490,10 @@ TEST_CASE("Expval(TensorProd(HermitianObs[]))", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -515,10 +515,10 @@ TEST_CASE("Expval(TensorProd(Obs[]))", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -544,10 +544,10 @@ TEST_CASE("Expval(Tensor(Hamiltonian(NamedObs[]), NamedObs)) test", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -569,7 +569,7 @@ TEST_CASE("Expval(Tensor(HermitianObs, Hamiltonian()) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 3; + constexpr std::size_t n = 3; std::vector Qs = sim->AllocateQubits(n); sim->NamedOperation("PauliX", {}, {Qs[0]}, false); @@ -592,10 +592,10 @@ TEST_CASE("Expval(Hamiltonian(NamedObs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -616,10 +616,10 @@ TEST_CASE("Expval(Hamiltonian(NamedObs[])) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -633,7 +633,7 @@ TEST_CASE("Expval(Hamiltonian(NamedObs[])) shots test", "[Measures]") { ObsIdType pz = sim->Observable(ObsId::PauliZ, {}, {Qs[1]}); ObsIdType hxyz = sim->HamiltonianObservable({0.4, 0.8, 0.2}, {px, py, pz}); - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); CHECK(sim->Expval(hxyz) == Approx(0.2).margin(5e-2)); @@ -643,10 +643,10 @@ TEST_CASE("Expval(Hamiltonian(TensorObs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -669,10 +669,10 @@ TEST_CASE("Expval(Hamiltonian(Hermitian[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -696,10 +696,10 @@ TEST_CASE("Expval(Hamiltonian({TensorProd, Hermitian}[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -725,10 +725,10 @@ TEST_CASE("Expval(Hamiltonian({Hamiltonian, Hermitian}[])) test", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -754,10 +754,10 @@ TEST_CASE("Expval(Hamiltonian({Hamiltonian(Hamiltonian), Hermitian}[])) test", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -783,10 +783,10 @@ TEST_CASE("Var(NamedObs) test with numWires=4", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -808,14 +808,14 @@ TEST_CASE("Var(NamedObs) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } - constexpr size_t num_shots = 5000; + constexpr std::size_t num_shots = 5000; sim->SetDeviceShots(num_shots); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -830,10 +830,10 @@ TEST_CASE("Var(HermitianObs) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -855,10 +855,10 @@ TEST_CASE("Var(TensorProd(NamedObs)) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -883,14 +883,14 @@ TEST_CASE("Var(TensorProd(NamedObs)) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); sim->NamedOperation("PauliX", {}, {Qs[0]}, false); @@ -911,10 +911,10 @@ TEST_CASE("Var(TensorProd(NamedObs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -937,10 +937,10 @@ TEST_CASE("Var(TensorProd(HermitianObs)) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -964,10 +964,10 @@ TEST_CASE("Var(TensorProd(HermitianObs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 2; + constexpr std::size_t n = 2; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -989,10 +989,10 @@ TEST_CASE("Var(TensorProd(Obs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1017,10 +1017,10 @@ TEST_CASE("Var(Tensor(Hamiltonian(NamedObs[]), NamedObs)) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1042,14 +1042,14 @@ TEST_CASE("Var(Tensor(NamedObs[])) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } - constexpr size_t num_shots = 5000; + constexpr std::size_t num_shots = 5000; sim->SetDeviceShots(num_shots); sim->NamedOperation("PauliX", {}, {Qs[0]}, false); @@ -1070,14 +1070,14 @@ TEST_CASE("Var(Tensor(NamedObs[])) shots test without gates " std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 3; + constexpr std::size_t n = 3; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } - constexpr size_t num_shots = 5000; + constexpr std::size_t num_shots = 5000; sim->SetDeviceShots(num_shots); sim->NamedOperation("PauliX", {}, {Qs[0]}, false); @@ -1096,7 +1096,7 @@ TEST_CASE("Var(Tensor(HermitianObs, Hamiltonian()) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 3; + constexpr std::size_t n = 3; std::vector Qs = sim->AllocateQubits(n); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -1118,10 +1118,10 @@ TEST_CASE("Var(Tensor(HermitianObs, Hamiltonian()) shots test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 3; + constexpr std::size_t n = 3; std::vector Qs = sim->AllocateQubits(n); - constexpr size_t num_shots = 5000; + constexpr std::size_t num_shots = 5000; sim->SetDeviceShots(num_shots); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -1138,10 +1138,10 @@ TEST_CASE("Var(Hamiltonian(NamedObs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1162,10 +1162,10 @@ TEST_CASE("Var(Hamiltonian(TensorObs[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1188,10 +1188,10 @@ TEST_CASE("Var(Hamiltonian(Hermitian[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1215,10 +1215,10 @@ TEST_CASE("Var(Hamiltonian({TensorProd, Hermitian}[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1243,10 +1243,10 @@ TEST_CASE("Var(Hamiltonian({Hamiltonian, Hermitian}[])) test", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1272,10 +1272,10 @@ TEST_CASE("Var(Hamiltonian({Hamiltonian(Hamiltonian), Hermitian}[])) test", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1301,7 +1301,7 @@ TEST_CASE("State test with incorrect size", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs = sim->AllocateQubits(n); std::vector> state(1U << (n - 1)); @@ -1315,7 +1315,7 @@ TEST_CASE("State test with numWires=4", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs = sim->AllocateQubits(n); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -1327,7 +1327,7 @@ TEST_CASE("State test with numWires=4", "[Measures]") { DataView, 1> view(state); sim->State(view); - for (size_t i = 0; i < 16; i++) { + for (std::size_t i = 0; i < 16; i++) { if (i == 4 || i == 6 || i == 12 || i == 14) { CHECK(std::real(state[i]) == Approx(0.).margin(1e-5)); CHECK(std::imag(state[i]) == Approx(0.5).margin(1e-5)); @@ -1343,10 +1343,10 @@ TEST_CASE("PartialProbs test with incorrect numWires and numAlloc", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1376,10 +1376,10 @@ TEST_CASE("Probs and PartialProbs tests with numWires=0-4", "[Measures]") { std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1412,14 +1412,14 @@ TEST_CASE("Probs and PartialProbs tests with numWires=0-4", "[Measures]") { CHECK(probs0[0] == Approx(1.0)); CHECK(probs1[0] == Approx(0.5).margin(1e-5)); CHECK(probs1[1] == Approx(0.5).margin(1e-5)); - for (size_t i = 0; i < 4; i++) { + for (std::size_t i = 0; i < 4; i++) { if (i == 0 || i == 2) { CHECK(probs2[i] == Approx(0.5).margin(1e-5)); } else { CHECK(probs2[i] == Approx(0.).margin(1e-5)); } } - for (size_t i = 0; i < 16; i++) { + for (std::size_t i = 0; i < 16; i++) { if (i == 4 || i == 6 || i == 12 || i == 14) { CHECK(probs3[i] == Approx(0.25).margin(1e-5)); CHECK(probs4[i] == Approx(0.25).margin(1e-5)); @@ -1435,14 +1435,14 @@ TEST_CASE("Probs and PartialProbs shots tests with numWires=0-4", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } - constexpr size_t num_shots = 10000; + constexpr std::size_t num_shots = 10000; sim->SetDeviceShots(num_shots); sim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -1474,14 +1474,14 @@ TEST_CASE("Probs and PartialProbs shots tests with numWires=0-4", CHECK(probs0[0] == Approx(1.0).margin(5e-2)); CHECK(probs1[0] == Approx(0.5).margin(5e-2)); CHECK(probs1[1] == Approx(0.5).margin(5e-2)); - for (size_t i = 0; i < 4; i++) { + for (std::size_t i = 0; i < 4; i++) { if (i == 0 || i == 2) { CHECK(probs2[i] == Approx(0.5).margin(5e-2)); } else { CHECK(probs2[i] == Approx(0.).margin(5e-2)); } } - for (size_t i = 0; i < 16; i++) { + for (std::size_t i = 0; i < 16; i++) { if (i == 4 || i == 6 || i == 12 || i == 14) { CHECK(probs3[i] == Approx(0.25).margin(5e-2)); CHECK(probs4[i] == Approx(0.25).margin(5e-2)); @@ -1497,10 +1497,10 @@ TEST_CASE("PartialSample test with incorrect numWires and numAlloc", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1536,10 +1536,10 @@ TEST_CASE("PartialCounts test with incorrect numWires and numAlloc", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1574,10 +1574,10 @@ TEST_CASE("Sample and PartialSample tests with numWires=0-4 shots=100", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1585,7 +1585,7 @@ TEST_CASE("Sample and PartialSample tests with numWires=0-4 shots=100", sim->NamedOperation("Hadamard", {}, {Qs[1]}, false); sim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); - size_t shots = 100; + std::size_t shots = 100; std::vector samples1(shots * 1); MemRefT buffer1{ @@ -1615,13 +1615,13 @@ TEST_CASE("Sample and PartialSample tests with numWires=0-4 shots=100", buffer4.sizes, buffer4.strides); sim->Sample(view4, shots); - for (size_t i = 0; i < shots * 1; i++) + for (std::size_t i = 0; i < shots * 1; i++) CHECK((samples1[i] == 0. || samples1[i] == 1.)); - for (size_t i = 0; i < shots * 2; i++) + for (std::size_t i = 0; i < shots * 2; i++) CHECK((samples2[i] == 0. || samples2[i] == 1.)); - for (size_t i = 0; i < shots * 4; i++) + for (std::size_t i = 0; i < shots * 4; i++) CHECK((samples3[i] == 0. || samples3[i] == 1.)); - for (size_t i = 0; i < shots * 4; i++) + for (std::size_t i = 0; i < shots * 4; i++) CHECK((samples4[i] == 0. || samples4[i] == 1.)); } @@ -1632,10 +1632,10 @@ TEST_CASE("Sample and PartialSample tests with numWires=0-4 " std::make_unique("{mcmc : True, num_burnin : 200}"); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs; Qs.reserve(n); - for (size_t i = 0; i < n; i++) { + for (std::size_t i = 0; i < n; i++) { Qs.push_back(sim->AllocateQubit()); } @@ -1643,7 +1643,7 @@ TEST_CASE("Sample and PartialSample tests with numWires=0-4 " sim->NamedOperation("Hadamard", {}, {Qs[1]}, false); sim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); - size_t shots = 100; + std::size_t shots = 100; std::vector samples1(shots * 1); MemRefT buffer1{ @@ -1673,13 +1673,13 @@ TEST_CASE("Sample and PartialSample tests with numWires=0-4 " buffer4.sizes, buffer4.strides); sim->Sample(view4, shots); - for (size_t i = 0; i < shots * 1; i++) + for (std::size_t i = 0; i < shots * 1; i++) CHECK((samples1[i] == 0. || samples1[i] == 1.)); - for (size_t i = 0; i < shots * 2; i++) + for (std::size_t i = 0; i < shots * 2; i++) CHECK((samples2[i] == 0. || samples2[i] == 1.)); - for (size_t i = 0; i < shots * 4; i++) + for (std::size_t i = 0; i < shots * 4; i++) CHECK((samples3[i] == 0. || samples3[i] == 1.)); - for (size_t i = 0; i < shots * 4; i++) + for (std::size_t i = 0; i < shots * 4; i++) CHECK((samples4[i] == 0. || samples4[i] == 1.)); } @@ -1688,14 +1688,14 @@ TEST_CASE("Counts and PartialCounts tests with numWires=0-4 shots=100", std::unique_ptr sim = std::make_unique(); // state-vector with #qubits = n - constexpr size_t n = 4; + constexpr std::size_t n = 4; std::vector Qs = sim->AllocateQubits(n); sim->NamedOperation("RX", {0.5}, {Qs[0]}, false); sim->NamedOperation("Hadamard", {}, {Qs[1]}, false); sim->NamedOperation("CNOT", {}, {Qs[0], Qs[1]}, false); - size_t shots = 100; + std::size_t shots = 100; std::vector eigvals0(1); std::vector counts0(1); @@ -1735,7 +1735,7 @@ TEST_CASE("Counts and PartialCounts tests with numWires=0-4 shots=100", CHECK((eigvals1[0] == 0. && eigvals1[1] == 1.)); CHECK((eigvals2[0] == 0. && eigvals2[1] == 1. && eigvals2[2] == 2. && eigvals2[3] == 3.)); - for (size_t i = 0; i < 16; i++) { + for (std::size_t i = 0; i < 16; i++) { CHECK(eigvals3[i] == static_cast(i)); CHECK(eigvals4[i] == static_cast(i)); } @@ -1743,8 +1743,8 @@ TEST_CASE("Counts and PartialCounts tests with numWires=0-4 shots=100", CHECK(counts1[0] + counts1[1] == static_cast(shots)); CHECK(counts2[0] + counts2[1] + counts2[2] + counts2[3] == static_cast(shots)); - size_t sum3 = 0, sum4 = 0; - for (size_t i = 0; i < 16; i++) { + std::size_t sum3 = 0, sum4 = 0; + for (std::size_t i = 0; i < 16; i++) { sum3 += counts3[i]; sum4 += counts4[i]; } diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp index 32a87d9e77..f290203517 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp @@ -82,14 +82,14 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Identity gate") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 10; + constexpr std::size_t n_qubits = 10; std::vector Qs; Qs.reserve(n_qubits); - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { Qs[ind] = LKsim->AllocateQubit(); } - for (size_t ind = 0; ind < n_qubits; ind += 2) { + for (std::size_t ind = 0; ind < n_qubits; ind += 2) { LKsim->NamedOperation("Identity", {}, {Qs[ind]}, false); } @@ -100,7 +100,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { CHECK(state.at(0) == std::complex{1, 0}); std::complex sum{0, 0}; - for (size_t ind = 1; ind < state.size(); ind++) { + for (std::size_t ind = 1; ind < state.size(); ind++) { sum += state[ind]; } @@ -110,17 +110,17 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("PauliX gate") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 3; + constexpr std::size_t n_qubits = 3; std::vector Qs; Qs.reserve(n_qubits); - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { Qs[ind] = LKsim->AllocateQubit(); } - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { LKsim->NamedOperation("PauliX", {}, {Qs[ind]}, false); } - for (size_t ind = n_qubits; ind > 0; ind--) { + for (std::size_t ind = n_qubits; ind > 0; ind--) { LKsim->NamedOperation("PauliX", {}, {Qs[ind - 1]}, false); } @@ -131,7 +131,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { CHECK(state.at(0) == std::complex{1, 0}); std::complex sum{0, 0}; - for (size_t ind = 1; ind < state.size(); ind++) { + for (std::size_t ind = 1; ind < state.size(); ind++) { sum += state[ind]; } @@ -141,14 +141,14 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("PauliY gate") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs; Qs.reserve(n_qubits); - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { Qs[ind] = LKsim->AllocateQubit(); } - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { LKsim->NamedOperation("PauliY", {}, {Qs[ind]}, false); } @@ -165,10 +165,10 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("PauliY and PauliZ gates") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs; Qs.reserve(n_qubits); - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { Qs[ind] = LKsim->AllocateQubit(); } @@ -188,14 +188,14 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard gate") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs; Qs.reserve(n_qubits); - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { Qs[ind] = LKsim->AllocateQubit(); } - for (size_t ind = 0; ind < n_qubits; ind++) { + for (std::size_t ind = 0; ind < n_qubits; ind++) { LKsim->NamedOperation("Hadamard", {}, {Qs[ind]}, false); } @@ -213,7 +213,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("R(X, Y, Z) and PauliX gates") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 4; + constexpr std::size_t n_qubits = 4; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("PauliX", {}, {Qs[0]}, false); @@ -260,7 +260,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard, RX, PhaseShift with cache manager") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs; Qs.reserve(n_qubits); @@ -289,8 +289,8 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { PLApproxComplex(std::complex{0.01913791, -0.039019}) .epsilon(1e-5)); - std::tuple, - std::vector> + std::tuple, std::vector> expected{3, 0, 2, {"Hadamard", "RX", "PhaseShift"}, {}}; REQUIRE(LKsim->CacheManagerInfo() == expected); } @@ -300,11 +300,11 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("PauliX and CNOT") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs; Qs.reserve(n_qubits); - for (size_t i = 0; i < n_qubits; i++) { + for (std::size_t i = 0; i < n_qubits; i++) { Qs[i] = LKsim->AllocateQubit(); } @@ -324,7 +324,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard and CR(X, Y, Z)") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 4; + constexpr std::size_t n_qubits = 4; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -372,7 +372,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard and CRot") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -401,7 +401,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard, PauliZ, IsingXY, SWAP") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -427,7 +427,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard, PauliX and Toffoli") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 3; + constexpr std::size_t n_qubits = 3; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -455,7 +455,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("RX, Hadamard and MultiRZ") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("RX", {M_PI}, {Qs[1]}, false); @@ -476,7 +476,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard, CNOT and Matrix") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -512,7 +512,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard, CR(X, Y, Z) and Matrix") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 4; + constexpr std::size_t n_qubits = 4; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->NamedOperation("Hadamard", {}, {Qs[0]}, false); @@ -622,7 +622,7 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { SECTION("Hadamard and IsingZZ and cache manager") { std::unique_ptr LKsim = std::make_unique(); - constexpr size_t n_qubits = 2; + constexpr std::size_t n_qubits = 2; std::vector Qs = LKsim->AllocateQubits(n_qubits); LKsim->StartTapeRecording(); @@ -643,8 +643,8 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { CHECK(state[2] == PLApproxComplex(c2).epsilon(1e-5)); CHECK(state[3] == PLApproxComplex(c1).epsilon(1e-5)); - std::tuple, - std::vector> + std::tuple, std::vector> expected{3, 0, 1, {"Hadamard", "Hadamard", "IsingZZ"}, {}}; REQUIRE(LKsim->CacheManagerInfo() == expected); } From 899a2149f62357d76d60a9adf81935c4f77f7486 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 24 Jun 2024 17:47:00 +0000 Subject: [PATCH 24/34] Auto update version from '0.37.0-dev46' to '0.37.0-dev47' --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 8a46df66d0..c243b63bc6 100644 --- a/pennylane_lightning/core/_version.py +++ b/pennylane_lightning/core/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.37.0-dev46" +__version__ = "0.37.0-dev47" From 463cca46c7b09525e80518798b7a70456ef34380 Mon Sep 17 00:00:00 2001 From: Ali Asadi <10773383+maliasadi@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:52:51 -0400 Subject: [PATCH 25/34] Update config --- pennylane_lightning/core/src/utils/config.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/utils/config.h b/pennylane_lightning/core/src/utils/config.h index 20e4cf0a84..d9c12fd532 100644 --- a/pennylane_lightning/core/src/utils/config.h +++ b/pennylane_lightning/core/src/utils/config.h @@ -19,6 +19,5 @@ #ifndef CONFIG_H #define CONFIG_H -#define SCIPY_LIBS_PATH \ - "/home/ali/miniforge3/envs/cat/lib/python3.11/site-packages/scipy.libs" +#define SCIPY_LIBS_PATH "" #endif From 2f9569cefe427ce7b8d14e4877f184cebf93e180 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Tue, 25 Jun 2024 07:14:28 -0400 Subject: [PATCH 26/34] trigger CIs From a5423c1336750005e735e588adc98202a4e1d6be Mon Sep 17 00:00:00 2001 From: Ali Asadi <10773383+maliasadi@users.noreply.github.com> Date: Tue, 25 Jun 2024 09:52:17 -0400 Subject: [PATCH 27/34] Update code coverage --- .../lightning_kokkos/catalyst/CMakeLists.txt | 2 +- .../catalyst/LightningKokkosSimulator.cpp | 4 ++++ .../catalyst/LightningKokkosSimulator.hpp | 1 + .../tests/Test_LightningKokkosMeasures.cpp | 3 +-- .../tests/Test_LightningKokkosSimulator.cpp | 17 ++++++++++++++--- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt index dd0acf3aea..a0f2593a03 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt @@ -89,4 +89,4 @@ target_link_libraries(lightning_kokkos_catalyst PUBLIC lightning_compile_option if (BUILD_TESTS) enable_testing() add_subdirectory("tests") -endif() \ No newline at end of file +endif() diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp index 0e4b5e81a3..6fa4089d8b 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.cpp @@ -106,6 +106,7 @@ auto LightningKokkosSimulator::GetDeviceShots() const -> std::size_t { return this->device_shots; } +/// LCOV_EXCL_START void LightningKokkosSimulator::PrintState() { using std::cout; using std::endl; @@ -130,6 +131,7 @@ void LightningKokkosSimulator::PrintState() { } cout << state[idx] << "]" << endl; } +/// LCOV_EXCL_STOP auto LightningKokkosSimulator::Zero() const -> Result { return const_cast(&GLOBAL_RESULT_FALSE_CONST); @@ -572,5 +574,7 @@ void LightningKokkosSimulator::Gradient( } // namespace Catalyst::Runtime::Simulator +/// LCOV_EXCL_START GENERATE_DEVICE_FACTORY(LightningKokkosSimulator, Catalyst::Runtime::Simulator::LightningKokkosSimulator); +/// LCOV_EXCL_STOP diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp index 26e799615f..34e0c44ad7 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp @@ -154,4 +154,5 @@ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { -> std::tuple, std::vector>; }; + } // namespace Catalyst::Runtime::Simulator diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp index bce2754c01..527c8fddb9 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosMeasures.cpp @@ -15,7 +15,6 @@ #include "CacheManager.hpp" #include "LightningKokkosSimulator.hpp" #include "QuantumDevice.hpp" -#include "RuntimeCAPI.h" #include "Types.h" #include "Utils.hpp" #include "catch2/catch.hpp" @@ -1750,4 +1749,4 @@ TEST_CASE("Counts and PartialCounts tests with numWires=0-4 shots=100", } CHECK(sum3 == shots); CHECK(sum4 == shots); -} \ No newline at end of file +} diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp index f290203517..4df813266d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/tests/Test_LightningKokkosSimulator.cpp @@ -24,7 +24,7 @@ #include #include "LightningKokkosSimulator.hpp" -#include "RuntimeCAPI.h" +#include "QuantumDevice.hpp" #include "TestHelpers.hpp" /// @cond DEV @@ -32,6 +32,10 @@ namespace { using namespace Catalyst::Runtime::Simulator; using namespace Pennylane::Util; using LKSimulator = LightningKokkosSimulator; +using QDevice = Catalyst::Runtime::QuantumDevice; + +GENERATE_DEVICE_FACTORY(LightningKokkosSimulator, + Catalyst::Runtime::Simulator::LightningKokkosSimulator); } // namespace /// @endcond @@ -48,12 +52,19 @@ TEST_CASE("LightningKokkosSimulator::constructor", "[constructibility]") { } } +TEST_CASE("Test the device factory method", "[constructibility]") { + std::unique_ptr LKsim(LightningKokkosSimulatorFactory("")); + REQUIRE(LKsim->GetNumQubits() == 0); +} + TEST_CASE("LightningKokkosSimulator::unit_tests", "[unit tests]") { SECTION("Managing Qubits") { std::unique_ptr LKsim = std::make_unique(); std::vector Qs = LKsim->AllocateQubits(0); REQUIRE(LKsim->GetNumQubits() == 0); - LKsim->AllocateQubits(4); + LKsim->AllocateQubits(2); + REQUIRE(LKsim->GetNumQubits() == 2); + LKsim->AllocateQubits(2); REQUIRE(LKsim->GetNumQubits() == 4); LKsim->ReleaseQubit(0); REQUIRE( @@ -648,4 +659,4 @@ TEST_CASE("LightningKokkosSimulator::GateSet", "[GateSet]") { expected{3, 0, 1, {"Hadamard", "Hadamard", "IsingZZ"}, {}}; REQUIRE(LKsim->CacheManagerInfo() == expected); } -} \ No newline at end of file +} From db9f17a23a3c78d5fa82f3c21dbe54e9d4925c06 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Wed, 26 Jun 2024 14:18:15 -0400 Subject: [PATCH 28/34] review suggestions --- .../lightning_kokkos/catalyst/CMakeLists.txt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt index a0f2593a03..cdf0570904 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/CMakeLists.txt @@ -2,28 +2,28 @@ cmake_minimum_required(VERSION 3.20) project(lightning_kokkos_catalyst LANGUAGES CXX) -set(CATALYST_FILES LightningKokkosSimulator.cpp CACHE INTERNAL "" FORCE) -add_library(lightning_kokkos_catalyst SHARED ${CATALYST_FILES}) +set(LK_CATALYST_FILES LightningKokkosSimulator.cpp CACHE INTERNAL "") +add_library(lightning_kokkos_catalyst SHARED ${LK_CATALYST_FILES}) include(FetchContent) -if(CATALYST_SRC_PATH) - if(NOT IS_ABSOLUTE ${CATALYST_SRC_PATH}) - message(FATAL_ERROR " CATALYST_SRC_PATH=${CATALYST_SRC_PATH} must be set to an absolute path") +if(LIGHTNING_CATALYST_SRC_PATH) + if(NOT IS_ABSOLUTE ${LIGHTNING_CATALYST_SRC_PATH}) + message(FATAL_ERROR " LIGHTNING_CATALYST_SRC_PATH=${LIGHTNING_CATALYST_SRC_PATH} must be set to an absolute path") endif() if(CATALYST_GIT_TAG) - message(WARN " Setting `CATALYST_SRC_PATH=${CATALYST_SRC_PATH}` overrides `CATALYST_GIT_TAG=${CATALYST_GIT_TAG}`") + message(WARN " Setting `LIGHTNING_CATALYST_SRC_PATH=${LIGHTNING_CATALYST_SRC_PATH}` overrides `CATALYST_GIT_TAG=${CATALYST_GIT_TAG}`") endif() # Acquire local git hash and use for CATALYST_GIT_TAG execute_process(COMMAND git rev-parse --short HEAD - WORKING_DIRECTORY ${CATALYST_SRC_PATH} + WORKING_DIRECTORY ${LIGHTNING_CATALYST_SRC_PATH} OUTPUT_VARIABLE CATALYST_GIT_TAG ) - message(INFO " Building against local Catalyst - path: ${CATALYST_SRC_PATH} - GIT TAG: ${CATALYST_GIT_TAG}") + message(INFO " Building against local Catalyst - path: ${LIGHTNING_CATALYST_SRC_PATH} - GIT TAG: ${CATALYST_GIT_TAG}") - target_include_directories(lightning_kokkos_catalyst PUBLIC ${CATALYST_SRC_PATH}/runtime/lib/backend/common) - target_include_directories(lightning_kokkos_catalyst PUBLIC ${CATALYST_SRC_PATH}/runtime/include) + target_include_directories(lightning_kokkos_catalyst PUBLIC ${LIGHTNING_CATALYST_SRC_PATH}/runtime/lib/backend/common) + target_include_directories(lightning_kokkos_catalyst PUBLIC ${LIGHTNING_CATALYST_SRC_PATH}/runtime/include) else() if(NOT CATALYST_GIT_TAG) From dcb468aa0902b35b176301ba3d92026fe0eb915e Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 26 Jun 2024 18:18:45 +0000 Subject: [PATCH 29/34] Auto update version from '0.37.0-dev49' to '0.37.0-dev50' --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 0321bcbfde..9a871e864f 100644 --- a/pennylane_lightning/core/_version.py +++ b/pennylane_lightning/core/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.37.0-dev49" +__version__ = "0.37.0-dev50" From 8481ea392e8280fe24e41ea817b6a13d40961fb1 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 27 Jun 2024 12:55:51 -0400 Subject: [PATCH 30/34] more review suggestions --- .../catalyst/LightningKokkosObsManager.hpp | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp index fb20866c25..387c4e282a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosObsManager.hpp @@ -31,14 +31,12 @@ namespace Catalyst::Runtime::Simulator { * runtime and maps each one to a const unique index (`int64_t`) in the scope of * the global context manager. */ -template class LightningKokkosObsManager { +template class LightningKokkosObsManager final { private: - using VectorStateT = + using StateVectorT = Pennylane::LightningKokkos::StateVectorKokkos; - using ObservableClassName = - Pennylane::Observables::Observable; - using ObservablePairType = - std::pair, ObsType>; + using ObservableT = Pennylane::Observables::Observable; + using ObservablePairType = std::pair, ObsType>; std::vector observables_{}; public: @@ -74,10 +72,10 @@ template class LightningKokkosObsManager { * @brief Get the constructed observable instance. * * @param key The observable key - * @return std::shared_ptr + * @return std::shared_ptr */ [[nodiscard]] auto getObservable(ObsIdType key) - -> std::shared_ptr { + -> std::shared_ptr { RT_FAIL_IF(!this->isValidObservables({key}), "Invalid observable key"); return std::get<0>(this->observables_[key]); } @@ -107,7 +105,7 @@ template class LightningKokkosObsManager { this->observables_.push_back(std::make_pair( std::make_shared>(obs_str, wires), + StateVectorT>>(obs_str, wires), ObsType::Basic)); return static_cast(this->observables_.size() - 1); } @@ -130,9 +128,9 @@ template class LightningKokkosObsManager { this->observables_.push_back(std::make_pair( std::make_shared>( + HermitianObs>( Pennylane::LightningKokkos::Observables::HermitianObs< - VectorStateT>{matrix_k, wires}), + StateVectorT>{matrix_k, wires}), ObsType::Basic)); return static_cast(this->observables_.size() - 1); @@ -149,7 +147,7 @@ template class LightningKokkosObsManager { const auto key_size = obsKeys.size(); const auto obs_size = this->observables_.size(); - std::vector> obs_vec; + std::vector> obs_vec; obs_vec.reserve(key_size); for (const auto &key : obsKeys) { @@ -162,7 +160,7 @@ template class LightningKokkosObsManager { this->observables_.push_back(std::make_pair( Pennylane::LightningKokkos::Observables::TensorProdObs< - VectorStateT>::create(obs_vec), + StateVectorT>::create(obs_vec), ObsType::TensorProd)); return static_cast(obs_size); @@ -186,7 +184,7 @@ template class LightningKokkosObsManager { "Incompatible list of observables and coefficients; " "Number of observables and number of coefficients must be equal"); - std::vector> obs_vec; + std::vector> obs_vec; obs_vec.reserve(key_size); for (auto key : obsKeys) { @@ -199,9 +197,9 @@ template class LightningKokkosObsManager { this->observables_.push_back(std::make_pair( std::make_shared>( + Hamiltonian>( Pennylane::LightningKokkos::Observables::Hamiltonian< - VectorStateT>(coeffs, std::move(obs_vec))), + StateVectorT>(coeffs, std::move(obs_vec))), ObsType::Hamiltonian)); return static_cast(obs_size); From 022aa3c225fda4d2f877580b7e08c6b9f7c7169e Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 27 Jun 2024 13:56:29 -0400 Subject: [PATCH 31/34] improve docstrings --- .../catalyst/LightningKokkosSimulator.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp index 34e0c44ad7..1284928a07 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp @@ -11,6 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + +/** + * @file LightningKokkosSimulator.hpp + */ + #pragma once #define __device_lightning_kokkos @@ -37,6 +42,12 @@ #include "Utils.hpp" namespace Catalyst::Runtime::Simulator { +/** + * @brief Kokkos state vector class wrapper for Catalyst. + * This class inherits from the QuantumDevice class defined in Catalyst. + * More info: https://github.com/PennyLaneAI/catalyst/blob/main/runtime/include/QuantumDevice.hpp + * + */ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { private: using StateVectorT = Pennylane::LightningKokkos::StateVectorKokkos; From 44fe033f7920d9cc03eee5b1c91980ac91c9fa3d Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 27 Jun 2024 14:28:57 -0400 Subject: [PATCH 32/34] format --- .../lightning_kokkos/catalyst/LightningKokkosSimulator.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp index 1284928a07..36b4b5891e 100644 --- a/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/catalyst/LightningKokkosSimulator.hpp @@ -45,7 +45,8 @@ namespace Catalyst::Runtime::Simulator { /** * @brief Kokkos state vector class wrapper for Catalyst. * This class inherits from the QuantumDevice class defined in Catalyst. - * More info: https://github.com/PennyLaneAI/catalyst/blob/main/runtime/include/QuantumDevice.hpp + * More info: + * https://github.com/PennyLaneAI/catalyst/blob/main/runtime/include/QuantumDevice.hpp * */ class LightningKokkosSimulator final : public Catalyst::Runtime::QuantumDevice { From 7555e499889e42edfceb5eaa5c146c1ab9c4d37d Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 8 Jul 2024 12:55:01 -0400 Subject: [PATCH 33/34] add changelog --- .github/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 2eb83d840b..351c825da6 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -5,6 +5,8 @@ ### Breaking changes ### Improvements +* Add a Catalyst wrapper for the LightningKokkos simulator. + [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) ### Documentation @@ -14,6 +16,8 @@ This release contains contributions from (in alphabetical order): +Amintor Dusko + --- # Release 0.37.0 From ee1d8b5f0f5b9501a678a83f5aac757a91fad044 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 8 Jul 2024 13:59:08 -0400 Subject: [PATCH 34/34] update changelog --- .github/CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 351c825da6..8139ce1c79 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -5,7 +5,7 @@ ### Breaking changes ### Improvements -* Add a Catalyst wrapper for the LightningKokkos simulator. +* Add a Catalyst-specific wrapping class for Lightning Kokkos. [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) ### Documentation @@ -41,9 +41,6 @@ Amintor Dusko * Add support for `C(BlockEncode)` to Lightning devices. [(#743)](https://github.com/PennyLaneAI/pennylane-lightning/pull/743) -* Add a Catalyst-specific wrapping class for Lightning Kokkos. - [(#770)](https://github.com/PennyLaneAI/pennylane-lightning/pull/770) - ### Breaking changes * Removed the `QuimbMPS` class and the corresponding interface/backend from `lightning.tensor`.