From 635767f45bda6379e55cf2b22a0d04d4ec79d48a Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 14:59:15 -0500 Subject: [PATCH 01/33] update dev version --- 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 5d80b68583..5301226fd1 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.35.0-dev7" +__version__ = "0.35.0-dev8" From 5c05425a2fcd11139eea6bdc292a42453543c296 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:00:24 -0500 Subject: [PATCH 02/33] update clean --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 7ad687c448..1c29725ed2 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,9 @@ help: clean: find . -type d -name '__pycache__' -exec rm -r {} \+ rm -rf build Build BuildTests BuildTidy BuildGBench + rm -rf build_lightning_qubit + rm -rf build_lightning_kokkos + rm -rf build_lightning_gpu rm -rf .coverage coverage_html_report/ rm -rf pennylane_lightning/*_ops* From 567d21f6581b8ee8da1a4b9a47d90c7162453dae Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:01:06 -0500 Subject: [PATCH 03/33] expand .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7c5a86618e..5be229e6f7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ doc/code/api/ PennyLane_Lightning.egg-info/ PennyLane_Lightning_Kokkos.egg-info/ build/ +build_lightning_qubit/ +build_lightning_kokkos/ +build_lightning_gpu/ Build/ BuildCov/ BuildGBench/ From b761f3fe997b58c4729ef2845227ab507736dca2 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:03:20 -0500 Subject: [PATCH 04/33] expand lightning qubit class specific python bindings --- .../bindings/LQubitBindings.hpp | 72 ++++++++++++++++--- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp index 147e35c3aa..abea4c7632 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp @@ -26,7 +26,7 @@ #include "GateOperation.hpp" #include "MeasurementsLQubit.hpp" #include "ObservablesLQubit.hpp" -#include "StateVectorLQubitRaw.hpp" +#include "StateVectorLQubitManaged.hpp" #include "TypeList.hpp" #include "VectorJacobianProduct.hpp" @@ -36,7 +36,7 @@ using namespace Pennylane::Bindings; using namespace Pennylane::LightningQubit::Algorithms; using namespace Pennylane::LightningQubit::Measures; using namespace Pennylane::LightningQubit::Observables; -using Pennylane::LightningQubit::StateVectorLQubitRaw; +using Pennylane::LightningQubit::StateVectorLQubitManaged; } // namespace /// @endcond @@ -44,8 +44,8 @@ namespace py = pybind11; namespace Pennylane::LightningQubit { using StateVectorBackends = - Pennylane::Util::TypeList, - StateVectorLQubitRaw, void>; + Pennylane::Util::TypeList, + StateVectorLQubitManaged, void>; /** * @brief Get a gate kernel map for a statevector. @@ -162,12 +162,68 @@ void registerControlledGate(PyClass &pyclass) { */ template void registerBackendClassSpecificBindings(PyClass &pyclass) { + using PrecisionT = + typename StateVectorT::PrecisionT; // Statevector's precision + using ComplexT = typename StateVectorT::ComplexT; + using ParamT = PrecisionT; // Parameter's data precision + using np_arr_c = py::array_t, + py::array::c_style | py::array::forcecast>; + registerGatesForStateVector(pyclass); registerControlledGate(pyclass); - pyclass.def("applyControlledMatrix", &applyControlledMatrix, - "Apply controlled operation"); - pyclass.def("kernel_map", &svKernelMap, - "Get internal kernels for operations"); + + pyclass + .def(py::init([](std::size_t num_qubits) { + return new StateVectorT(num_qubits); + })) + .def("resetStateVector", &StateVectorT::resetStateVector) + .def( + "setBasisState", + [](StateVectorT &sv, const size_t index) { + sv.setBasisState(index); + }, + "Create Basis State.") + .def( + "setStateVector", + [](StateVectorT &sv, const std::vector &indices, + const np_arr_c &state) { + const auto buffer = state.request(); + std::vector state_in; + if (buffer.size) { + const auto ptr = static_cast(buffer.ptr); + state_in = std::vector{ptr, ptr + buffer.size}; + } + sv.setStateVector(indices, state_in); + }, + "Set State Vector with values and their corresponding indices") + .def( + "getState", + [](const StateVectorT &sv, np_arr_c &state) { + py::buffer_info numpyArrayInfo = state.request(); + auto *data_ptr = + static_cast *>(numpyArrayInfo.ptr); + if (state.size()) { + std::copy(sv.getData(), sv.getData() + sv.getLength(), + data_ptr); + } + }, + "Synchronize data from the GPU device to host.") + .def( + "UpdateData", + [](StateVectorT &device_sv, const np_arr_c &state) { + const py::buffer_info numpyArrayInfo = state.request(); + auto *data_ptr = static_cast(numpyArrayInfo.ptr); + const auto length = + static_cast(numpyArrayInfo.shape[0]); + if (length) { + device_sv.updateData(data_ptr, length); + } + }, + "Synchronize data from the host device to GPU.") + .def("applyControlledMatrix", &applyControlledMatrix, + "Apply controlled operation") + .def("kernel_map", &svKernelMap, + "Get internal kernels for operations"); } /** From 762ee8cffed6cd7b989185996cd0f5abed394037 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:06:42 -0500 Subject: [PATCH 05/33] add some statevector manipulation methods to statevector managed simulator --- .../StateVectorLQubitManaged.hpp | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp index add76efeb0..93b256acae 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp @@ -19,6 +19,7 @@ #pragma once +#include // fill #include #include @@ -76,7 +77,7 @@ class StateVectorLQubitManaged final : BaseType{num_qubits, threading, memory_model}, data_{exp2(num_qubits), ComplexT{0.0, 0.0}, getAllocator(this->memory_model_)} { - data_[0] = {1, 0}; + setBasisState(0U); } /** @@ -139,6 +140,39 @@ class StateVectorLQubitManaged final ~StateVectorLQubitManaged() = default; + /** + * @brief Prepares a single computational basis state. + * + * @param index Index of the target element. + */ + void setBasisState(const size_t index) { + std::fill(data_.begin(), data_.end(), 0); + data_[index] = {1, 0}; + } + + /** + * @brief Set values for a batch of elements of the state-vector. + * + * @param values Values to be set for the target elements. + * @param indices Indices of the target elements. + */ + void setStateVector(const std::vector &indices, + const std::vector &values) { + for (size_t n = 0; n < indices.size(); n++) { + data_[indices[n]] = values[n]; + } + } + + /** + * @brief Reset the data back to the \f$\ket{0}\f$ state. + * + */ + void resetStateVector() { + if (this->getLength() > 0) { + setBasisState(0U); + } + } + [[nodiscard]] auto getData() -> ComplexT * { return data_.data(); } [[nodiscard]] auto getData() const -> const ComplexT * { From 99150d836db39aab512da4c96f8571cbae1421e5 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:14:24 -0500 Subject: [PATCH 06/33] update lightning qubit python class --- .../lightning_qubit/lightning_qubit.py | 153 ++++++++---------- 1 file changed, 68 insertions(+), 85 deletions(-) diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 860f9bb2dd..243619b724 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -75,6 +75,11 @@ VectorJacobianProductC128, ) + def _state_dtype(dtype): + if dtype not in [np.complex128, np.complex64]: # pragma: no cover + raise ValueError(f"Data type is not supported for state-vector computation: {dtype}") + return StateVectorC128 if dtype == np.complex128 else StateVectorC64 + allowed_operations = { "Identity", "BasisState", @@ -226,8 +231,8 @@ def __init__( # pylint: disable=too-many-arguments # Create the initial state. Internally, we store the # state as an array of dimension [2]*wires. - self._state = self._create_basis_state(0) - self._pre_rotated_state = self._state + self._state = _state_dtype(c_dtype)(self.num_wires) + self._pre_rotated_state = _state_dtype(c_dtype)(self.num_wires) self._c_dtype = c_dtype self._batch_obs = batch_obs @@ -274,24 +279,16 @@ def _asarray(arr, dtype=None): def _create_basis_state(self, index): """Return a computational basis state over all wires. Args: - index (int): integer representing the computational basis state - Returns: - array[complex]: complex array of shape ``[2]*self.num_wires`` - representing the statevector of the basis state - Note: This function does not support broadcasted inputs yet. + index (int): integer representing the computational basis state. """ - state = allocate_aligned_array(2**self.num_wires, np.dtype(self.C_DTYPE), True) - state[index] = 1 - return self._reshape(state, [2] * self.num_wires) + self._state.setBasisState(index) def reset(self): """Reset the device""" super().reset() # init the state vector to |00..0> - if not self.state[0] == 1.0 + 0j: - self._state = self._create_basis_state(0) - self._pre_rotated_state = self._state + self._state.resetStateVector() @property def create_ops_list(self): @@ -301,25 +298,23 @@ def create_ops_list(self): @property def measurements(self): """Returns a Measurements object matching ``use_csingle`` precision.""" - ket = np.ravel(self._state) - state_vector = StateVectorC64(ket) if self.use_csingle else StateVectorC128(ket) return ( - MeasurementsC64(state_vector) + MeasurementsC64(self.state_vector) if self.use_csingle - else MeasurementsC128(state_vector) + else MeasurementsC128(self.state_vector) ) @property def state(self): - """Returns the flattened state vector.""" - shape = (1 << self.num_wires,) - return self._reshape(self._pre_rotated_state, shape) + state = np.zeros(2**self.num_wires, dtype=self.C_DTYPE) + state = self._asarray(state, dtype=self.C_DTYPE) + self._state.getState(state.ravel(order="C")) + return state @property def state_vector(self): - """Returns a handle to a StateVector object matching ``use_csingle`` precision.""" - ket = np.ravel(self._state) - return StateVectorC64(ket) if self.use_csingle else StateVectorC128(ket) + """Returns a handle to the statevector.""" + return self._state def _apply_state_vector(self, state, device_wires): """Initialize the internal state vector in a specified state. @@ -328,6 +323,13 @@ def _apply_state_vector(self, state, device_wires): or broadcasted state of shape ``(batch_size, 2**len(wires))`` device_wires (Wires): wires that get initialized in the state """ + + if isinstance(state, self._state.__class__): + state_data = np.zeros(state.size, dtype=self.C_DTYPE) + state_data = self._asarray(state_data, dtype=self.C_DTYPE) + self._state.getState(state_data.ravel(order="C")) + state = state_data + ravelled_indices, state = self._preprocess_state_vector(state, device_wires) # translate to wire labels used by device @@ -336,12 +338,11 @@ def _apply_state_vector(self, state, device_wires): if len(device_wires) == self.num_wires and Wires(sorted(device_wires)) == device_wires: # Initialize the entire device state with the input state - self._state = self._reshape(state, output_shape) + state = self._reshape(state, output_shape).ravel(order="C") + self._state.UpdateData(state) return - state = self._scatter(ravelled_indices, state, [2**self.num_wires]) - state = self._reshape(state, output_shape) - self._state = self._asarray(state, dtype=self.C_DTYPE) + self._state.setStateVector(ravelled_indices, state) # this operation on device def _apply_basis_state(self, state, wires): """Initialize the state vector in a specified computational basis state. @@ -355,22 +356,23 @@ def _apply_basis_state(self, state, wires): Note: This function does not support broadcasted inputs yet. """ num = self._get_basis_state_index(state, wires) - self._state = self._create_basis_state(num) + self._create_basis_state(num) - def _apply_lightning_controlled(self, sim, operation): + def _apply_lightning_controlled(self, operation): """Apply an arbitrary controlled operation to the state tensor. Args: - sim (StateVectorC64, StateVectorC128): a state vector simulator operation (~pennylane.operation.Operation): operation to apply Returns: array[complex]: the output state tensor """ + state = self.state_vector + basename = "PauliX" if operation.name == "MultiControlledX" else operation.base.name if basename == "Identity": return - method = getattr(sim, f"{basename}", None) + method = getattr(state, f"{basename}", None) control_wires = self.wires.indices(operation.control_wires) control_values = ( [bool(int(i)) for i in operation.hyperparameters["control_values"]] @@ -386,7 +388,7 @@ def _apply_lightning_controlled(self, sim, operation): param = operation.parameters method(control_wires, control_values, target_wires, inv, param) else: # apply gate as an n-controlled matrix - method = getattr(sim, "applyControlledMatrix") + method = getattr(state, "applyControlledMatrix") target_wires = self.wires.indices(operation.target_wires) try: method( @@ -402,27 +404,24 @@ def _apply_lightning_controlled(self, sim, operation): operation.base.matrix, control_wires, control_values, target_wires, False ) - def apply_lightning(self, state, operations): + def apply_lightning(self, operations): """Apply a list of operations to the state tensor. Args: - state (array[complex]): the input state tensor operations (list[~pennylane.operation.Operation]): operations to apply Returns: array[complex]: the output state tensor """ - state_vector = np.ravel(state) - sim = ( - StateVectorC64(state_vector) if self.use_csingle else StateVectorC128(state_vector) - ) + state = self.state_vector # Skip over identity operations instead of performing # matrix multiplication with it. for operation in operations: - if operation.name == "Identity": + name = operation.name + if name == "Identity": continue - method = getattr(sim, operation.name, None) + method = getattr(state, name, None) wires = self.wires.indices(operation.wires) if method is not None: # apply specialized gate @@ -430,23 +429,21 @@ def apply_lightning(self, state, operations): param = operation.parameters method(wires, inv, param) elif ( - operation.name[0:2] == "C(" - or operation.name == "ControlledQubitUnitary" - or operation.name == "MultiControlledX" + name[0:2] == "C(" + or name == "ControlledQubitUnitary" + or name == "MultiControlledX" ): # apply n-controlled gate - self._apply_lightning_controlled(sim, operation) + self._apply_lightning_controlled(operation) else: # apply gate as a matrix # Inverse can be set to False since qml.matrix(operation) is already in # inverted form - method = getattr(sim, "applyMatrix") + method = getattr(state, "applyMatrix") try: method(qml.matrix(operation), wires, False) except AttributeError: # pragma: no cover # To support older versions of PL method(operation.matrix, wires, False) - return np.reshape(state_vector, state.shape) - # pylint: disable=unused-argument def apply(self, operations, rotations=None, **kwargs): """Applies operations to the state vector.""" @@ -468,15 +465,7 @@ def apply(self, operations, rotations=None, **kwargs): f"Operations have already been applied on a {self.short_name} device." ) - if operations: - self._pre_rotated_state = self.apply_lightning(self._state, operations) - else: - self._pre_rotated_state = self._state - - if rotations: - self._state = self.apply_lightning(np.copy(self._pre_rotated_state), rotations) - else: - self._state = self._pre_rotated_state + self.apply_lightning(operations) # pylint: disable=protected-access def expval(self, observable, shot_range=None, bin_size=None): @@ -505,14 +494,10 @@ def expval(self, observable, shot_range=None, bin_size=None): samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) return np.squeeze(np.mean(samples, axis=0)) - # Initialization of state - ket = np.ravel(self._pre_rotated_state) - - state_vector = StateVectorC64(ket) if self.use_csingle else StateVectorC128(ket) measurements = ( - MeasurementsC64(state_vector) + MeasurementsC64(self.state_vector) if self.use_csingle - else MeasurementsC128(state_vector) + else MeasurementsC128(self.state_vector) ) if observable.name == "SparseHamiltonian": csr_hamiltonian = observable.sparse_matrix(wire_order=self.wires).tocsr(copy=False) @@ -563,14 +548,10 @@ def var(self, observable, shot_range=None, bin_size=None): samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) return np.squeeze(np.var(samples, axis=0)) - # Initialization of state - ket = np.ravel(self._pre_rotated_state) - - state_vector = StateVectorC64(ket) if self.use_csingle else StateVectorC128(ket) measurements = ( - MeasurementsC64(state_vector) + MeasurementsC64(self.state_vector) if self.use_csingle - else MeasurementsC128(state_vector) + else MeasurementsC128(self.state_vector) ) if observable.name == "SparseHamiltonian": @@ -603,14 +584,10 @@ def generate_samples(self): array[int]: array of samples in binary representation with shape ``(dev.shots, dev.num_wires)`` """ - # Initialization of state - ket = np.ravel(self._state) - - state_vector = StateVectorC64(ket) if self.use_csingle else StateVectorC128(ket) measurements = ( - MeasurementsC64(state_vector) + MeasurementsC64(self.state_vector) if self.use_csingle - else MeasurementsC128(state_vector) + else MeasurementsC128(self.state_vector) ) if self._mcmc: return measurements.generate_mcmc_samples( @@ -630,13 +607,22 @@ def probability_lightning(self, wires): Returns: array[float]: list of the probabilities """ - state_vector = self.state_vector return ( - MeasurementsC64(state_vector) + MeasurementsC64(self.state_vector) if self.use_csingle - else MeasurementsC128(state_vector) + else MeasurementsC128(self.state_vector) ).probs(wires) + # pylint: disable=attribute-defined-outside-init + def sample(self, observable, shot_range=None, bin_size=None, counts=False): + """Return samples of an observable.""" + if observable.name != "PauliZ": + self.apply_lightning(observable.diagonalizing_gates()) + self._samples = self.generate_samples() + return super().sample( + observable, shot_range=shot_range, bin_size=bin_size, counts=counts + ) + @staticmethod def _check_adjdiff_supported_measurements( measurements: List[MeasurementProcess], @@ -700,14 +686,11 @@ def _init_process_jacobian_tape(self, tape, starting_state, use_device_state): "The number of qubits of starting_state must be the same as " "that of the device." ) - ket = self._asarray(starting_state, dtype=self.C_DTYPE) - else: - if not use_device_state: - self.reset() - self.apply(tape.operations) - ket = self._pre_rotated_state - ket = ket.reshape(-1) - return StateVectorC64(ket) if self.use_csingle else StateVectorC128(ket) + self._apply_state_vector(starting_state, self.wires) + elif not use_device_state: + self.reset() + self.apply(tape.operations) + return self.state_vector def adjoint_jacobian(self, tape, starting_state=None, use_device_state=False): """Computes and returns the Jacobian with the adjoint method.""" From 404d249400c2f454a72a1412e7b871935610e368 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:16:29 -0500 Subject: [PATCH 07/33] add c++ unit tests --- .../tests/Test_StateVectorLQubitManaged.cpp | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp index 127cfe3df3..3d94289571 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp @@ -21,7 +21,8 @@ #include -#include "LinearAlgebra.hpp" //randomUnitary +#include "CPUMemoryModel.hpp" // getBestAllocator +#include "LinearAlgebra.hpp" //randomUnitary #include "StateVectorLQubitManaged.hpp" #include "StateVectorLQubitRaw.hpp" #include "TestHelpers.hpp" // createRandomStateVectorData, TestVector @@ -107,4 +108,60 @@ TEMPLATE_TEST_CASE("StateVectorLQubitManaged::StateVectorLQubitManaged", REQUIRE(sv.getDataVector() == approx(st_data)); } -} \ No newline at end of file +} + +TEMPLATE_TEST_CASE("StateVectorLQubitManaged::setBasisState", + "[StateVectorLQubitManaged]", float, double) { + using PrecisionT = TestType; + using ComplexT = std::complex; + using TestVectorT = TestVector; + + const std::size_t num_qubits = 3; + + SECTION("Prepares a single computational basis state.") { + TestVectorT init_state = + createRandomStateVectorData(re, num_qubits); + + TestVectorT expected_state(size_t{1U} << num_qubits, 0.0, + getBestAllocator()); + expected_state[3] = {1.0, 0.0}; + + StateVectorLQubitManaged sv(init_state); + + size_t index = 3; + sv.setBasisState(index); + + REQUIRE(sv.getDataVector() == approx(expected_state)); + } +} + +TEMPLATE_TEST_CASE("StateVectorLQubitManaged::SetStateVector", + "[StateVectorLQubitManaged]", float, double) { + using PrecisionT = TestType; + using ComplexT = std::complex; + using TestVectorT = TestVector; + + const std::size_t num_qubits = 3; + + SECTION("Set state vector with values and indices") { + TestVectorT init_state = + createRandomStateVectorData(re, num_qubits); + + auto expected_state = init_state; + + for (size_t i = 0; i < Pennylane::Util::exp2(num_qubits - 1); i++) { + std::swap(expected_state[i * 2], expected_state[i * 2 + 1]); + } + + std::vector indices = {0, 2, 4, 6, 1, 3, 5, 7}; + + std::vector values = { + init_state[1], init_state[3], init_state[5], init_state[7], + init_state[0], init_state[2], init_state[4], init_state[6]}; + + StateVectorLQubitManaged sv{num_qubits}; + sv.setStateVector(indices, values); + + REQUIRE(sv.getDataVector() == approx(expected_state)); + } +} From b760684892db7c7d378e1162fcdd4052bb978732 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:17:56 -0500 Subject: [PATCH 08/33] add comments to test --- tests/test_apply.py | 563 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 491 insertions(+), 72 deletions(-) diff --git a/tests/test_apply.py b/tests/test_apply.py index a8075a8176..c2e8cacbd1 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -23,6 +23,7 @@ import pennylane as qml from pennylane import DeviceError from pennylane.operation import Operation +import functools class TestApply: @@ -57,7 +58,7 @@ def test_apply_operation_single_wire_no_parameters( ): """Tests that applying an operation yields the expected output state for single wire operations that have no parameters.""" - from pennylane.wires import Wires + # from pennylane.wires import Wires dev = qubit_device(wires=1) _state = np.array(input).astype(dev.C_DTYPE) @@ -67,23 +68,23 @@ def test_apply_operation_single_wire_no_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - @pytest.mark.skipif( - device_name == "lightning.kokkos" or device_name == "lightning.gpu", - reason="Only meaningful for lightning_qubit", - ) - @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) - @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - def test_apply_operation_preserve_pointer_single_wire_no_parameters( - self, qubit_device, operation, input, expected_output, C - ): - dev = qubit_device(wires=1) - dev._state = dev._asarray(input, dtype=C) - pointer_before, _ = dev._state.__array_interface__["data"] - dev.apply([operation(wires=[0])]) - pointer_after, _ = dev._state.__array_interface__["data"] - - assert pointer_before == pointer_after + # @pytest.mark.skipif( + # device_name == "lightning.kokkos" or device_name == "lightning.gpu", + # reason="Only meaningful for lightning_qubit", + # ) + # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + # @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) + # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + # def test_apply_operation_preserve_pointer_single_wire_no_parameters( + # self, qubit_device, operation, input, expected_output, C + # ): + # dev = qubit_device(wires=1) + # dev._state = dev._asarray(input, dtype=C) + # pointer_before, _ = dev._state.__array_interface__["data"] + # dev.apply([operation(wires=[0])]) + # pointer_after, _ = dev._state.__array_interface__["data"] + + # assert pointer_before == pointer_after test_data_two_wires_no_parameters = [ (qml.CNOT, [1, 0, 0, 0], [1, 0, 0, 0]), @@ -123,19 +124,19 @@ def test_apply_operation_two_wires_no_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - @pytest.mark.parametrize("operation,input,expected_output", test_data_two_wires_no_parameters) - @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - def test_apply_operation_preserve_pointer_two_wires_no_parameters( - self, qubit_device, operation, input, expected_output, C - ): - dev = qubit_device(wires=2) - dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) - pointer_before, _ = dev._state.__array_interface__["data"] - dev.apply([operation(wires=[0, 1])]) - pointer_after, _ = dev._state.__array_interface__["data"] + # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + # @pytest.mark.parametrize("operation,input,expected_output", test_data_two_wires_no_parameters) + # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + # def test_apply_operation_preserve_pointer_two_wires_no_parameters( + # self, qubit_device, operation, input, expected_output, C + # ): + # dev = qubit_device(wires=2) + # dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) + # pointer_before, _ = dev._state.__array_interface__["data"] + # dev.apply([operation(wires=[0, 1])]) + # pointer_after, _ = dev._state.__array_interface__["data"] - assert pointer_before == pointer_after + # assert pointer_before == pointer_after test_data_three_wires_no_parameters = [ (qml.CSWAP, [1, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0]), @@ -162,19 +163,19 @@ def test_apply_operation_three_wires_no_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) - @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - def test_apply_operation_preserve_pointer_three_wires_no_parameters( - self, qubit_device, operation, input, expected_output, C - ): - dev = qubit_device(wires=3) - dev._state = dev._asarray(input, dtype=C).reshape(3 * [2]) - pointer_before, _ = dev._state.__array_interface__["data"] - dev.apply([operation(wires=[0, 1, 2])]) - pointer_after, _ = dev._state.__array_interface__["data"] + # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + # @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) + # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + # def test_apply_operation_preserve_pointer_three_wires_no_parameters( + # self, qubit_device, operation, input, expected_output, C + # ): + # dev = qubit_device(wires=3) + # dev._state = dev._asarray(input, dtype=C).reshape(3 * [2]) + # pointer_before, _ = dev._state.__array_interface__["data"] + # dev.apply([operation(wires=[0, 1, 2])]) + # pointer_after, _ = dev._state.__array_interface__["data"] - assert pointer_before == pointer_after + # assert pointer_before == pointer_after @pytest.mark.parametrize( "operation,expected_output,par", @@ -307,21 +308,21 @@ def test_apply_operation_single_wire_with_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - @pytest.mark.parametrize( - "operation,input,expected_output,par", test_data_single_wire_with_parameters - ) - @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - def test_apply_operation_preserve_pointer_single_wire_with_parameters( - self, qubit_device, operation, input, expected_output, par, C - ): - dev = qubit_device(wires=1) - dev._state = dev._asarray(input, dtype=C) - pointer_before, _ = dev._state.__array_interface__["data"] - dev.apply([operation(*par, wires=[0])]) - pointer_after, _ = dev._state.__array_interface__["data"] - - assert pointer_before == pointer_after + # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + # @pytest.mark.parametrize( + # "operation,input,expected_output,par", test_data_single_wire_with_parameters + # ) + # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + # def test_apply_operation_preserve_pointer_single_wire_with_parameters( + # self, qubit_device, operation, input, expected_output, par, C + # ): + # dev = qubit_device(wires=1) + # dev._state = dev._asarray(input, dtype=C) + # pointer_before, _ = dev._state.__array_interface__["data"] + # dev.apply([operation(*par, wires=[0])]) + # pointer_after, _ = dev._state.__array_interface__["data"] + + # assert pointer_before == pointer_after """ operation,input,expected_output,par """ test_data_two_wires_with_parameters = [ @@ -458,21 +459,21 @@ def test_apply_operation_two_wires_with_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - @pytest.mark.parametrize( - "operation,input,expected_output,par", test_data_two_wires_with_parameters - ) - @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - def test_apply_operation_preserve_pointer_two_wires_with_parameters( - self, qubit_device, operation, input, expected_output, par, C - ): - dev = qubit_device(wires=2) - dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) - pointer_before, _ = dev._state.__array_interface__["data"] - dev.apply([operation(*par, wires=[0, 1])]) - pointer_after, _ = dev._state.__array_interface__["data"] - - assert pointer_before == pointer_after + # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + # @pytest.mark.parametrize( + # "operation,input,expected_output,par", test_data_two_wires_with_parameters + # ) + # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + # def test_apply_operation_preserve_pointer_two_wires_with_parameters( + # self, qubit_device, operation, input, expected_output, par, C + # ): + # dev = qubit_device(wires=2) + # dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) + # pointer_before, _ = dev._state.__array_interface__["data"] + # dev.apply([operation(*par, wires=[0, 1])]) + # pointer_after, _ = dev._state.__array_interface__["data"] + + # assert pointer_before == pointer_after @pytest.mark.parametrize("stateprep", [qml.QubitStateVector, qml.StatePrep]) def test_apply_errors_qubit_state_vector(self, stateprep, qubit_device): @@ -1466,6 +1467,424 @@ def test_qubitunitary_rotation_hadamard(self, theta, phi, varphi, shots, qubit_d assert np.allclose(var, expected, atol=tolerance, rtol=0) +# This block of similar tests coming from pennylane will not fail: +# def ansatz(a, b, c): +# qml.RX(a, wires=0) +# qml.RX(b, wires=1) +# qml.RX(c, wires=2) +# qml.CNOT(wires=[0, 1]) +# qml.CNOT(wires=[1, 2]) +# Z = np.array([[1, 0], [0, -1]]) + +# from pennylane import expval, var, sample + +# @pytest.mark.parametrize("shots", [None, int(1e6)]) +# @pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) +# class TestTensorExpval: +# """Test tensor expectation values""" + +# @pytest.fixture +# def tolerance(self, shots, tol): +# if shots is not None: +# return {"atol": 0.01, "rtol": 0.1} + +# return {"atol": tol, "rtol": 0} + +# def test_tensor_product(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product ZxZ gives the same result as simply +# using an Hermitian matrix""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit1(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliZ(0) @ qml.PauliZ(2)) + +# @qml.qnode(dev) +# def circuit2(a, b, c): +# ansatz(a, b, c) +# return expval(qml.Hermitian(np.kron(Z, Z), wires=[0, 2])) + +# res1 = circuit1(theta, phi, varphi) +# res2 = circuit2(theta, phi, varphi) + +# assert np.allclose(res1, res2, **tolerance) + +# def test_combine_tensor_with_non_tensor(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product along with a non-tensor product +# continues to function correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit1(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliZ(0) @ qml.PauliZ(2)), expval(qml.PauliZ(1)) + +# @qml.qnode(dev) +# def circuit2(a, b, c): +# ansatz(a, b, c) +# return expval(qml.Hermitian(np.kron(Z, Z), wires=[0, 2])) + +# @qml.qnode(dev) +# def circuit3(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliZ(1)) + +# res1 = circuit1(theta, phi, varphi) +# res2 = circuit2(theta, phi, varphi), circuit3(theta, phi, varphi) + +# assert np.allclose(res1, res2, **tolerance) + +# def test_paulix_tensor_pauliy(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving PauliX and PauliY works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliX(0) @ qml.PauliY(2)) + +# res = circuit(theta, phi, varphi) +# expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + +# assert np.allclose(res, expected, **tolerance) + +# @pytest.mark.autograd +# def test_paulix_tensor_pauliy_gradient(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving PauliX and PauliY works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliX(0) @ qml.PauliY(2)) + +# dcircuit = qml.grad(circuit, 0) +# res = dcircuit(theta, phi, varphi) +# expected = np.cos(theta) * np.sin(phi) * np.sin(varphi) + +# assert np.allclose(res, expected, **tolerance) + +# def test_pauliz_tensor_identity(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving PauliZ and Identity works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2)) + +# res = circuit(theta, phi, varphi) +# expected = np.cos(varphi) * np.cos(phi) + +# assert np.allclose(res, expected, **tolerance) + +# def test_pauliz_tensor_hadamard(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving PauliZ and hadamard works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2)) + +# res = circuit(theta, phi, varphi) +# expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + +# assert np.allclose(res, expected, **tolerance) + +# def test_hermitian(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving an Hermitian matrix works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# A = np.array( +# [ +# [-6, 2 + 1j, -3, -5 + 2j], +# [2 - 1j, 0, 2 - 1j, -5 + 4j], +# [-3, 2 + 1j, 0, -4 + 3j], +# [-5 - 2j, -5 - 4j, -4 - 3j, -6], +# ] +# ) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return expval(qml.PauliZ(0) @ qml.Hermitian(A, [1, 2])) + +# res = circuit(theta, phi, varphi) +# expected = 0.5 * ( +# -6 * np.cos(theta) * (np.cos(varphi) + 1) +# - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) +# + 3 * np.cos(varphi) * np.sin(phi) +# + np.sin(phi) +# ) + +# assert np.allclose(res, expected, **tolerance) + +# def test_hermitian_tensor_hermitian(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving two Hermitian matrices works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# A1 = np.array([[1, 2], [2, 4]]) + +# A2 = np.array( +# [ +# [-6, 2 + 1j, -3, -5 + 2j], +# [2 - 1j, 0, 2 - 1j, -5 + 4j], +# [-3, 2 + 1j, 0, -4 + 3j], +# [-5 - 2j, -5 - 4j, -4 - 3j, -6], +# ] +# ) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return expval(qml.Hermitian(A1, 0) @ qml.Hermitian(A2, [1, 2])) + +# res = circuit(theta, phi, varphi) +# expected = 0.25 * ( +# -30 +# + 4 * np.cos(phi) * np.sin(theta) +# + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) +# - 3 * np.sin(phi) +# - 2 +# * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) +# * np.sin(varphi) +# + np.cos(theta) +# * ( +# 18 +# + 5 * np.sin(phi) +# + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) +# + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) +# ) +# ) + +# assert np.allclose(res, expected, **tolerance) + +# def test_hermitian_tensor_identity_expectation(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=2, shots=shots) + +# A = np.array( +# [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] +# ) + +# # pylint: disable=unused-argument +# @qml.qnode(dev) +# def circuit(a, b, c): +# qml.RY(a, wires=0) +# qml.RY(b, wires=1) +# qml.CNOT(wires=[0, 1]) +# return expval(qml.Hermitian(A, 0) @ qml.Identity(1)) + +# res = circuit(theta, phi, varphi) + +# a = A[0, 0] +# re_b = A[0, 1].real +# d = A[1, 1] +# expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + +# assert np.allclose(res, expected, **tolerance) + + +# @pytest.mark.parametrize("shots", [None, int(1e6)]) +# @pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) +# class TestTensorVar: +# """Tests for variance of tensor observables""" + +# @pytest.fixture +# def tolerance(self, shots, tol): +# if shots is not None: +# return {"atol": 0.01, "rtol": 0.2} + +# return {"atol": tol, "rtol": 0} + +# def test_paulix_tensor_pauliy(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving PauliX and PauliY works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return var(qml.PauliX(0) @ qml.PauliY(2)) + +# res = circuit(theta, phi, varphi) +# expected = ( +# 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 +# - np.cos(2 * (theta - phi)) +# - np.cos(2 * (theta + phi)) +# + 2 * np.cos(2 * theta) +# + 2 * np.cos(2 * phi) +# + 14 +# ) / 16 + +# assert np.allclose(res, expected, **tolerance) + +# def test_pauliz_tensor_hadamard(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving PauliZ and hadamard works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return var(qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2)) + +# res = circuit(theta, phi, varphi) +# expected = ( +# 3 +# + np.cos(2 * phi) * np.cos(varphi) ** 2 +# - np.cos(2 * theta) * np.sin(varphi) ** 2 +# - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) +# ) / 4 + +# assert np.allclose(res, expected, **tolerance) + +# def test_tensor_hermitian(self, shots, theta, phi, varphi, tolerance): +# """Test that a tensor product involving qml.Hermitian works correctly""" +# dev = qml.device(device_name, wires=3, shots=shots) +# # dev = qml.device("default.qubit", wires=3, shots=shots) + +# A = np.array( +# [ +# [-6, 2 + 1j, -3, -5 + 2j], +# [2 - 1j, 0, 2 - 1j, -5 + 4j], +# [-3, 2 + 1j, 0, -4 + 3j], +# [-5 - 2j, -5 - 4j, -4 - 3j, -6], +# ] +# ) + +# @qml.qnode(dev) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return var(qml.PauliZ(0) @ qml.Hermitian(A, [1, 2])) + +# res = circuit(theta, phi, varphi) +# expected = ( +# 1057 +# - np.cos(2 * phi) +# + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) +# - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) +# + 16 * np.sin(2 * phi) +# - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) +# - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 +# - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) +# - 8 +# * np.cos(theta) +# * ( +# 4 +# * np.cos(phi) +# * ( +# 4 +# + 8 * np.cos(varphi) +# + np.cos(2 * varphi) +# - (1 + 6 * np.cos(varphi)) * np.sin(varphi) +# ) +# + np.sin(phi) +# * ( +# 15 +# + 8 * np.cos(varphi) +# - 11 * np.cos(2 * varphi) +# + 42 * np.sin(varphi) +# + 3 * np.sin(2 * varphi) +# ) +# ) +# ) / 16 + +# assert np.allclose(res, expected, **tolerance) + + +# def tensor_product(observables): +# return functools.reduce(np.kron, observables) + + +# @pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) +# class TestTensorSample: +# """Tests for samples of tensor observables""" + +# # pylint: disable=unused-argument +# def test_paulix_tensor_pauliz(self, theta, phi, varphi, tol_stochastic): +# """Test that a tensor product involving PauliX and PauliZ works correctly""" +# # dev = qml.device("default.qubit", wires=2, shots=int(1e6)) +# dev = qml.device(device_name, wires=2, shots=int(1e6)) + +# @qml.qnode(dev) +# def circuit(): +# qml.Hadamard(wires=0) +# return sample(qml.PauliX(0) @ qml.PauliZ(1)) + +# s1 = circuit() + +# # s1 should only contain 1 +# assert np.allclose(s1, 1, atol=tol_stochastic, rtol=0) + +# def test_paulix_tensor_pauliy(self, theta, phi, varphi, tol_stochastic): +# """Test that a tensor product involving PauliX and PauliY works correctly""" +# # dev = qml.device("default.qubit", wires=3, shots=int(1e6)) +# dev = qml.device(device_name, wires=3, shots=int(1e6)) + +# @qml.qnode(dev, diff_method="parameter-shift") +# def circuit(a, b, c): +# ansatz(a, b, c) +# return sample(qml.PauliX(0) @ qml.PauliY(2)) + +# s1 = circuit(theta, phi, varphi) + +# # s1 should only contain 1 and -1 +# assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) + +# def test_pauliz_tensor_hadamard(self, theta, phi, varphi, tol_stochastic): +# """Test that a tensor product involving PauliZ and hadamard works correctly""" +# # dev = qml.device("default.qubit", wires=3, shots=int(1e6)) +# dev = qml.device(device_name, wires=3, shots=int(1e6)) + +# @qml.qnode(dev, diff_method="parameter-shift") +# def circuit(a, b, c): +# ansatz(a, b, c) +# return sample(qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2)) + +# s1 = circuit(theta, phi, varphi) + +# # s1 should only contain 1 and -1 +# assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) + +# def test_tensor_hermitian(self, theta, phi, varphi, tol_stochastic): +# """Test that a tensor product involving qml.Hermitian works correctly""" +# # dev = qml.device("default.qubit", wires=3, shots=int(1e6)) +# dev = qml.device(device_name, wires=3, shots=int(1e6)) + +# A = np.array( +# [ +# [-6, 2 + 1j, -3, -5 + 2j], +# [2 - 1j, 0, 2 - 1j, -5 + 4j], +# [-3, 2 + 1j, 0, -4 + 3j], +# [-5 - 2j, -5 - 4j, -4 - 3j, -6], +# ] +# ) + +# @qml.qnode(dev, diff_method=None) +# def circuit(a, b, c): +# ansatz(a, b, c) +# return sample(qml.PauliZ(0) @ qml.Hermitian(A, [1, 2])) + +# s1 = circuit(theta, phi, varphi) + +# # s1 should only contain the eigenvalues of +# # the hermitian matrix tensor product Z +# eigvals = np.linalg.eigvalsh(np.kron(Z, A)) +# assert set(np.round(s1, 8)).issubset(set(np.round(eigvals, 8))) + + class TestApplyLightningMethod: """Unit tests for the apply_lightning method.""" From ab3304a4e95f8d0af3742db9bc0aed49cadbc2b0 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Thu, 25 Jan 2024 15:31:58 -0500 Subject: [PATCH 09/33] update lightning_qubit.py --- pennylane_lightning/lightning_qubit/lightning_qubit.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 243619b724..a00456095e 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -233,7 +233,6 @@ def __init__( # pylint: disable=too-many-arguments # state as an array of dimension [2]*wires. self._state = _state_dtype(c_dtype)(self.num_wires) self._pre_rotated_state = _state_dtype(c_dtype)(self.num_wires) - self._c_dtype = c_dtype self._batch_obs = batch_obs self._mcmc = mcmc @@ -306,6 +305,15 @@ def measurements(self): @property def state(self): + """Copy the state vector data to a numpy array. + + **Example** + + >>> dev = qml.device('lightning.kokkos', wires=1) + >>> dev.apply([qml.PauliX(wires=[0])]) + >>> print(dev.state) + [0.+0.j 1.+0.j] + """ state = np.zeros(2**self.num_wires, dtype=self.C_DTYPE) state = self._asarray(state, dtype=self.C_DTYPE) self._state.getState(state.ravel(order="C")) From 6b9de7cf576f527f4bff2f873936d985a007f90e Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 26 Jan 2024 13:47:57 -0500 Subject: [PATCH 10/33] remove obsolete tests --- tests/test_apply.py | 698 -------------------------------------------- 1 file changed, 698 deletions(-) diff --git a/tests/test_apply.py b/tests/test_apply.py index c2e8cacbd1..fd2748a9b9 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -1187,704 +1187,6 @@ def circuit(): assert np.allclose(res_probs, expected_prob, atol=tol, rtol=0) -@pytest.mark.skipif( - device_name == "lightning.kokkos" or device_name == "lightning.gpu", - reason="lightning.kokkos/gpu does not support apply with rotations.", -) -@pytest.mark.parametrize("theta,phi,varphi", list(zip(THETA, PHI, VARPHI))) -class TestTensorExpval: - """Test tensor expectation values""" - - def test_paulix_pauliy(self, theta, phi, varphi, qubit_device, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qubit_device(wires=3) - dev.reset() - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_identity(self, theta, phi, varphi, qubit_device, tol): - """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = qubit_device(wires=3) - dev.reset() - - obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.cos(varphi) * np.cos(phi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, qubit_device, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qubit_device(wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.skipif( - device_name == "lightning.kokkos" or device_name == "lightning.gpu", - reason="lightning.kokkos/gpu does not support apply with rotations.", -) -@pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) -class TestTensorVar: - """Tests for variance of tensor observables""" - - def test_paulix_pauliy(self, theta, phi, varphi, qubit_device, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qubit_device(wires=3) - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 - - np.cos(2 * (theta - phi)) - - np.cos(2 * (theta + phi)) - + 2 * np.cos(2 * theta) - + 2 * np.cos(2 * phi) - + 14 - ) / 16 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, qubit_device, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qubit_device(wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.skipif( - device_name == "lightning.kokkos" or device_name == "lightning.gpu", - reason="lightning.kokkos/lightning.gpu does not support apply with rotations.", -) -@pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) -@pytest.mark.parametrize("shots", [None, 100000]) -class TestTensorSample: - """Test sampling tensor the tensor product of observables""" - - def test_paulix_pauliy(self, theta, phi, varphi, shots, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - tolerance = tol if shots is None else TOL_STOCHASTIC - dev = qml.device(device_name, wires=3, shots=shots) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() if shots is not None else None - - s1 = qml.eigvals(obs) - p = dev.probability(wires=obs.wires) - - # s1 should only contain 1 and -1 - assert np.allclose(s1**2, 1, atol=tolerance, rtol=0) - - mean = s1 @ p - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - assert np.allclose(mean, expected, atol=tolerance, rtol=0) - - var = (s1**2) @ p - (s1 @ p).real ** 2 - expected = ( - 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 - - np.cos(2 * (theta - phi)) - - np.cos(2 * (theta + phi)) - + 2 * np.cos(2 * theta) - + 2 * np.cos(2 * phi) - + 14 - ) / 16 - assert np.allclose(var, expected, atol=tolerance, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, shots, qubit_device, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - tolerance = tol if shots is None else TOL_STOCHASTIC - dev = qubit_device(wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() if dev.shots is not None else None - - s1 = qml.eigvals(obs) - p = dev.marginal_prob(dev.probability(), wires=obs.wires) - - # s1 should only contain 1 and -1 - assert np.allclose(s1**2, 1, atol=tol, rtol=0) - - mean = s1 @ p - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - assert np.allclose(mean, expected, atol=tol, rtol=0) - - var = (s1**2) @ p - (s1 @ p).real ** 2 - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - assert np.allclose(var, expected, atol=tolerance, rtol=0) - - def test_qubitunitary_rotation_hadamard(self, theta, phi, varphi, shots, qubit_device, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - tolerance = tol if shots is None else TOL_STOCHASTIC - dev = qubit_device(wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - [ - qml.QubitUnitary( - qml.matrix(obs.diagonalizing_gates()[0]), - wires=obs.diagonalizing_gates()[0].wires, - ), - *obs.diagonalizing_gates()[1:], - ], - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() if dev.shots is not None else None - - s1 = qml.eigvals(obs) - p = dev.marginal_prob(dev.probability(), wires=obs.wires) - - # s1 should only contain 1 and -1 - assert np.allclose(s1**2, 1, atol=tol, rtol=0) - - mean = s1 @ p - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - assert np.allclose(mean, expected, atol=tol, rtol=0) - - var = (s1**2) @ p - (s1 @ p).real ** 2 - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - assert np.allclose(var, expected, atol=tolerance, rtol=0) - - -# This block of similar tests coming from pennylane will not fail: -# def ansatz(a, b, c): -# qml.RX(a, wires=0) -# qml.RX(b, wires=1) -# qml.RX(c, wires=2) -# qml.CNOT(wires=[0, 1]) -# qml.CNOT(wires=[1, 2]) -# Z = np.array([[1, 0], [0, -1]]) - -# from pennylane import expval, var, sample - -# @pytest.mark.parametrize("shots", [None, int(1e6)]) -# @pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) -# class TestTensorExpval: -# """Test tensor expectation values""" - -# @pytest.fixture -# def tolerance(self, shots, tol): -# if shots is not None: -# return {"atol": 0.01, "rtol": 0.1} - -# return {"atol": tol, "rtol": 0} - -# def test_tensor_product(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product ZxZ gives the same result as simply -# using an Hermitian matrix""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit1(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliZ(0) @ qml.PauliZ(2)) - -# @qml.qnode(dev) -# def circuit2(a, b, c): -# ansatz(a, b, c) -# return expval(qml.Hermitian(np.kron(Z, Z), wires=[0, 2])) - -# res1 = circuit1(theta, phi, varphi) -# res2 = circuit2(theta, phi, varphi) - -# assert np.allclose(res1, res2, **tolerance) - -# def test_combine_tensor_with_non_tensor(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product along with a non-tensor product -# continues to function correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit1(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliZ(0) @ qml.PauliZ(2)), expval(qml.PauliZ(1)) - -# @qml.qnode(dev) -# def circuit2(a, b, c): -# ansatz(a, b, c) -# return expval(qml.Hermitian(np.kron(Z, Z), wires=[0, 2])) - -# @qml.qnode(dev) -# def circuit3(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliZ(1)) - -# res1 = circuit1(theta, phi, varphi) -# res2 = circuit2(theta, phi, varphi), circuit3(theta, phi, varphi) - -# assert np.allclose(res1, res2, **tolerance) - -# def test_paulix_tensor_pauliy(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving PauliX and PauliY works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliX(0) @ qml.PauliY(2)) - -# res = circuit(theta, phi, varphi) -# expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - -# assert np.allclose(res, expected, **tolerance) - -# @pytest.mark.autograd -# def test_paulix_tensor_pauliy_gradient(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving PauliX and PauliY works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliX(0) @ qml.PauliY(2)) - -# dcircuit = qml.grad(circuit, 0) -# res = dcircuit(theta, phi, varphi) -# expected = np.cos(theta) * np.sin(phi) * np.sin(varphi) - -# assert np.allclose(res, expected, **tolerance) - -# def test_pauliz_tensor_identity(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving PauliZ and Identity works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2)) - -# res = circuit(theta, phi, varphi) -# expected = np.cos(varphi) * np.cos(phi) - -# assert np.allclose(res, expected, **tolerance) - -# def test_pauliz_tensor_hadamard(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving PauliZ and hadamard works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2)) - -# res = circuit(theta, phi, varphi) -# expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - -# assert np.allclose(res, expected, **tolerance) - -# def test_hermitian(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving an Hermitian matrix works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# A = np.array( -# [ -# [-6, 2 + 1j, -3, -5 + 2j], -# [2 - 1j, 0, 2 - 1j, -5 + 4j], -# [-3, 2 + 1j, 0, -4 + 3j], -# [-5 - 2j, -5 - 4j, -4 - 3j, -6], -# ] -# ) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return expval(qml.PauliZ(0) @ qml.Hermitian(A, [1, 2])) - -# res = circuit(theta, phi, varphi) -# expected = 0.5 * ( -# -6 * np.cos(theta) * (np.cos(varphi) + 1) -# - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) -# + 3 * np.cos(varphi) * np.sin(phi) -# + np.sin(phi) -# ) - -# assert np.allclose(res, expected, **tolerance) - -# def test_hermitian_tensor_hermitian(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving two Hermitian matrices works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# A1 = np.array([[1, 2], [2, 4]]) - -# A2 = np.array( -# [ -# [-6, 2 + 1j, -3, -5 + 2j], -# [2 - 1j, 0, 2 - 1j, -5 + 4j], -# [-3, 2 + 1j, 0, -4 + 3j], -# [-5 - 2j, -5 - 4j, -4 - 3j, -6], -# ] -# ) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return expval(qml.Hermitian(A1, 0) @ qml.Hermitian(A2, [1, 2])) - -# res = circuit(theta, phi, varphi) -# expected = 0.25 * ( -# -30 -# + 4 * np.cos(phi) * np.sin(theta) -# + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) -# - 3 * np.sin(phi) -# - 2 -# * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) -# * np.sin(varphi) -# + np.cos(theta) -# * ( -# 18 -# + 5 * np.sin(phi) -# + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) -# + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) -# ) -# ) - -# assert np.allclose(res, expected, **tolerance) - -# def test_hermitian_tensor_identity_expectation(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=2, shots=shots) - -# A = np.array( -# [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] -# ) - -# # pylint: disable=unused-argument -# @qml.qnode(dev) -# def circuit(a, b, c): -# qml.RY(a, wires=0) -# qml.RY(b, wires=1) -# qml.CNOT(wires=[0, 1]) -# return expval(qml.Hermitian(A, 0) @ qml.Identity(1)) - -# res = circuit(theta, phi, varphi) - -# a = A[0, 0] -# re_b = A[0, 1].real -# d = A[1, 1] -# expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - -# assert np.allclose(res, expected, **tolerance) - - -# @pytest.mark.parametrize("shots", [None, int(1e6)]) -# @pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) -# class TestTensorVar: -# """Tests for variance of tensor observables""" - -# @pytest.fixture -# def tolerance(self, shots, tol): -# if shots is not None: -# return {"atol": 0.01, "rtol": 0.2} - -# return {"atol": tol, "rtol": 0} - -# def test_paulix_tensor_pauliy(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving PauliX and PauliY works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return var(qml.PauliX(0) @ qml.PauliY(2)) - -# res = circuit(theta, phi, varphi) -# expected = ( -# 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 -# - np.cos(2 * (theta - phi)) -# - np.cos(2 * (theta + phi)) -# + 2 * np.cos(2 * theta) -# + 2 * np.cos(2 * phi) -# + 14 -# ) / 16 - -# assert np.allclose(res, expected, **tolerance) - -# def test_pauliz_tensor_hadamard(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving PauliZ and hadamard works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return var(qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2)) - -# res = circuit(theta, phi, varphi) -# expected = ( -# 3 -# + np.cos(2 * phi) * np.cos(varphi) ** 2 -# - np.cos(2 * theta) * np.sin(varphi) ** 2 -# - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) -# ) / 4 - -# assert np.allclose(res, expected, **tolerance) - -# def test_tensor_hermitian(self, shots, theta, phi, varphi, tolerance): -# """Test that a tensor product involving qml.Hermitian works correctly""" -# dev = qml.device(device_name, wires=3, shots=shots) -# # dev = qml.device("default.qubit", wires=3, shots=shots) - -# A = np.array( -# [ -# [-6, 2 + 1j, -3, -5 + 2j], -# [2 - 1j, 0, 2 - 1j, -5 + 4j], -# [-3, 2 + 1j, 0, -4 + 3j], -# [-5 - 2j, -5 - 4j, -4 - 3j, -6], -# ] -# ) - -# @qml.qnode(dev) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return var(qml.PauliZ(0) @ qml.Hermitian(A, [1, 2])) - -# res = circuit(theta, phi, varphi) -# expected = ( -# 1057 -# - np.cos(2 * phi) -# + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) -# - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) -# + 16 * np.sin(2 * phi) -# - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) -# - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 -# - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) -# - 8 -# * np.cos(theta) -# * ( -# 4 -# * np.cos(phi) -# * ( -# 4 -# + 8 * np.cos(varphi) -# + np.cos(2 * varphi) -# - (1 + 6 * np.cos(varphi)) * np.sin(varphi) -# ) -# + np.sin(phi) -# * ( -# 15 -# + 8 * np.cos(varphi) -# - 11 * np.cos(2 * varphi) -# + 42 * np.sin(varphi) -# + 3 * np.sin(2 * varphi) -# ) -# ) -# ) / 16 - -# assert np.allclose(res, expected, **tolerance) - - -# def tensor_product(observables): -# return functools.reduce(np.kron, observables) - - -# @pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) -# class TestTensorSample: -# """Tests for samples of tensor observables""" - -# # pylint: disable=unused-argument -# def test_paulix_tensor_pauliz(self, theta, phi, varphi, tol_stochastic): -# """Test that a tensor product involving PauliX and PauliZ works correctly""" -# # dev = qml.device("default.qubit", wires=2, shots=int(1e6)) -# dev = qml.device(device_name, wires=2, shots=int(1e6)) - -# @qml.qnode(dev) -# def circuit(): -# qml.Hadamard(wires=0) -# return sample(qml.PauliX(0) @ qml.PauliZ(1)) - -# s1 = circuit() - -# # s1 should only contain 1 -# assert np.allclose(s1, 1, atol=tol_stochastic, rtol=0) - -# def test_paulix_tensor_pauliy(self, theta, phi, varphi, tol_stochastic): -# """Test that a tensor product involving PauliX and PauliY works correctly""" -# # dev = qml.device("default.qubit", wires=3, shots=int(1e6)) -# dev = qml.device(device_name, wires=3, shots=int(1e6)) - -# @qml.qnode(dev, diff_method="parameter-shift") -# def circuit(a, b, c): -# ansatz(a, b, c) -# return sample(qml.PauliX(0) @ qml.PauliY(2)) - -# s1 = circuit(theta, phi, varphi) - -# # s1 should only contain 1 and -1 -# assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) - -# def test_pauliz_tensor_hadamard(self, theta, phi, varphi, tol_stochastic): -# """Test that a tensor product involving PauliZ and hadamard works correctly""" -# # dev = qml.device("default.qubit", wires=3, shots=int(1e6)) -# dev = qml.device(device_name, wires=3, shots=int(1e6)) - -# @qml.qnode(dev, diff_method="parameter-shift") -# def circuit(a, b, c): -# ansatz(a, b, c) -# return sample(qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2)) - -# s1 = circuit(theta, phi, varphi) - -# # s1 should only contain 1 and -1 -# assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) - -# def test_tensor_hermitian(self, theta, phi, varphi, tol_stochastic): -# """Test that a tensor product involving qml.Hermitian works correctly""" -# # dev = qml.device("default.qubit", wires=3, shots=int(1e6)) -# dev = qml.device(device_name, wires=3, shots=int(1e6)) - -# A = np.array( -# [ -# [-6, 2 + 1j, -3, -5 + 2j], -# [2 - 1j, 0, 2 - 1j, -5 + 4j], -# [-3, 2 + 1j, 0, -4 + 3j], -# [-5 - 2j, -5 - 4j, -4 - 3j, -6], -# ] -# ) - -# @qml.qnode(dev, diff_method=None) -# def circuit(a, b, c): -# ansatz(a, b, c) -# return sample(qml.PauliZ(0) @ qml.Hermitian(A, [1, 2])) - -# s1 = circuit(theta, phi, varphi) - -# # s1 should only contain the eigenvalues of -# # the hermitian matrix tensor product Z -# eigvals = np.linalg.eigvalsh(np.kron(Z, A)) -# assert set(np.round(s1, 8)).issubset(set(np.round(eigvals, 8))) - - class TestApplyLightningMethod: """Unit tests for the apply_lightning method.""" From dd1e632de6473e8aa5a2b60b26fe932fbb062ce3 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 26 Jan 2024 13:53:03 -0500 Subject: [PATCH 11/33] rename statevector instance --- .../lightning_qubit/lightning_qubit.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index a00456095e..4910a4ba37 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -231,8 +231,8 @@ def __init__( # pylint: disable=too-many-arguments # Create the initial state. Internally, we store the # state as an array of dimension [2]*wires. - self._state = _state_dtype(c_dtype)(self.num_wires) - self._pre_rotated_state = _state_dtype(c_dtype)(self.num_wires) + self._qubit_state = _state_dtype(c_dtype)(self.num_wires) + # self._pre_rotated_state = _state_dtype(c_dtype)(self.num_wires) self._batch_obs = batch_obs self._mcmc = mcmc @@ -280,14 +280,14 @@ def _create_basis_state(self, index): Args: index (int): integer representing the computational basis state. """ - self._state.setBasisState(index) + self._qubit_state.setBasisState(index) def reset(self): """Reset the device""" super().reset() # init the state vector to |00..0> - self._state.resetStateVector() + self._qubit_state.resetStateVector() @property def create_ops_list(self): @@ -316,13 +316,13 @@ def state(self): """ state = np.zeros(2**self.num_wires, dtype=self.C_DTYPE) state = self._asarray(state, dtype=self.C_DTYPE) - self._state.getState(state.ravel(order="C")) + self._qubit_state.getState(state.ravel(order="C")) return state @property def state_vector(self): """Returns a handle to the statevector.""" - return self._state + return self._qubit_state def _apply_state_vector(self, state, device_wires): """Initialize the internal state vector in a specified state. @@ -332,10 +332,10 @@ def _apply_state_vector(self, state, device_wires): device_wires (Wires): wires that get initialized in the state """ - if isinstance(state, self._state.__class__): + if isinstance(state, self._qubit_state.__class__): state_data = np.zeros(state.size, dtype=self.C_DTYPE) state_data = self._asarray(state_data, dtype=self.C_DTYPE) - self._state.getState(state_data.ravel(order="C")) + self._qubit_state.getState(state_data.ravel(order="C")) state = state_data ravelled_indices, state = self._preprocess_state_vector(state, device_wires) @@ -347,10 +347,10 @@ def _apply_state_vector(self, state, device_wires): if len(device_wires) == self.num_wires and Wires(sorted(device_wires)) == device_wires: # Initialize the entire device state with the input state state = self._reshape(state, output_shape).ravel(order="C") - self._state.UpdateData(state) + self._qubit_state.UpdateData(state) return - self._state.setStateVector(ravelled_indices, state) # this operation on device + self._qubit_state.setStateVector(ravelled_indices, state) # this operation on device def _apply_basis_state(self, state, wires): """Initialize the state vector in a specified computational basis state. From 2e497fbade9c72700257e98860fc29b1a644a4e3 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 26 Jan 2024 13:54:36 -0500 Subject: [PATCH 12/33] return some important tests --- tests/test_apply.py | 142 ++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/tests/test_apply.py b/tests/test_apply.py index fd2748a9b9..9a00e0d811 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -68,23 +68,23 @@ def test_apply_operation_single_wire_no_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - # @pytest.mark.skipif( - # device_name == "lightning.kokkos" or device_name == "lightning.gpu", - # reason="Only meaningful for lightning_qubit", - # ) - # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - # @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) - # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - # def test_apply_operation_preserve_pointer_single_wire_no_parameters( - # self, qubit_device, operation, input, expected_output, C - # ): - # dev = qubit_device(wires=1) - # dev._state = dev._asarray(input, dtype=C) - # pointer_before, _ = dev._state.__array_interface__["data"] - # dev.apply([operation(wires=[0])]) - # pointer_after, _ = dev._state.__array_interface__["data"] - - # assert pointer_before == pointer_after + @pytest.mark.skipif( + device_name == "lightning.kokkos" or device_name == "lightning.gpu", + reason="Only meaningful for lightning_qubit", + ) + @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) + @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + def test_apply_operation_preserve_pointer_single_wire_no_parameters( + self, qubit_device, operation, input, expected_output, C + ): + dev = qubit_device(wires=1) + dev._state = dev._asarray(input, dtype=C) + pointer_before, _ = dev._state.__array_interface__["data"] + dev.apply([operation(wires=[0])]) + pointer_after, _ = dev._state.__array_interface__["data"] + + assert pointer_before == pointer_after test_data_two_wires_no_parameters = [ (qml.CNOT, [1, 0, 0, 0], [1, 0, 0, 0]), @@ -124,19 +124,19 @@ def test_apply_operation_two_wires_no_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - # @pytest.mark.parametrize("operation,input,expected_output", test_data_two_wires_no_parameters) - # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - # def test_apply_operation_preserve_pointer_two_wires_no_parameters( - # self, qubit_device, operation, input, expected_output, C - # ): - # dev = qubit_device(wires=2) - # dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) - # pointer_before, _ = dev._state.__array_interface__["data"] - # dev.apply([operation(wires=[0, 1])]) - # pointer_after, _ = dev._state.__array_interface__["data"] + @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + @pytest.mark.parametrize("operation,input,expected_output", test_data_two_wires_no_parameters) + @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + def test_apply_operation_preserve_pointer_two_wires_no_parameters( + self, qubit_device, operation, input, expected_output, C + ): + dev = qubit_device(wires=2) + dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) + pointer_before, _ = dev._state.__array_interface__["data"] + dev.apply([operation(wires=[0, 1])]) + pointer_after, _ = dev._state.__array_interface__["data"] - # assert pointer_before == pointer_after + assert pointer_before == pointer_after test_data_three_wires_no_parameters = [ (qml.CSWAP, [1, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0]), @@ -163,19 +163,19 @@ def test_apply_operation_three_wires_no_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - # @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) - # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - # def test_apply_operation_preserve_pointer_three_wires_no_parameters( - # self, qubit_device, operation, input, expected_output, C - # ): - # dev = qubit_device(wires=3) - # dev._state = dev._asarray(input, dtype=C).reshape(3 * [2]) - # pointer_before, _ = dev._state.__array_interface__["data"] - # dev.apply([operation(wires=[0, 1, 2])]) - # pointer_after, _ = dev._state.__array_interface__["data"] + @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) + @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + def test_apply_operation_preserve_pointer_three_wires_no_parameters( + self, qubit_device, operation, input, expected_output, C + ): + dev = qubit_device(wires=3) + dev._state = dev._asarray(input, dtype=C).reshape(3 * [2]) + pointer_before, _ = dev._state.__array_interface__["data"] + dev.apply([operation(wires=[0, 1, 2])]) + pointer_after, _ = dev._state.__array_interface__["data"] - # assert pointer_before == pointer_after + assert pointer_before == pointer_after @pytest.mark.parametrize( "operation,expected_output,par", @@ -308,21 +308,21 @@ def test_apply_operation_single_wire_with_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - # @pytest.mark.parametrize( - # "operation,input,expected_output,par", test_data_single_wire_with_parameters - # ) - # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - # def test_apply_operation_preserve_pointer_single_wire_with_parameters( - # self, qubit_device, operation, input, expected_output, par, C - # ): - # dev = qubit_device(wires=1) - # dev._state = dev._asarray(input, dtype=C) - # pointer_before, _ = dev._state.__array_interface__["data"] - # dev.apply([operation(*par, wires=[0])]) - # pointer_after, _ = dev._state.__array_interface__["data"] - - # assert pointer_before == pointer_after + @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + @pytest.mark.parametrize( + "operation,input,expected_output,par", test_data_single_wire_with_parameters + ) + @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + def test_apply_operation_preserve_pointer_single_wire_with_parameters( + self, qubit_device, operation, input, expected_output, par, C + ): + dev = qubit_device(wires=1) + dev._state = dev._asarray(input, dtype=C) + pointer_before, _ = dev._state.__array_interface__["data"] + dev.apply([operation(*par, wires=[0])]) + pointer_after, _ = dev._state.__array_interface__["data"] + + assert pointer_before == pointer_after """ operation,input,expected_output,par """ test_data_two_wires_with_parameters = [ @@ -459,21 +459,21 @@ def test_apply_operation_two_wires_with_parameters( assert np.allclose(dev.state, np.array(expected_output), atol=tol, rtol=0) assert dev.state.dtype == dev.C_DTYPE - # @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") - # @pytest.mark.parametrize( - # "operation,input,expected_output,par", test_data_two_wires_with_parameters - # ) - # @pytest.mark.parametrize("C", [np.complex64, np.complex128]) - # def test_apply_operation_preserve_pointer_two_wires_with_parameters( - # self, qubit_device, operation, input, expected_output, par, C - # ): - # dev = qubit_device(wires=2) - # dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) - # pointer_before, _ = dev._state.__array_interface__["data"] - # dev.apply([operation(*par, wires=[0, 1])]) - # pointer_after, _ = dev._state.__array_interface__["data"] - - # assert pointer_before == pointer_after + @pytest.mark.skipif(not ld._CPP_BINARY_AVAILABLE, reason="Lightning binary required") + @pytest.mark.parametrize( + "operation,input,expected_output,par", test_data_two_wires_with_parameters + ) + @pytest.mark.parametrize("C", [np.complex64, np.complex128]) + def test_apply_operation_preserve_pointer_two_wires_with_parameters( + self, qubit_device, operation, input, expected_output, par, C + ): + dev = qubit_device(wires=2) + dev._state = dev._asarray(input, dtype=C).reshape(2 * [2]) + pointer_before, _ = dev._state.__array_interface__["data"] + dev.apply([operation(*par, wires=[0, 1])]) + pointer_after, _ = dev._state.__array_interface__["data"] + + assert pointer_before == pointer_after @pytest.mark.parametrize("stateprep", [qml.QubitStateVector, qml.StatePrep]) def test_apply_errors_qubit_state_vector(self, stateprep, qubit_device): From d0675d1f8094b0cd437785318648f1272de95a37 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 26 Jan 2024 14:03:08 -0500 Subject: [PATCH 13/33] implement PR review sugestions --- .gitignore | 4 +--- Makefile | 4 +--- .../lightning_qubit/StateVectorLQubitManaged.hpp | 10 +++++----- .../lightning_qubit/bindings/LQubitBindings.hpp | 4 ++-- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 5be229e6f7..df49993fc2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,7 @@ doc/code/api/ PennyLane_Lightning.egg-info/ PennyLane_Lightning_Kokkos.egg-info/ build/ -build_lightning_qubit/ -build_lightning_kokkos/ -build_lightning_gpu/ +build_lightning_*/ Build/ BuildCov/ BuildGBench/ diff --git a/Makefile b/Makefile index 1c29725ed2..0e9031f427 100644 --- a/Makefile +++ b/Makefile @@ -59,9 +59,7 @@ help: clean: find . -type d -name '__pycache__' -exec rm -r {} \+ rm -rf build Build BuildTests BuildTidy BuildGBench - rm -rf build_lightning_qubit - rm -rf build_lightning_kokkos - rm -rf build_lightning_gpu + rm -rf build_* rm -rf .coverage coverage_html_report/ rm -rf pennylane_lightning/*_ops* diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp index 93b256acae..727b431b63 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/StateVectorLQubitManaged.hpp @@ -72,7 +72,7 @@ class StateVectorLQubitManaged final * @param memory_model Memory model the statevector will use */ explicit StateVectorLQubitManaged( - size_t num_qubits, Threading threading = Threading::SingleThread, + std::size_t num_qubits, Threading threading = Threading::SingleThread, CPUMemoryModel memory_model = bestCPUMemoryModel()) : BaseType{num_qubits, threading, memory_model}, data_{exp2(num_qubits), ComplexT{0.0, 0.0}, @@ -103,7 +103,7 @@ class StateVectorLQubitManaged final * @param threading Threading option the statevector to use * @param memory_model Memory model the statevector will use */ - StateVectorLQubitManaged(const ComplexT *other_data, size_t other_size, + StateVectorLQubitManaged(const ComplexT *other_data, std::size_t other_size, Threading threading = Threading::SingleThread, CPUMemoryModel memory_model = bestCPUMemoryModel()) : BaseType(log2PerfectPower(other_size), threading, memory_model), @@ -145,7 +145,7 @@ class StateVectorLQubitManaged final * * @param index Index of the target element. */ - void setBasisState(const size_t index) { + void setBasisState(const std::size_t index) { std::fill(data_.begin(), data_.end(), 0); data_[index] = {1, 0}; } @@ -158,7 +158,7 @@ class StateVectorLQubitManaged final */ void setStateVector(const std::vector &indices, const std::vector &values) { - for (size_t n = 0; n < indices.size(); n++) { + for (std::size_t n = 0; n < indices.size(); n++) { data_[indices[n]] = values[n]; } } @@ -198,7 +198,7 @@ class StateVectorLQubitManaged final * @param new_data data pointer to new data. * @param new_size size of underlying data storage. */ - void updateData(const ComplexT *new_data, size_t new_size) { + void updateData(const ComplexT *new_data, std::size_t new_size) { PL_ASSERT(data_.size() == new_size); std::copy(new_data, new_data + new_size, data_.data()); } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp index abea4c7632..74352a08aa 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/bindings/LQubitBindings.hpp @@ -207,7 +207,7 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { data_ptr); } }, - "Synchronize data from the GPU device to host.") + "Copy StateVector data into a Numpy array.") .def( "UpdateData", [](StateVectorT &device_sv, const np_arr_c &state) { @@ -219,7 +219,7 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { device_sv.updateData(data_ptr, length); } }, - "Synchronize data from the host device to GPU.") + "Copy StateVector data into a Numpy array.") .def("applyControlledMatrix", &applyControlledMatrix, "Apply controlled operation") .def("kernel_map", &svKernelMap, From 1ec3cd25039e9fd7c73b0f5de95a46f2c2773c8c Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Fri, 26 Jan 2024 15:48:33 -0500 Subject: [PATCH 14/33] add review suggestion --- .../lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp index 3d94289571..56497a84d5 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp @@ -124,11 +124,9 @@ TEMPLATE_TEST_CASE("StateVectorLQubitManaged::setBasisState", TestVectorT expected_state(size_t{1U} << num_qubits, 0.0, getBestAllocator()); - expected_state[3] = {1.0, 0.0}; - + std::size_t index = GENERATE(0, 1, 2, 3, 4, 5, 6, 7) + expected_state[index] = {1.0, 0.0}; StateVectorLQubitManaged sv(init_state); - - size_t index = 3; sv.setBasisState(index); REQUIRE(sv.getDataVector() == approx(expected_state)); From 9c66497cd13b7d35d71f5c03ecc5af91cf75e4e8 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Fri, 26 Jan 2024 15:55:52 -0500 Subject: [PATCH 15/33] Add semi-colon. --- .../lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp index 56497a84d5..45b97d1b4f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp @@ -124,7 +124,7 @@ TEMPLATE_TEST_CASE("StateVectorLQubitManaged::setBasisState", TestVectorT expected_state(size_t{1U} << num_qubits, 0.0, getBestAllocator()); - std::size_t index = GENERATE(0, 1, 2, 3, 4, 5, 6, 7) + std::size_t index = GENERATE(0, 1, 2, 3, 4, 5, 6, 7); expected_state[index] = {1.0, 0.0}; StateVectorLQubitManaged sv(init_state); sv.setBasisState(index); From 31f4104c6b0002cfa899d5e06d233d7013e6e24d Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Mon, 29 Jan 2024 09:01:29 -0500 Subject: [PATCH 16/33] Fix Projector obs in L-Qubit and add Proj support in L-Kokkos. --- .../lightning_kokkos/lightning_kokkos.py | 13 ++++++++----- .../lightning_qubit/lightning_qubit.py | 4 ++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index f3153dcfe9..867e8223c7 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -150,6 +150,7 @@ def _kokkos_configuration(): "Hadamard", "Hermitian", "Identity", + "Projector", "SparseHamiltonian", "Hamiltonian", "Sum", @@ -196,7 +197,7 @@ def __init__( shots=None, batch_obs=False, kokkos_args=None, - ): # pylint: disable=unused-argument + ): # pylint: disable=unused-argument, too-many-arguments super().__init__(wires, shots=shots, c_dtype=c_dtype) if kokkos_args is None: @@ -213,10 +214,6 @@ def __init__( if not LightningKokkos.kokkos_config: LightningKokkos.kokkos_config = _kokkos_configuration() - # Create the initial state. Internally, we store the - # state as an array of dimension [2]*wires. - self._pre_rotated_state = _kokkos_dtype(c_dtype)(self.num_wires) - @staticmethod def _asarray(arr, dtype=None): arr = np.asarray(arr) # arr is not copied @@ -466,8 +463,11 @@ def expval(self, observable, shot_range=None, bin_size=None): Expectation value of the observable """ if observable.name in [ + "Identity", "Projector", ]: + qs = qml.tape.QuantumScript([], [qml.expval(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().expval(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: @@ -526,8 +526,11 @@ def var(self, observable, shot_range=None, bin_size=None): Variance of the observable """ if observable.name in [ + "Identity", "Projector", ]: + qs = qml.tape.QuantumScript([], [qml.var(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().var(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 4910a4ba37..d3c37fd959 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -494,6 +494,8 @@ def expval(self, observable, shot_range=None, bin_size=None): "Identity", "Projector", ]: + qs = qml.tape.QuantumScript([], [qml.expval(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().expval(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: @@ -548,6 +550,8 @@ def var(self, observable, shot_range=None, bin_size=None): "Identity", "Projector", ]: + qs = qml.tape.QuantumScript([], [qml.var(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().var(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: From 7ee08a220be1568f0f5b04f10a1e3688bd01ec3b Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Mon, 29 Jan 2024 09:10:38 -0500 Subject: [PATCH 17/33] Implement previous commit fix for None shots only. --- .../lightning_kokkos/lightning_kokkos.py | 10 ++++++---- pennylane_lightning/lightning_qubit/lightning_qubit.py | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 867e8223c7..6d719b2b2d 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -466,8 +466,9 @@ def expval(self, observable, shot_range=None, bin_size=None): "Identity", "Projector", ]: - qs = qml.tape.QuantumScript([], [qml.expval(observable)]) - self.apply(self._get_diagonalizing_gates(qs)) + if self.shots is None: + qs = qml.tape.QuantumScript([], [qml.expval(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().expval(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: @@ -529,8 +530,9 @@ def var(self, observable, shot_range=None, bin_size=None): "Identity", "Projector", ]: - qs = qml.tape.QuantumScript([], [qml.var(observable)]) - self.apply(self._get_diagonalizing_gates(qs)) + if self.shots is None: + qs = qml.tape.QuantumScript([], [qml.var(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().var(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index d3c37fd959..a0b3735530 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -494,8 +494,9 @@ def expval(self, observable, shot_range=None, bin_size=None): "Identity", "Projector", ]: - qs = qml.tape.QuantumScript([], [qml.expval(observable)]) - self.apply(self._get_diagonalizing_gates(qs)) + if self.shots is None: + qs = qml.tape.QuantumScript([], [qml.expval(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().expval(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: @@ -550,8 +551,9 @@ def var(self, observable, shot_range=None, bin_size=None): "Identity", "Projector", ]: - qs = qml.tape.QuantumScript([], [qml.var(observable)]) - self.apply(self._get_diagonalizing_gates(qs)) + if self.shots is None: + qs = qml.tape.QuantumScript([], [qml.var(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) return super().var(observable, shot_range=shot_range, bin_size=bin_size) if self.shots is not None: From 8df8a2a145bf3f514dfa2b70fa857b6a06c601e6 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Mon, 29 Jan 2024 09:25:30 -0500 Subject: [PATCH 18/33] Add tests for Proj expval/var --- tests/test_expval.py | 23 ++++++++++++++++++++++- tests/test_var.py | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/test_expval.py b/tests/test_expval.py index e64ef2a329..1073f16200 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -106,9 +106,30 @@ def test_hadamard_expectation(self, theta, phi, qubit_device, tol): ) / np.sqrt(2) assert np.allclose(res, expected, tol) + def test_projector_expectation(self, theta, phi, qubit_device, tol): + """Test that Projector variance value is correct""" + n_qubits = 2 + dev_def = qml.device("default.qubit", wires=n_qubits) + dev = qubit_device(wires=n_qubits) + + init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) + init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) + obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) + + def circuit(): + qml.StatePrep(init_state, wires=range(n_qubits)) + qml.RY(theta, wires=[0]) + qml.RY(phi, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(obs) + + circ = qml.QNode(circuit, dev) + circ_def = qml.QNode(circuit, dev_def) + assert np.allclose(circ(), circ_def(), tol) + @pytest.mark.parametrize("n_wires", range(1, 7)) def test_hermitian_expectation(self, n_wires, theta, phi, qubit_device, tol): - """Test that Hadamard expectation value is correct""" + """Test that Hermitian expectation value is correct""" n_qubits = 7 dev_def = qml.device("default.qubit", wires=n_qubits) dev = qubit_device(wires=n_qubits) diff --git a/tests/test_var.py b/tests/test_var.py index 76946705d0..ae1cf9b2c6 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -47,6 +47,27 @@ def test_var(self, theta, phi, qubit_device, tol): assert np.allclose(var, expected, tol) + def test_projector_var(self, theta, phi, qubit_device, tol): + """Test that Projector variance value is correct""" + n_qubits = 2 + dev_def = qml.device("default.qubit", wires=n_qubits) + dev = qubit_device(wires=n_qubits) + + init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) + init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) + obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) + + def circuit(): + qml.StatePrep(init_state, wires=range(n_qubits)) + qml.RY(theta, wires=[0]) + qml.RY(phi, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(obs) + + circ = qml.QNode(circuit, dev) + circ_def = qml.QNode(circuit, dev_def) + assert np.allclose(circ(), circ_def(), tol) + @pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) class TestTensorVar: From 9e39e056c78536526cf2d9f095d0f77afb21f218 Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Mon, 29 Jan 2024 15:54:43 +0000 Subject: [PATCH 19/33] Auto update version --- 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 5301226fd1..3676e2aa5a 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.35.0-dev8" +__version__ = "0.35.0-dev9" From e6412bf561bcf9cb60eecaf9aae28933479ad80d Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 10:59:48 -0500 Subject: [PATCH 20/33] Trigger CI From 4e7f1a93db02e8932c6439c38716226697390bbf Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 11:15:53 -0500 Subject: [PATCH 21/33] remove comment --- pennylane_lightning/lightning_qubit/lightning_qubit.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index a0b3735530..177ddb3744 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -232,8 +232,6 @@ def __init__( # pylint: disable=too-many-arguments # Create the initial state. Internally, we store the # state as an array of dimension [2]*wires. self._qubit_state = _state_dtype(c_dtype)(self.num_wires) - # self._pre_rotated_state = _state_dtype(c_dtype)(self.num_wires) - self._batch_obs = batch_obs self._mcmc = mcmc if self._mcmc: From 0c8cffbd61e29ca196028c042db23d6369a2c3d7 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 11:16:16 -0500 Subject: [PATCH 22/33] add projector support to LGPU --- .../lightning_gpu/lightning_gpu.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index 349e821959..13fa987c43 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -197,6 +197,7 @@ def _mebibytesToBytes(mebibytes): "Hamiltonian", "Hermitian", "Identity", + "Projector", "Sum", "Prod", "SProd", @@ -866,6 +867,15 @@ def expval(self, observable, shot_range=None, bin_size=None): Returns: Expectation value of the observable """ + if observable.name in [ + "Identity", + "Projector", + ]: + if self.shots is None: + qs = qml.tape.QuantumScript([], [qml.expval(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) + return super().expval(observable, shot_range=shot_range, bin_size=bin_size) + if self.shots is not None: # estimate the expectation value samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) @@ -950,6 +960,15 @@ def var(self, observable, shot_range=None, bin_size=None): Returns: Variance of the observable """ + if observable.name in [ + "Identity", + "Projector", + ]: + if self.shots is None: + qs = qml.tape.QuantumScript([], [qml.var(observable)]) + self.apply(self._get_diagonalizing_gates(qs)) + return super().var(observable, shot_range=shot_range, bin_size=bin_size) + if self.shots is not None: # estimate the var # Lightning doesn't support sampling yet From 645bbe09dbb2d3524f6c3a11a67b05a6020aee8a Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 11:17:39 -0500 Subject: [PATCH 23/33] format --- pennylane_lightning/lightning_gpu/lightning_gpu.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index 13fa987c43..462761a93e 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -875,7 +875,7 @@ def expval(self, observable, shot_range=None, bin_size=None): qs = qml.tape.QuantumScript([], [qml.expval(observable)]) self.apply(self._get_diagonalizing_gates(qs)) return super().expval(observable, shot_range=shot_range, bin_size=bin_size) - + if self.shots is not None: # estimate the expectation value samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) @@ -968,7 +968,7 @@ def var(self, observable, shot_range=None, bin_size=None): qs = qml.tape.QuantumScript([], [qml.var(observable)]) self.apply(self._get_diagonalizing_gates(qs)) return super().var(observable, shot_range=shot_range, bin_size=bin_size) - + if self.shots is not None: # estimate the var # Lightning doesn't support sampling yet From 40a8a00ea42ef79700ef4a1c223cc9942e0b3cde Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 12:35:13 -0500 Subject: [PATCH 24/33] revert changes for LGPU --- .../lightning_gpu/lightning_gpu.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.py b/pennylane_lightning/lightning_gpu/lightning_gpu.py index 462761a93e..349e821959 100644 --- a/pennylane_lightning/lightning_gpu/lightning_gpu.py +++ b/pennylane_lightning/lightning_gpu/lightning_gpu.py @@ -197,7 +197,6 @@ def _mebibytesToBytes(mebibytes): "Hamiltonian", "Hermitian", "Identity", - "Projector", "Sum", "Prod", "SProd", @@ -867,15 +866,6 @@ def expval(self, observable, shot_range=None, bin_size=None): Returns: Expectation value of the observable """ - if observable.name in [ - "Identity", - "Projector", - ]: - if self.shots is None: - qs = qml.tape.QuantumScript([], [qml.expval(observable)]) - self.apply(self._get_diagonalizing_gates(qs)) - return super().expval(observable, shot_range=shot_range, bin_size=bin_size) - if self.shots is not None: # estimate the expectation value samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size) @@ -960,15 +950,6 @@ def var(self, observable, shot_range=None, bin_size=None): Returns: Variance of the observable """ - if observable.name in [ - "Identity", - "Projector", - ]: - if self.shots is None: - qs = qml.tape.QuantumScript([], [qml.var(observable)]) - self.apply(self._get_diagonalizing_gates(qs)) - return super().var(observable, shot_range=shot_range, bin_size=bin_size) - if self.shots is not None: # estimate the var # Lightning doesn't support sampling yet From 8d28fd450dd1fa8df57b8fee49dff7cff8ec80f8 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 12:38:07 -0500 Subject: [PATCH 25/33] skip tests for Projector observable not supported --- tests/test_expval.py | 3 +++ tests/test_var.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/test_expval.py b/tests/test_expval.py index 1073f16200..561a9ed235 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -112,6 +112,9 @@ def test_projector_expectation(self, theta, phi, qubit_device, tol): dev_def = qml.device("default.qubit", wires=n_qubits) dev = qubit_device(wires=n_qubits) + if "Projector" not in dev.observables: + pytest.skip("Device does not support the Projector observable.") + init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) diff --git a/tests/test_var.py b/tests/test_var.py index ae1cf9b2c6..ccee5cda20 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -53,6 +53,9 @@ def test_projector_var(self, theta, phi, qubit_device, tol): dev_def = qml.device("default.qubit", wires=n_qubits) dev = qubit_device(wires=n_qubits) + if "Projector" not in dev.observables: + pytest.skip("Device does not support the Projector observable.") + init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1]) From f115f6f7d63803c3b2485fc70b5b4c711c167fd4 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 14:34:43 -0500 Subject: [PATCH 26/33] expand tests for lightning.qubit --- tests/test_adjoint_jacobian.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index 58a156aa4a..d88bb23e10 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -583,8 +583,8 @@ def test_provide_starting_state(self, tol, dev): dM1 = dev.adjoint_jacobian(tape) - if device_name == "lightning.kokkos": - dev._pre_rotated_state = dev.state_vector # necessary for lightning.kokkos + if device_name in ["lightning.kokkos", "lightning.qubit"]: + dev._pre_rotated_state = dev.state_vector qml.execute([tape], dev, None) dM2 = dev.adjoint_jacobian(tape, starting_state=dev._pre_rotated_state) From 3d67dfebfbeabf54bae5692b6f7c2ba916d9ae87 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 14:57:49 -0500 Subject: [PATCH 27/33] update changelog --- .github/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index ab31f2ce57..b2d9ed2af3 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -9,6 +9,12 @@ ### Improvements +* Decouple LightningQubit memory ownership from numpy and migrate it to LightningQubit managed state-vector class. + [(#601)](https://github.com/PennyLaneAI/pennylane-lightning/pull/601) + +* Expand support for Projector observables on LightningKokkos. + [(#601)](https://github.com/PennyLaneAI/pennylane-lightning/pull/601) + * Split Docker build cron job into two jobs: master and latest. This is mainly for reporting in the `plugin-test-matrix` repo. [(#600)](https://github.com/PennyLaneAI/pennylane-lightning/pull/600) From 0d7b87646d511a975b4feed5eec4421b49a16f8e Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Mon, 29 Jan 2024 20:59:39 +0000 Subject: [PATCH 28/33] Auto update version --- 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 3676e2aa5a..3c07426591 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.35.0-dev9" +__version__ = "0.35.0-dev10" From 2e7d363f38de7ae3c6a68ff4bddeee522ac3ba45 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 16:01:36 -0500 Subject: [PATCH 29/33] Trigger CI From 6a2cab9e02896ea9b7253184afb3e9364bc3ec61 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Mon, 29 Jan 2024 16:16:53 -0500 Subject: [PATCH 30/33] add some review suggestions --- .github/CHANGELOG.md | 4 ++-- tests/test_adjoint_jacobian.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 4615df54fc..be57b94646 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -9,10 +9,10 @@ ### Improvements -* Decouple LightningQubit memory ownership from numpy and migrate it to LightningQubit managed state-vector class. +* Decouple LightningQubit memory ownership from numpy and migrate it to Lightning-Qubit managed state-vector class. [(#601)](https://github.com/PennyLaneAI/pennylane-lightning/pull/601) -* Expand support for Projector observables on LightningKokkos. +* Expand support for Projector observables on Lightning-Kokkos. [(#601)](https://github.com/PennyLaneAI/pennylane-lightning/pull/601) * Split Docker build cron job into two jobs: master and latest. This is mainly for reporting in the `plugin-test-matrix` repo. diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index d88bb23e10..86c0a9e246 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -584,10 +584,8 @@ def test_provide_starting_state(self, tol, dev): dM1 = dev.adjoint_jacobian(tape) if device_name in ["lightning.kokkos", "lightning.qubit"]: - dev._pre_rotated_state = dev.state_vector - qml.execute([tape], dev, None) - dM2 = dev.adjoint_jacobian(tape, starting_state=dev._pre_rotated_state) + dM2 = dev.adjoint_jacobian(tape, starting_state=dev.state_vector) assert np.allclose(dM1, dM2, atol=tol, rtol=0) else: From e80072542253866431dcf9286834335666e20b4e Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Tue, 30 Jan 2024 08:35:39 -0500 Subject: [PATCH 31/33] remove identities --- pennylane_lightning/lightning_kokkos/lightning_kokkos.py | 2 -- pennylane_lightning/lightning_qubit/lightning_qubit.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 6d719b2b2d..742948ca47 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -463,7 +463,6 @@ def expval(self, observable, shot_range=None, bin_size=None): Expectation value of the observable """ if observable.name in [ - "Identity", "Projector", ]: if self.shots is None: @@ -527,7 +526,6 @@ def var(self, observable, shot_range=None, bin_size=None): Variance of the observable """ if observable.name in [ - "Identity", "Projector", ]: if self.shots is None: diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 177ddb3744..8c0f16bef2 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -489,7 +489,6 @@ def expval(self, observable, shot_range=None, bin_size=None): Expectation value of the observable """ if observable.name in [ - "Identity", "Projector", ]: if self.shots is None: @@ -546,7 +545,6 @@ def var(self, observable, shot_range=None, bin_size=None): Variance of the observable """ if observable.name in [ - "Identity", "Projector", ]: if self.shots is None: From 1dc6b3ebf3fada8bf3becb3fd8873bee8e4726c3 Mon Sep 17 00:00:00 2001 From: AmintorDusko Date: Tue, 30 Jan 2024 09:07:01 -0500 Subject: [PATCH 32/33] update LKokkos and LQubit _apply_state_vector --- pennylane_lightning/lightning_kokkos/lightning_kokkos.py | 5 ++--- pennylane_lightning/lightning_qubit/lightning_qubit.py | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py index 742948ca47..401a6d6de0 100644 --- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.py +++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.py @@ -344,9 +344,8 @@ def _apply_state_vector(self, state, device_wires): """ if isinstance(state, self._kokkos_state.__class__): - state_data = np.zeros(state.size, dtype=self.C_DTYPE) - state_data = self._asarray(state_data, dtype=self.C_DTYPE) - state.DeviceToHost(state_data.ravel(order="C")) + state_data = allocate_aligned_array(state.size, np.dtype(self.C_DTYPE), True) + state.DeviceToHost(state_data) state = state_data ravelled_indices, state = self._preprocess_state_vector(state, device_wires) diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 8c0f16bef2..f6ff7d2fea 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -314,7 +314,7 @@ def state(self): """ state = np.zeros(2**self.num_wires, dtype=self.C_DTYPE) state = self._asarray(state, dtype=self.C_DTYPE) - self._qubit_state.getState(state.ravel(order="C")) + self._qubit_state.getState(state) return state @property @@ -331,9 +331,8 @@ def _apply_state_vector(self, state, device_wires): """ if isinstance(state, self._qubit_state.__class__): - state_data = np.zeros(state.size, dtype=self.C_DTYPE) - state_data = self._asarray(state_data, dtype=self.C_DTYPE) - self._qubit_state.getState(state_data.ravel(order="C")) + state_data = allocate_aligned_array(state.size, np.dtype(self.C_DTYPE), True) + self._qubit_state.getState(state_data) state = state_data ravelled_indices, state = self._preprocess_state_vector(state, device_wires) From 91d672e4103aa1243a1cfe27017cda8516d62f54 Mon Sep 17 00:00:00 2001 From: Amintor Dusko <87949283+AmintorDusko@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:54:12 -0500 Subject: [PATCH 33/33] Update tests/test_apply.py Co-authored-by: Lee James O'Riordan --- tests/test_apply.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_apply.py b/tests/test_apply.py index 9a00e0d811..c889eb6e18 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -58,7 +58,6 @@ def test_apply_operation_single_wire_no_parameters( ): """Tests that applying an operation yields the expected output state for single wire operations that have no parameters.""" - # from pennylane.wires import Wires dev = qubit_device(wires=1) _state = np.array(input).astype(dev.C_DTYPE)