diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 0ff382d5c8..d355136bde 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add `qml.StatePrep()` and `qml.QubitStateVector()` support to `lightning.tensor`. + [(#849)](https://github.com/PennyLaneAI/pennylane-lightning/pull/849) + * Add LightningGPU Linux (aarch64+GraceHopper) wheels to PyPI. [(#815)](https://github.com/PennyLaneAI/pennylane-lightning/pull/815) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 33a207e9fb..b7dfacadb0 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.38.0-dev43" +__version__ = "0.38.0-dev44" diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp index dad38bfdd6..178d987a10 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -64,7 +64,7 @@ class MPSTNCuda final : public TNCudaBase> { MPSStatus MPSInitialized_ = MPSStatus::MPSInitNotSet; const std::size_t maxBondDim_; - + const std::vector bondDims_; const std::vector> sitesModes_; const std::vector> sitesExtents_; const std::vector> sitesExtents_int64_; @@ -86,9 +86,12 @@ class MPSTNCuda final : public TNCudaBase> { explicit MPSTNCuda(const std::size_t numQubits, const std::size_t maxBondDim) : BaseType(numQubits), maxBondDim_(maxBondDim), - sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()), + bondDims_(setBondDims_()), sitesModes_(setSitesModes_()), + sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); + reset(); + appendInitialMPSState_(); } // TODO: Add method to the constructor to allow users to select methods at @@ -96,9 +99,12 @@ class MPSTNCuda final : public TNCudaBase> { explicit MPSTNCuda(const std::size_t numQubits, const std::size_t maxBondDim, DevTag dev_tag) : BaseType(numQubits, dev_tag), maxBondDim_(maxBondDim), - sitesModes_(setSitesModes_()), sitesExtents_(setSitesExtents_()), + bondDims_(setBondDims_()), sitesModes_(setSitesModes_()), + sitesExtents_(setSitesExtents_()), sitesExtents_int64_(setSitesExtents_int64_()) { initTensors_(); + reset(); + appendInitialMPSState_(); } ~MPSTNCuda() = default; @@ -162,6 +168,31 @@ class MPSTNCuda final : public TNCudaBase> { setBasisState(zeroState); } + /** + * @brief Update the ith MPS site data. + * + * @param site_idx Index of the MPS site. + * @param host_data Pointer to the data on host. + * @param host_data_size Length of the data. + */ + void updateMPSSiteData(const std::size_t site_idx, + const ComplexT *host_data, + std::size_t host_data_size) { + PL_ABORT_IF_NOT( + site_idx < BaseType::getNumQubits(), + "The site index should be less than the number of qubits."); + + const std::size_t idx = BaseType::getNumQubits() - site_idx - 1; + PL_ABORT_IF_NOT( + host_data_size == tensors_[idx].getDataBuffer().getLength(), + "The length of the host data should match its copy on the device."); + + tensors_[idx].getDataBuffer().zeroInit(); + + tensors_[idx].getDataBuffer().CopyHostDataToGpu(host_data, + host_data_size); + } + /** * @brief Update quantum state with a basis state. * NOTE: This API assumes the bond vector is a standard basis vector @@ -192,18 +223,13 @@ class MPSTNCuda final : public TNCudaBase> { if (i == 0) { target = basisState[idx]; } else { - target = basisState[idx] == 0 ? 0 : maxBondDim_; + target = basisState[idx] == 0 ? 0 : bondDims_[i - 1]; } PL_CUDA_IS_SUCCESS( cudaMemcpy(&tensors_[i].getDataBuffer().getData()[target], &value_cu, sizeof(CFP_t), cudaMemcpyHostToDevice)); } - - if (MPSInitialized_ == MPSStatus::MPSInitNotSet) { - MPSInitialized_ = MPSStatus::MPSInitSet; - updateQuantumStateMPS_(); - } }; /** @@ -307,6 +333,27 @@ class MPSTNCuda final : public TNCudaBase> { } private: + /** + * @brief Return bondDims to the member initializer + * NOTE: This method only works for the open boundary condition + * @return std::vector + */ + std::vector setBondDims_() { + std::vector localBondDims(BaseType::getNumQubits() - 1, + maxBondDim_); + + const std::size_t ubDim = log2(maxBondDim_); + for (std::size_t i = 0; i < localBondDims.size(); i++) { + const std::size_t bondDim = + std::min(i + 1, BaseType::getNumQubits() - i - 1); + + if (bondDim <= ubDim) { + localBondDims[i] = std::size_t{1} << bondDim; + } + } + return localBondDims; + } + /** * @brief Return siteModes to the member initializer * NOTE: This method only works for the open boundary condition @@ -348,15 +395,16 @@ class MPSTNCuda final : public TNCudaBase> { if (i == 0) { // Leftmost site (state mode, shared mode) localSiteExtents = std::vector( - {BaseType::getQubitDims()[i], maxBondDim_}); + {BaseType::getQubitDims()[i], bondDims_[i]}); } else if (i == BaseType::getNumQubits() - 1) { // Rightmost site (shared mode, state mode) localSiteExtents = std::vector( - {maxBondDim_, BaseType::getQubitDims()[i]}); + {bondDims_[i - 1], BaseType::getQubitDims()[i]}); } else { // Interior sites (state mode, state mode, shared mode) localSiteExtents = std::vector( - {maxBondDim_, BaseType::getQubitDims()[i], maxBondDim_}); + {bondDims_[i - 1], BaseType::getQubitDims()[i], + bondDims_[i]}); } localSitesExtents.push_back(std::move(localSiteExtents)); } @@ -394,11 +442,11 @@ class MPSTNCuda final : public TNCudaBase> { } /** - * @brief Update quantumState (cutensornetState_t) with data provided by a - * user + * @brief Append initial MPS sites to the compute graph with data provided + * by a user * */ - void updateQuantumStateMPS_() { + void appendInitialMPSState_() { PL_CUTENSORNET_IS_SUCCESS(cutensornetStateInitializeMPS( /*const cutensornetHandle_t */ BaseType::getTNCudaHandle(), /*cutensornetState_t*/ BaseType::getQuantumState(), diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp index 5dd6efe701..aee4834a72 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp @@ -74,6 +74,18 @@ void registerBackendClassSpecificBindings(PyClass &pyclass) { tensor_network.getData(data_ptr, state.size()); }, "Copy StateVector data into a Numpy array.") + .def( + "updateMPSSitesData", + [](TensorNet &tensor_network, std::vector &tensors) { + for (std::size_t idx = 0; idx < tensors.size(); idx++) { + py::buffer_info numpyArrayInfo = tensors[idx].request(); + auto *data_ptr = static_cast *>( + numpyArrayInfo.ptr); + tensor_network.updateMPSSiteData(idx, data_ptr, + tensors[idx].size()); + } + }, + "Pass MPS site data to the C++ backend.") .def( "setBasisState", [](TensorNet &tensor_network, diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp index 344bb8eea0..21b809a301 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/measurements/tests/Test_MPSTNCuda_Expval.cpp @@ -203,7 +203,7 @@ TEMPLATE_TEST_CASE("[PauliZ]", "[MPSTNCuda_Expval]", float, double) { PrecisionT ref = -0.2115276040475712; REQUIRE_THAT(res, Catch::Matchers::WithinRel( - ref, static_cast(cutoff))); + ref, static_cast(0.1))); } } } diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp index 78363c43b8..1cea281878 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp @@ -58,6 +58,67 @@ TEMPLATE_PRODUCT_TEST_CASE("MPSTNCuda::Constructibility", } } +TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { + SECTION("Set MPS site with wrong site index") { + const std::size_t num_qubits = 3; + const std::size_t maxBondDim = 3; + const std::size_t siteIdx = 3; + + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> site_data(1, {0.0, 0.0}); + + REQUIRE_THROWS_WITH( + mps_state.updateMPSSiteData(siteIdx, site_data.data(), + site_data.size()), + Catch::Matchers::Contains( + "The site index should be less than the number of qubits.")); + } + + SECTION("Set MPS site with wrong site data size") { + const std::size_t num_qubits = 3; + const std::size_t maxBondDim = 3; + const std::size_t siteIdx = 0; + + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> site_data(1, {0.0, 0.0}); + + REQUIRE_THROWS_WITH( + mps_state.updateMPSSiteData(siteIdx, site_data.data(), + site_data.size()), + Catch::Matchers::Contains("The length of the host data should " + "match its copy on the device.")); + } + + SECTION("Set MPS sites") { + const std::size_t num_qubits = 2; + const std::size_t maxBondDim = 3; + + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + mps_state.reset(); // Reset the state to zero state + + std::vector> site0_data(4, {0.0, 0.0}); // MSB + std::vector> site1_data(4, {0.0, 0.0}); // LSB + + site0_data[2] = {1.0, 0.0}; + site1_data[1] = {1.0, 0.0}; + + mps_state.updateMPSSiteData(0, site0_data.data(), site0_data.size()); + mps_state.updateMPSSiteData(1, site1_data.data(), site1_data.size()); + + auto results = mps_state.getDataVector(); + + std::vector> expected_state( + std::size_t{1} << num_qubits, std::complex({0.0, 0.0})); + + expected_state[3] = {1.0, 0.0}; + + CHECK(expected_state == Pennylane::Util::approx(results)); + } +} + TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", float, double) { std::vector> basisStates = { diff --git a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp index a4201f22d5..95b2299699 100644 --- a/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp +++ b/pennylane_lightning/core/src/utils/cuda_utils/tests/Test_LinearAlgebra.cpp @@ -1,4 +1,4 @@ -// Copyright 2018-2023 Xanadu Quantum Technologies Inc. +// Copyright 2018-2024 Xanadu Quantum Technologies Inc. // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index fd107a5bba..226861f7ed 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -21,12 +21,52 @@ except ImportError: pass +from itertools import product import numpy as np import pennylane as qml from pennylane import BasisState, DeviceError, StatePrep from pennylane.ops.op_math import Adjoint from pennylane.tape import QuantumScript +from pennylane.wires import Wires + + +def svd_split(M, bond_dim): + """SVD split a matrix into a matrix product state via numpy linalg. Note that this function is to be moved to the C++ layer.""" + U, S, Vd = np.linalg.svd(M, full_matrices=False) + U = U @ np.diag(S) # Append singular values to U + bonds = len(S) + Vd = Vd.reshape(bonds, 2, -1) + U = U.reshape((-1, 2, bonds)) + + # keep only chi bonds + chi = np.min([bonds, bond_dim]) + U, S, Vd = U[:, :, :chi], S[:chi], Vd[:chi] + return U, Vd + + +def dense_to_mps(psi, n_wires, bond_dim): + """Convert a dense state vector to a matrix product state.""" + Ms = [[] for _ in range(n_wires)] + + psi = np.reshape(psi, (2, -1)) # split psi[2, 2, 2, 2..] = psi[2, (2x2x2...)] + U, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] Vd[mu, (2x2x2x..)] + + Ms[0] = U + bondL = Vd.shape[0] + psi = Vd + + for i in range(1, n_wires - 1): + psi = np.reshape(psi, (2 * bondL, -1)) # reshape psi[2 * bondL, (2x2x2...)] + U, Vd = svd_split(psi, bond_dim) # psi[2, (2x2x..)] = U[2, mu] Vd[mu, (2x2x2x..)] + Ms[i] = U + + psi = Vd + bondL = Vd.shape[0] + + Ms[n_wires - 1] = Vd + + return Ms # pylint: disable=too-many-instance-attributes @@ -112,6 +152,54 @@ def reset_state(self): # init the quantum state to |00..0> self._tensornet.reset() + def _preprocess_state_vector(self, state, device_wires): + """Convert a specified state to a full internal state vector. + + Args: + state (array[complex]): normalized input state of length ``2**len(device_wires)`` + device_wires (Wires): wires that get initialized in the state + + Returns: + array[complex]: normalized input state of length ``2**len(device_wires)`` + """ + output_shape = [2] * self._num_wires + # special case for integral types + if state.dtype.kind == "i": + state = np.array(state, dtype=self.dtype) + + if len(device_wires) == self._num_wires and Wires(sorted(device_wires)) == device_wires: + return np.reshape(state, output_shape).ravel(order="C") + + # generate basis states on subset of qubits via the cartesian product + basis_states = np.array(list(product([0, 1], repeat=len(device_wires)))) + + # get basis states to alter on full set of qubits + unravelled_indices = np.zeros((2 ** len(device_wires), self._num_wires), dtype=int) + unravelled_indices[:, device_wires] = basis_states + + # get indices for which the state is changed to input state vector elements + ravelled_indices = np.ravel_multi_index(unravelled_indices.T, [2] * self._num_wires) + + # get full state vector to be factorized into MPS + full_state = np.zeros(2**self._num_wires, dtype=self.dtype) + for i, value in enumerate(state): + full_state[ravelled_indices[i]] = value + return np.reshape(full_state, output_shape).ravel(order="C") + + def _apply_state_vector(self, state, device_wires: Wires): + """Convert a specified state to MPS sites. + Args: + state (array[complex]): normalized input state of length ``2**len(device_wires)`` + or broadcasted state of shape ``(batch_size, 2**len(device_wires))`` + device_wires (Wires): wires that get initialized in the state + """ + + state = self._preprocess_state_vector(state, device_wires) + + M = dense_to_mps(state, self._num_wires, self._max_bond_dim) + + self._tensornet.updateMPSSitesData(M) + def _apply_basis_state(self, state, wires): """Initialize the quantum state in a specified computational basis state. @@ -177,10 +265,9 @@ def apply_operations(self, operations): # State preparation is currently done in Python if operations: # make sure operations[0] exists if isinstance(operations[0], StatePrep): - raise DeviceError( - "lightning.tensor does not support initialization with a state vector." - ) - if isinstance(operations[0], BasisState): + self._apply_state_vector(operations[0].parameters[0].copy(), operations[0].wires) + operations = operations[1:] + elif isinstance(operations[0], BasisState): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] diff --git a/tests/lightning_tensor/test_gates_and_expval.py b/tests/lightning_tensor/test_gates_and_expval.py index 644185797b..9d2213d528 100644 --- a/tests/lightning_tensor/test_gates_and_expval.py +++ b/tests/lightning_tensor/test_gates_and_expval.py @@ -184,28 +184,6 @@ def circuit(params): assert np.allclose(j_ltensor, j_default, rtol=1e-6) -@pytest.mark.parametrize("theta, phi", list(zip(THETA, PHI))) -def test_state_prep_not_support(qubit_device, theta, phi): - """Test that state preparation is not supported on the device.""" - dev = qubit_device(wires=3) - obs = qml.Hermitian([[1, 0], [0, -1]], wires=[0]) - - tape = qml.tape.QuantumScript( - [ - qml.StatePrep([1.0, 0, 0, 0, 0, 0, 0, 0], wires=[0, 1, 2]), - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(theta + phi, wires=[2]), - ], - measurements=[qml.expval(obs)], - ) - - with pytest.raises( - DeviceError, match="lightning.tensor does not support initialization with a state vector." - ): - dev.execute(tape) - - class TestSparseHExpval: """Test sparseH expectation values""" diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index 845c1ef991..a2c8d74a43 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -63,31 +63,3 @@ def test_errors_basis_state(): with pytest.raises(ValueError, match="State must be of length 1;"): tensornet = LightningTensorNet(3, 5) tensornet.apply_operations([qml.BasisState(np.array([0, 1]), wires=[0])]) - - -@pytest.mark.parametrize( - "operation,par", - [ - (qml.StatePrep, [0, 0, 1, 0]), - (qml.StatePrep, [0, 0, 0, 1]), - ( - qml.StatePrep, - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ( - qml.StatePrep, - [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ], -) -def test_errors_apply_operation_state_preparation(operation, par): - """Test that errors are raised when applying a StatePreparation operation.""" - wires = 2 - bondDims = 5 - tensornet = LightningTensorNet(wires, bondDims) - - with pytest.raises( - qml.DeviceError, - match="lightning.tensor does not support initialization with a state vector.", - ): - tensornet.apply_operations([operation(np.array(par), Wires(range(wires)))]) diff --git a/tests/new_api/test_device.py b/tests/new_api/test_device.py index e13893f49a..623bc6c793 100644 --- a/tests/new_api/test_device.py +++ b/tests/new_api/test_device.py @@ -336,15 +336,14 @@ def test_preprocess(self, adjoint): (qml.BasisState([1, 1], wires=[0, 1]), False), (qml.BasisState(qml.numpy.array([1, 1]), wires=[0, 1]), True), ] - if device_name != "lightning.tensor" - else [ - (qml.BasisState([1, 1], wires=[0, 1]), False), - ] ), ) def test_preprocess_state_prep_first_op_decomposition(self, op, is_trainable): """Test that state prep ops in the beginning of a tape are decomposed with adjoint but not otherwise.""" + if device_name == "lightning.tensor" and is_trainable: + pytest.skip("StatePrep trainable not supported in lightning.tensor") + tape = qml.tape.QuantumScript([op, qml.RX(1.23, wires=0)], [qml.expval(qml.PauliZ(0))]) device = LightningDevice(wires=3) diff --git a/tests/test_apply.py b/tests/test_apply.py index 13b8bcd93c..8c06a25af4 100644 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -202,11 +202,6 @@ def test_apply_operation_preserve_pointer_three_wires_no_parameters( [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], ), ] - if device_name != "lightning.tensor" - else [ - (qml.BasisState, [0, 0, 1, 0], [1, 0]), - (qml.BasisState, [0, 0, 0, 1], [1, 1]), - ] ), ) def test_apply_operation_state_preparation( @@ -843,11 +838,6 @@ def circuit(): assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) - # This test is ran against the state |Phi+> with two Z expvals - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.Stateprep()", - ) @pytest.mark.parametrize( "name,expected_output", [ @@ -906,33 +896,9 @@ def circuit(): ("BasisState", [0, 0], [1, 1]), ("BasisState", [1, 0], [-1, 1]), ("BasisState", [0, 1], [1, -1]), - pytest.param( - "QubitStateVector", - [1, 0, 0, 0], - [1, 1], - marks=pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ), - ), - pytest.param( - "QubitStateVector", - [0, 0, 1, 0], - [-1, 1], - marks=pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ), - ), - pytest.param( - "QubitStateVector", - [0, 1, 0, 0], - [1, -1], - marks=pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ), - ), + ("QubitStateVector", [1, 0, 0, 0], [1, 1]), + ("QubitStateVector", [0, 0, 1, 0], [-1, 1]), + ("QubitStateVector", [0, 1, 0, 0], [1, -1]), ], ) def test_supported_state_preparation(self, qubit_device, tol, name, par, expected_output): @@ -1021,10 +987,6 @@ def circuit(): assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) # This test is run with three expvals - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector()", - ) @pytest.mark.parametrize( "name,par,wires,expected_output", [ @@ -1099,10 +1061,6 @@ def circuit(): assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) # This test is ran against the state 1/2|00>+sqrt(3)/2|11> with two Z expvals - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector() and qml.StatePrep()", - ) @pytest.mark.parametrize( "name,par,expected_output", [ @@ -1148,7 +1106,7 @@ def circuit(): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector() and qml.StatePrep()", + reason="lightning.tensor does not support a single wire device", ) @pytest.mark.parametrize( "name,state,expected_output", @@ -1187,7 +1145,7 @@ def circuit(): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor does not support qml.QubitStateVector() and qml.StatePrep()", + reason="lightning.tensor does not support single wire devices", ) @pytest.mark.parametrize( "name,state,expected_output,par", @@ -1417,10 +1375,6 @@ def compute_matrix(*params, **hyperparams): with pytest.raises(ValueError, match="Unsupported operation"): dev.apply_lightning([EmptyGate(0)]) - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support StatePrep", - ) @pytest.mark.parametrize( "ops0", [ @@ -1486,11 +1440,7 @@ def test_circuit_with_stateprep(op, theta, phi, tol): init_state /= np.linalg.norm(init_state) def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0, 0, 0, 0, 0], wires=[0, 1, 2, 3, 4]) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.CNOT(wires=[0, 1]) diff --git a/tests/test_comparison.py b/tests/test_comparison.py index 4967b72bd0..2c16862ae0 100644 --- a/tests/test_comparison.py +++ b/tests/test_comparison.py @@ -269,7 +269,7 @@ def circuit(measurement): @pytest.mark.skipif( device_name == "lightning.tensor", - reason="lightning.tensor device does not support initialization with a state vector", + reason="lightning.tensor device does not support does not support the direct access to state", ) @pytest.mark.parametrize( "lightning_dev_version", [lightning_backend_dev, lightning_backend_batch_obs_dev] diff --git a/tests/test_expval.py b/tests/test_expval.py index 87c65bbb0b..b07ac4a8e2 100644 --- a/tests/test_expval.py +++ b/tests/test_expval.py @@ -144,8 +144,7 @@ def test_hermitian_expectation(self, n_wires, theta, phi, qubit_device, tol): obs = qml.Hermitian(U, wires=perm) def circuit(): - if device_name != "lightning.tensor": - qml.StatePrep(init_state, wires=range(n_qubits)) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RX(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RX(theta, wires=[2]) diff --git a/tests/test_gates.py b/tests/test_gates.py index fa120b820c..78a439bc2d 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -299,11 +299,7 @@ def test_qubit_RY(theta, phi, tol): init_state /= np.linalg.norm(init_state) def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) @@ -334,11 +330,7 @@ def test_qubit_unitary(n_wires, theta, phi, tol): for perm in perms: def circuit(): - ( - qml.StatePrep(init_state, wires=range(n_qubits)) - if device_name != "lightning.tensor" - else qml.BasisState([0] * n_qubits, wires=range(n_qubits)) - ) + qml.StatePrep(init_state, wires=range(n_qubits)) qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) qml.RY(theta, wires=[2]) diff --git a/tests/test_templates.py b/tests/test_templates.py index 3f242d7af5..0c8ff9ca82 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -109,10 +109,6 @@ def circuit(feature_vector): class TestAmplitudeEmbedding: """Test the AmplitudeEmbedding algorithm.""" - @pytest.mark.skipif( - device_name == "lightning.tensor", - reason="lightning.tensor does not support QubitStateVector.", - ) @pytest.mark.parametrize("first_op", [False, True]) @pytest.mark.parametrize("n_qubits", range(2, 10, 2)) def test_amplitudeembedding(self, first_op, n_qubits):