From bc5c4d6c511570f03c33365a2d619b497aa52b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Fri, 18 Oct 2024 21:04:14 +0000 Subject: [PATCH 01/30] prototype for MPSStatePrep --- MPS_explore/MPS_StatePrep_aux.py | 161 ++++++++++++++++++ .../lightning_qubit/lightning_qubit.py | 7 + .../lightning_tensor/_tensornet.py | 69 +++++++- .../lightning_tensor/lightning_tensor.py | 19 ++- 4 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 MPS_explore/MPS_StatePrep_aux.py diff --git a/MPS_explore/MPS_StatePrep_aux.py b/MPS_explore/MPS_StatePrep_aux.py new file mode 100644 index 0000000000..04d3cd5c36 --- /dev/null +++ b/MPS_explore/MPS_StatePrep_aux.py @@ -0,0 +1,161 @@ +import numpy as np +import pennylane as qml + + + +# Function to define the bond dim for MPS on base to the number of qubits. +def setBondDims(numQubits, maxBondDim): + + log_maxBondDim = np.log2(maxBondDim) + localBondDims = np.ones(numQubits -1) * maxBondDim + + for i, val in enumerate(localBondDims): + bondDim = min(i+1, numQubits - i - 1) + if bondDim <= log_maxBondDim: + localBondDims[i] = 2**bondDim + + return localBondDims + +def setSitesModes(numQubits): + localSitesModes = [] + + for i in range(numQubits): + if i == 0: + localSite = [i, i+numQubits, -1] + elif i == numQubits - 1: + localSite = [i+numQubits-1, i, -1] + else: + localSite = [i + numQubits - 1, i , i + numQubits] + + localSitesModes.append(localSite) + + localSitesModes = np.array(localSitesModes) + + return localSitesModes + +def setSitesExtents(numQubits, bondDims): + qubitDims = np.ones(numQubits,dtype=int) * 2 + localSiteExtents = [] + for i in range(numQubits): + if i == 0: + localSite = [qubitDims[i], bondDims[i], -1] + elif i == numQubits - 1: + localSite = [bondDims[i-1], qubitDims[i], -1] + else: + localSite = [bondDims[i-1], qubitDims[i], bondDims[i]] + + localSiteExtents.append(localSite) + + localSiteExtents = np.array(localSiteExtents).astype(int) + + return localSiteExtents + +# Function to print all the array for set the MPS bond dim. +def build_MPS(numQubits, maxBondDim): + print('Conditions') + print('NumQubit:', numQubits, '| MaxBondDim:',maxBondDim) + + + print('Function setBondDims') + bondDims = setBondDims(numQubits, maxBondDim) + + print('len:', bondDims.shape) + print(bondDims.astype(int)) + + print('-'*100) + + print('Function setSitesModes') + sitesModes = setSitesModes(numQubits) + + print('shape',sitesModes.shape) + print(sitesModes.T) + + print('-'*100) + + print('Function setSiteExtends') + siteExtents = setSitesExtents(numQubits, bondDims) + + print("Sites Extents") + print('shape',siteExtents.shape) + print(siteExtents.T) + + print('-'*100) + +# ----------------------------------------------------------------------------------------- +# ----------------------------------------------------------------------------------------- +# Create a random MPS with the correct dimensions +def create_custom_MPS(numQubits): + + maxBondDim = 128 + + bondDims = setBondDims(numQubits, maxBondDim) + sitesExtents = setSitesExtents(numQubits, bondDims) + + MPS_example = [] + + for T_shape in sitesExtents: + + if T_shape[-1] == -1: + T_shape = T_shape[:-1] + + MPS_site = np.random.rand(*(tuple(T_shape))) + + MPS_example.append(MPS_site) + + return MPS_example + +# Dummy circuit +def LTensor_circuit(wires, custom_MPS): + + # It is necessary to create an fake state to avoid complete from the preprocess + state_one = np.zeros(2**(wires-1), dtype=float) + state_one = state_one + state_one * 0j + state_one[0] = 1.0 + 0j + + dev = qml.device("lightning.tensor", + wires=wires, + cutoff=1e-7, + max_bond_dim=128, + # Extra argument for LTensor to pass the MPS + # If custom_MPS is [] or None then compute the normal StatePrep + custom_MPS=custom_MPS # MPS sites + ) + + dev_wires = dev.wires.tolist() + + @qml.qnode(dev) + def circuit(set_state=state_one): + + qml.StatePrep(set_state, wires=dev_wires[1:]) + + return qml.state() + + result = circuit() + + # print(f"Circuit result: \n{result}") + +if __name__ == '__main__': + + wires = 9 + maxBondDim = 128 + + build_MPS(wires, maxBondDim) + + # ---------------------------------------------------------------------- + print('-'*100) + print("Lightning Tensor Base") + + LTensor_circuit(wires,[]) # Empty custom_MPS + + # ---------------------------------------------------------------------- + print('-'*100) + print("Lightning Tensor Custom MPS") + + print('Custom MPS shape') + MPS_example = create_custom_MPS(wires) + [print(f'{site.shape}') for site in MPS_example] + + LTensor_circuit(wires, MPS_example) # Passing a custom_MPS + + + \ No newline at end of file diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index abf0809787..45453ba991 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -474,6 +474,13 @@ def execute( for circuit in circuits: if self._wire_map is not None: [circuit], _ = qml.map_wires(circuit, self._wire_map) + + # Tmp function to get the amount of gates + gates = {} + for i, ops in enumerate(circuit.__dict__['_ops']): + gates[ops._name] = gates.get(ops._name, 0) + 1 + print('FDX:', gates) + results.append( self.simulate( circuit, diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 967c0fbb17..7c0dde1f27 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -21,6 +21,8 @@ except ImportError: pass +from typing import List + import numpy as np import pennylane as qml from pennylane import BasisState, DeviceError, StatePrep @@ -117,6 +119,47 @@ def gate_matrix_decompose(gate_ops_matrix, wires, max_mpo_bond_dim, c_dtype): return mpos, sorted_wires +def setBondDims(num_qubits, max_bond_dim): + + log_max_bond_dim = np.log2(max_bond_dim) + localBondDims = [0 for _ in range(num_qubits-1)] + + for i in range(len(localBondDims)): + bondDim = min(i+1, num_qubits - i - 1) + if bondDim <= log_max_bond_dim: + localBondDims[i] = 2**bondDim + + return localBondDims + +def setSitesExtents(num_qubits, max_bond_dim): + + bondDims = setBondDims(num_qubits, max_bond_dim) + qubitDims = [2 for _ in range(num_qubits)] + + localSiteExtents = [] + for i in range(num_qubits): + if i == 0: + localSite = [qubitDims[i], bondDims[i]] + elif i == num_qubits - 1: + localSite = [bondDims[i-1], qubitDims[i]] + else: + localSite = [bondDims[i-1], qubitDims[i], bondDims[i]] + + localSiteExtents.append(localSite) + + return localSiteExtents + +def custom_MPS_checks(MPS, num_wires, max_bond_dim): + + MPS_shape_dest = setSitesExtents(num_wires, max_bond_dim) + + MPS_shape_source = [list(site.shape) for site in MPS] + + same_shape = [s == d for s, d in zip(MPS_shape_source, MPS_shape_dest)] + + if not all(same_shape): + raise ValueError(f"The custom MPS does not have the correct layout for lightning.tensor.\n MPS source shape {MPS_shape_source}\n MPS destiny shape {MPS_shape_dest}") + # pylint: disable=too-many-instance-attributes class LightningTensorNet: @@ -144,6 +187,7 @@ def __init__( max_bond_dim: int = 128, cutoff: float = 0, cutoff_mode: str = "abs", + custom_MPS: List = [], device_name="lightning.tensor", ): self._num_wires = num_wires @@ -152,6 +196,8 @@ def __init__( self._cutoff = cutoff self._cutoff_mode = cutoff_mode self._c_dtype = c_dtype + + self._custom_MPS = custom_MPS if device_name != "lightning.tensor": raise DeviceError(f'The device name "{device_name}" is not a valid option.') @@ -271,11 +317,24 @@ def _apply_state_vector(self, state, device_wires: Wires): device_wires (Wires): wires that get initialized in the state """ - state = self._preprocess_state_vector(state, device_wires) - mps_site_shape = [2] - M = decompose_dense(state, self._num_wires, mps_site_shape, self._max_bond_dim) - - self._tensornet.updateMPSSitesData(M) + if self._custom_MPS == []: + print("Create MPS site from state") + + state = self._preprocess_state_vector(state, device_wires) + mps_site_shape = [2] + M = decompose_dense(state, self._num_wires, mps_site_shape, self._max_bond_dim) + + # print('Lightning.Tensor MPS shape') + # [print(i.shape) for i in M] + + self._tensornet.updateMPSSitesData(M) + else: + # Custom MPS. + print("Pass MPS site at run time") + # Checking for the MPS shape. + + custom_MPS_checks(self._custom_MPS, self._num_wires, self._max_bond_dim) + self._tensornet.updateMPSSitesData(self._custom_MPS) def _apply_basis_state(self, state, wires): """Initialize the quantum state in a specified computational basis state. diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index d70f1d3c69..41110e4de8 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -19,6 +19,9 @@ from numbers import Number from typing import Callable, Optional, Sequence, Tuple, Union from warnings import warn +from ctypes.util import find_library +from importlib import util as imp_util + import numpy as np import pennylane as qml @@ -263,7 +266,7 @@ def circuit(num_qubits): # pylint: disable=too-many-instance-attributes # So far we just consider the options for MPS simulator - _device_options = ("backend", "max_bond_dim", "cutoff", "cutoff_mode") + _device_options = ("backend", "max_bond_dim", "cutoff", "cutoff_mode", "custom_MPS") _CPP_BINARY_AVAILABLE = LT_CPP_BINARY_AVAILABLE _new_API = True @@ -287,6 +290,11 @@ def __init__( if not self._CPP_BINARY_AVAILABLE: raise ImportError("Pre-compiled binaries for lightning.tensor are not available. ") + if find_library("cutensornet") is None and not imp_util.find_spec("cuquantum"): + + raise ImportError( + "cuStateVec libraries not found. Please pip install the appropriate cuStateVec library in a virtual environment.") + if not accepted_methods(method): raise ValueError(f"Unsupported method: {method}") @@ -311,6 +319,8 @@ def __init__( self._cutoff = kwargs.get("cutoff", 0) self._cutoff_mode = kwargs.get("cutoff_mode", "abs") self._backend = kwargs.get("backend", "cutensornet") + + self._custom_MPS = kwargs.get("custom_MPS",[]) for arg in kwargs: if arg not in self._device_options: @@ -361,6 +371,7 @@ def _tensornet(self): self._max_bond_dim, self._cutoff, self._cutoff_mode, + self._custom_MPS, ) dtype = c_dtype @@ -440,6 +451,12 @@ def execute( for circuit in circuits: if self._wire_map is not None: [circuit], _ = qml.map_wires(circuit, self._wire_map) + # Tmp function to print the number of gates + gates = {} + for i, ops in enumerate(circuit.__dict__['_ops']): + gates[ops._name] = gates.get(ops._name, 0) + 1 + total_gates = sum([gates[i] for i in gates]) + print('Execute Gates:', gates, "Total:",total_gates) results.append(simulate(circuit, self._tensornet())) return tuple(results) From e02a9435fd5d11b5fdf619c23462ea630f3dfe2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Wed, 23 Oct 2024 20:45:46 +0000 Subject: [PATCH 02/30] MPSPrep added --- MPS_explore/MPS_StatePrep_aux.py | 32 +++++++++++++------ .../lightning_tensor/_tensornet.py | 27 +++++++++++++++- .../lightning_tensor/lightning_tensor.py | 4 +++ 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/MPS_explore/MPS_StatePrep_aux.py b/MPS_explore/MPS_StatePrep_aux.py index 04d3cd5c36..9336e7f06e 100644 --- a/MPS_explore/MPS_StatePrep_aux.py +++ b/MPS_explore/MPS_StatePrep_aux.py @@ -112,15 +112,8 @@ def LTensor_circuit(wires, custom_MPS): state_one = state_one + state_one * 0j state_one[0] = 1.0 + 0j - dev = qml.device("lightning.tensor", - wires=wires, - cutoff=1e-7, - max_bond_dim=128, - # Extra argument for LTensor to pass the MPS - # If custom_MPS is [] or None then compute the normal StatePrep - custom_MPS=custom_MPS # MPS sites - ) - + dev = qml.device("lightning.tensor", wires=wires, cutoff=1e-7, max_bond_dim=128) + dev_wires = dev.wires.tolist() @qml.qnode(dev) @@ -134,6 +127,25 @@ def circuit(set_state=state_one): # print(f"Circuit result: \n{result}") +# Dummy circuit +def LTensor_circuit_MPS(wires, custom_MPS): + + dev = qml.device("lightning.tensor", wires=wires, cutoff=1e-7, max_bond_dim=128) + + dev_wires = dev.wires.tolist() + + @qml.qnode(dev) + def circuit(custom_MPS=custom_MPS): + + qml.MPSPrep(custom_MPS, wires=dev_wires[1:]) + + return qml.state() + + result = circuit() + + # print(f"Circuit result: \n{result}") + + if __name__ == '__main__': wires = 9 @@ -155,7 +167,7 @@ def circuit(set_state=state_one): MPS_example = create_custom_MPS(wires) [print(f'{site.shape}') for site in MPS_example] - LTensor_circuit(wires, MPS_example) # Passing a custom_MPS + LTensor_circuit_MPS(wires, MPS_example) # Passing a custom_MPS \ No newline at end of file diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 7c0dde1f27..fb4180383b 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -26,6 +26,7 @@ import numpy as np import pennylane as qml from pennylane import BasisState, DeviceError, StatePrep +from pennylane.labs import MPSPrep from pennylane.ops.op_math import Adjoint from pennylane.tape import QuantumScript from pennylane.wires import Wires @@ -132,6 +133,7 @@ def setBondDims(num_qubits, max_bond_dim): return localBondDims def setSitesExtents(num_qubits, max_bond_dim): + """Compute the MPS sites dimensions on base to the number of wires.""" bondDims = setBondDims(num_qubits, max_bond_dim) qubitDims = [2 for _ in range(num_qubits)] @@ -149,7 +151,8 @@ def setSitesExtents(num_qubits, max_bond_dim): return localSiteExtents -def custom_MPS_checks(MPS, num_wires, max_bond_dim): +def custom_MPS_checks(MPS: List, num_wires: int, max_bond_dim: int): + """Check if the provided MPS has the correct dimension for C++ backend.""" MPS_shape_dest = setSitesExtents(num_wires, max_bond_dim) @@ -357,6 +360,24 @@ def _apply_basis_state(self, state, wires): raise ValueError("BasisState parameter and wires must be of equal length.") self._tensornet.setBasisState(state) + + def _load_mps_state(self, state: List, wires: List): + """Prepares an initial state using MPS. + + Args: + state (List): A list of different numpy array with the MPS sites values. The structure should be as follows: + [ (2, 2), (2, 2, 4), (4, 2, 8), ..., + (8, 2, 4), (4, 2, 2), (2, 2) ] + wires (List): wires that the provided computational state should be + initialized on. + + Note: The correct MPS sites format and layout are user responsible. + """ + mps = state.data + custom_MPS_checks(mps, self._num_wires, self._max_bond_dim) + self._tensornet.updateMPSSitesData(mps) + + def _apply_MPO(self, gate_matrix, wires): """Apply a matrix product operator to the quantum state. @@ -468,6 +489,10 @@ def apply_operations(self, operations): elif isinstance(operations[0], BasisState): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] + elif isinstance(operations[0], MPSPrep): + self._load_mps_state(operations[0].parameters[0], operations[0].wires) + operations = operations[1:] + self._apply_lightning(operations) diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 41110e4de8..e83b405abf 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -74,6 +74,7 @@ { "Identity", "BasisState", + "MPSPrep", "QubitUnitary", "ControlledQubitUnitary", "DiagonalQubitUnitary", @@ -173,6 +174,9 @@ def stopping_condition(op: Operator) -> bool: if isinstance(op, qml.ControlledQubitUnitary): return True + if isinstance(op, qml.labs.MPSPrep): + return True + return op.has_matrix and op.name in _operations From c1022793b487aae90aef00691a59b733efee6a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Wed, 6 Nov 2024 19:57:18 +0000 Subject: [PATCH 03/30] remove shortcut MPSstate --- .../lightning_tensor/_tensornet.py | 26 ++++--------------- .../lightning_tensor/lightning_tensor.py | 3 --- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index fb4180383b..5984dc3cb5 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -190,7 +190,6 @@ def __init__( max_bond_dim: int = 128, cutoff: float = 0, cutoff_mode: str = "abs", - custom_MPS: List = [], device_name="lightning.tensor", ): self._num_wires = num_wires @@ -199,8 +198,6 @@ def __init__( self._cutoff = cutoff self._cutoff_mode = cutoff_mode self._c_dtype = c_dtype - - self._custom_MPS = custom_MPS if device_name != "lightning.tensor": raise DeviceError(f'The device name "{device_name}" is not a valid option.') @@ -320,24 +317,11 @@ def _apply_state_vector(self, state, device_wires: Wires): device_wires (Wires): wires that get initialized in the state """ - if self._custom_MPS == []: - print("Create MPS site from state") - - state = self._preprocess_state_vector(state, device_wires) - mps_site_shape = [2] - M = decompose_dense(state, self._num_wires, mps_site_shape, self._max_bond_dim) - - # print('Lightning.Tensor MPS shape') - # [print(i.shape) for i in M] - - self._tensornet.updateMPSSitesData(M) - else: - # Custom MPS. - print("Pass MPS site at run time") - # Checking for the MPS shape. - - custom_MPS_checks(self._custom_MPS, self._num_wires, self._max_bond_dim) - self._tensornet.updateMPSSitesData(self._custom_MPS) + state = self._preprocess_state_vector(state, device_wires) + mps_site_shape = [2] + M = decompose_dense(state, self._num_wires, mps_site_shape, 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. diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index e83b405abf..951142927e 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -323,8 +323,6 @@ def __init__( self._cutoff = kwargs.get("cutoff", 0) self._cutoff_mode = kwargs.get("cutoff_mode", "abs") self._backend = kwargs.get("backend", "cutensornet") - - self._custom_MPS = kwargs.get("custom_MPS",[]) for arg in kwargs: if arg not in self._device_options: @@ -375,7 +373,6 @@ def _tensornet(self): self._max_bond_dim, self._cutoff, self._cutoff_mode, - self._custom_MPS, ) dtype = c_dtype From e9a0a4ed50830ff16fbc48b17f9b3d45baf2169d Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 6 Nov 2024 20:04:41 +0000 Subject: [PATCH 04/30] Auto update version from '0.40.0-dev0' to '0.40.0-dev1' --- 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 5a87bcbfbf..43d5778572 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.40.0-dev0" +__version__ = "0.40.0-dev1" From 92689dcc1c9dc868199b683c40e0f61aa3223831 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Fri, 29 Nov 2024 23:11:13 +0000 Subject: [PATCH 05/30] Auto update version from '0.40.0-dev23' to '0.40.0-dev24' --- 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 4830359ac4..17c98c7d19 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.40.0-dev23" +__version__ = "0.40.0-dev24" From f0779dd1f87bb87e0a4781b6d89af2a1c9c6e19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Fri, 29 Nov 2024 23:14:12 +0000 Subject: [PATCH 06/30] upoate and solve issue with truncated mps --- MPS_explore/MPS_StatePrep_aux.py | 27 +++++++++---------- .../lightning_tensor/tncuda/MPSTNCuda.hpp | 6 +++++ .../lightning_tensor/_tensornet.py | 11 ++++---- .../lightning_tensor/lightning_tensor.py | 12 ++++----- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/MPS_explore/MPS_StatePrep_aux.py b/MPS_explore/MPS_StatePrep_aux.py index 9336e7f06e..f725e1e765 100644 --- a/MPS_explore/MPS_StatePrep_aux.py +++ b/MPS_explore/MPS_StatePrep_aux.py @@ -7,7 +7,8 @@ def setBondDims(numQubits, maxBondDim): log_maxBondDim = np.log2(maxBondDim) - localBondDims = np.ones(numQubits -1) * maxBondDim + limit_dimension = 2 ** int(log_maxBondDim) + localBondDims = np.ones(numQubits -1) * limit_dimension for i, val in enumerate(localBondDims): bondDim = min(i+1, numQubits - i - 1) @@ -84,9 +85,7 @@ def build_MPS(numQubits, maxBondDim): # ----------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------- # Create a random MPS with the correct dimensions -def create_custom_MPS(numQubits): - - maxBondDim = 128 +def create_custom_MPS(numQubits,maxBondDim): bondDims = setBondDims(numQubits, maxBondDim) sitesExtents = setSitesExtents(numQubits, bondDims) @@ -128,16 +127,16 @@ def circuit(set_state=state_one): # print(f"Circuit result: \n{result}") # Dummy circuit -def LTensor_circuit_MPS(wires, custom_MPS): +def LTensor_circuit_MPS(wires, custom_MPS, max_bond_dim): - dev = qml.device("lightning.tensor", wires=wires, cutoff=1e-7, max_bond_dim=128) + dev = qml.device("lightning.tensor", wires=wires, cutoff=1e-7, max_bond_dim=max_bond_dim) dev_wires = dev.wires.tolist() @qml.qnode(dev) def circuit(custom_MPS=custom_MPS): - qml.MPSPrep(custom_MPS, wires=dev_wires[1:]) + qml.MPSPrep(mps=custom_MPS, wires=dev_wires[1:]) return qml.state() @@ -148,26 +147,26 @@ def circuit(custom_MPS=custom_MPS): if __name__ == '__main__': - wires = 9 - maxBondDim = 128 + wires = 13 + maxBondDim = 16 build_MPS(wires, maxBondDim) # ---------------------------------------------------------------------- - print('-'*100) - print("Lightning Tensor Base") + # print('-'*100) + # print("Lightning Tensor Base") - LTensor_circuit(wires,[]) # Empty custom_MPS + # LTensor_circuit(wires,[]) # Empty custom_MPS # ---------------------------------------------------------------------- print('-'*100) print("Lightning Tensor Custom MPS") print('Custom MPS shape') - MPS_example = create_custom_MPS(wires) + MPS_example = create_custom_MPS(wires, maxBondDim) [print(f'{site.shape}') for site in MPS_example] - LTensor_circuit_MPS(wires, MPS_example) # Passing a custom_MPS + LTensor_circuit_MPS(wires, MPS_example, maxBondDim) # Passing a custom_MPS \ No newline at end of file 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 dd37b3c994..f47593b8c1 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -38,6 +38,8 @@ #include "tncudaError.hpp" #include "tncuda_helpers.hpp" +#include + /// @cond DEV namespace { namespace cuUtil = Pennylane::LightningGPU::Util; @@ -191,6 +193,10 @@ class MPSTNCuda final : public TNCudaBase> { host_data_size == tensors_[idx].getDataBuffer().getLength(), "The length of the host data should match its copy on the device."); + std::cout << "C++ Debug: MPS site: " << idx; + std::cout << " values (dimL * dimC * dimR) PL source = " << tensors_[idx].getDataBuffer().getLength(); + std::cout << "cuQuantum dest = " << host_data_size << std::endl; + tensors_[idx].getDataBuffer().zeroInit(); tensors_[idx].getDataBuffer().CopyHostDataToGpu(host_data, diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 5984dc3cb5..0512ee50b1 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -26,7 +26,7 @@ import numpy as np import pennylane as qml from pennylane import BasisState, DeviceError, StatePrep -from pennylane.labs import MPSPrep +from pennylane import MPSPrep from pennylane.ops.op_math import Adjoint from pennylane.tape import QuantumScript from pennylane.wires import Wires @@ -123,7 +123,8 @@ def gate_matrix_decompose(gate_ops_matrix, wires, max_mpo_bond_dim, c_dtype): def setBondDims(num_qubits, max_bond_dim): log_max_bond_dim = np.log2(max_bond_dim) - localBondDims = [0 for _ in range(num_qubits-1)] + limit_dimension = 2 ** int(log_max_bond_dim) + localBondDims = [limit_dimension for _ in range(num_qubits-1)] for i in range(len(localBondDims)): bondDim = min(i+1, num_qubits - i - 1) @@ -161,7 +162,7 @@ def custom_MPS_checks(MPS: List, num_wires: int, max_bond_dim: int): same_shape = [s == d for s, d in zip(MPS_shape_source, MPS_shape_dest)] if not all(same_shape): - raise ValueError(f"The custom MPS does not have the correct layout for lightning.tensor.\n MPS source shape {MPS_shape_source}\n MPS destiny shape {MPS_shape_dest}") + raise ValueError(f"The custom MPS does not have the correct layout for lightning.tensor.\n MPS source shape {MPS_shape_source}\n MPS destination shape {MPS_shape_dest}") # pylint: disable=too-many-instance-attributes @@ -357,7 +358,7 @@ def _load_mps_state(self, state: List, wires: List): Note: The correct MPS sites format and layout are user responsible. """ - mps = state.data + mps = state.mps custom_MPS_checks(mps, self._num_wires, self._max_bond_dim) self._tensornet.updateMPSSitesData(mps) @@ -474,7 +475,7 @@ def apply_operations(self, operations): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] elif isinstance(operations[0], MPSPrep): - self._load_mps_state(operations[0].parameters[0], operations[0].wires) + self._load_mps_state(operations[0], operations[0].wires) operations = operations[1:] diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index 1f0dd02827..ae325ca5a2 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -173,7 +173,7 @@ def stopping_condition(op: Operator) -> bool: if isinstance(op, qml.ControlledQubitUnitary): return True - if isinstance(op, qml.labs.MPSPrep): + if isinstance(op, qml.MPSPrep): return True return op.has_matrix and op.name in _operations @@ -452,11 +452,11 @@ def execute( if self._wire_map is not None: [circuit], _ = qml.map_wires(circuit, self._wire_map) # Tmp function to print the number of gates - gates = {} - for i, ops in enumerate(circuit.__dict__['_ops']): - gates[ops._name] = gates.get(ops._name, 0) + 1 - total_gates = sum([gates[i] for i in gates]) - print('Execute Gates:', gates, "Total:",total_gates) + # gates = {} + # for i, ops in enumerate(circuit.__dict__['_ops']): + # gates[ops._name] = gates.get(ops._name, 0) + 1 + # total_gates = sum([gates[i] for i in gates]) + # print('Execute Gates:', gates, "Total:",total_gates) results.append(simulate(circuit, self._tensornet())) return tuple(results) From a51aeb6f1456ce3ae06712c426086c43c921bc10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Fri, 29 Nov 2024 23:27:14 +0000 Subject: [PATCH 07/30] change debug print --- .../src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 f47593b8c1..8a82aee172 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -189,14 +189,15 @@ class MPSTNCuda final : public TNCudaBase> { "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."); - std::cout << "C++ Debug: MPS site: " << idx; + std::cout << "C++ Debug: MPS site: " << idx; std::cout << " values (dimL * dimC * dimR) PL source = " << tensors_[idx].getDataBuffer().getLength(); std::cout << "cuQuantum dest = " << host_data_size << std::endl; + 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, From e61f495f9df18b4e8bfdbebc93be9c6d4e4b6652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Sat, 7 Dec 2024 23:38:17 +0000 Subject: [PATCH 08/30] adding testing --- MPS_explore/MPS_StatePrep_aux.py | 172 ------------------ .../lightning_tensor/tncuda/MPSTNCuda.hpp | 2 - .../lightning_qubit/lightning_qubit.py | 7 - .../lightning_tensor/_tensornet.py | 19 +- .../lightning_tensor/lightning_tensor.py | 16 +- .../lightning_tensor/test_tensornet_class.py | 56 ++++++ 6 files changed, 67 insertions(+), 205 deletions(-) delete mode 100644 MPS_explore/MPS_StatePrep_aux.py diff --git a/MPS_explore/MPS_StatePrep_aux.py b/MPS_explore/MPS_StatePrep_aux.py deleted file mode 100644 index f725e1e765..0000000000 --- a/MPS_explore/MPS_StatePrep_aux.py +++ /dev/null @@ -1,172 +0,0 @@ -import numpy as np -import pennylane as qml - - - -# Function to define the bond dim for MPS on base to the number of qubits. -def setBondDims(numQubits, maxBondDim): - - log_maxBondDim = np.log2(maxBondDim) - limit_dimension = 2 ** int(log_maxBondDim) - localBondDims = np.ones(numQubits -1) * limit_dimension - - for i, val in enumerate(localBondDims): - bondDim = min(i+1, numQubits - i - 1) - if bondDim <= log_maxBondDim: - localBondDims[i] = 2**bondDim - - return localBondDims - -def setSitesModes(numQubits): - localSitesModes = [] - - for i in range(numQubits): - if i == 0: - localSite = [i, i+numQubits, -1] - elif i == numQubits - 1: - localSite = [i+numQubits-1, i, -1] - else: - localSite = [i + numQubits - 1, i , i + numQubits] - - localSitesModes.append(localSite) - - localSitesModes = np.array(localSitesModes) - - return localSitesModes - -def setSitesExtents(numQubits, bondDims): - qubitDims = np.ones(numQubits,dtype=int) * 2 - localSiteExtents = [] - for i in range(numQubits): - if i == 0: - localSite = [qubitDims[i], bondDims[i], -1] - elif i == numQubits - 1: - localSite = [bondDims[i-1], qubitDims[i], -1] - else: - localSite = [bondDims[i-1], qubitDims[i], bondDims[i]] - - localSiteExtents.append(localSite) - - localSiteExtents = np.array(localSiteExtents).astype(int) - - return localSiteExtents - -# Function to print all the array for set the MPS bond dim. -def build_MPS(numQubits, maxBondDim): - print('Conditions') - print('NumQubit:', numQubits, '| MaxBondDim:',maxBondDim) - - - print('Function setBondDims') - bondDims = setBondDims(numQubits, maxBondDim) - - print('len:', bondDims.shape) - print(bondDims.astype(int)) - - print('-'*100) - - print('Function setSitesModes') - sitesModes = setSitesModes(numQubits) - - print('shape',sitesModes.shape) - print(sitesModes.T) - - print('-'*100) - - print('Function setSiteExtends') - siteExtents = setSitesExtents(numQubits, bondDims) - - print("Sites Extents") - print('shape',siteExtents.shape) - print(siteExtents.T) - - print('-'*100) - -# ----------------------------------------------------------------------------------------- -# ----------------------------------------------------------------------------------------- -# Create a random MPS with the correct dimensions -def create_custom_MPS(numQubits,maxBondDim): - - bondDims = setBondDims(numQubits, maxBondDim) - sitesExtents = setSitesExtents(numQubits, bondDims) - - MPS_example = [] - - for T_shape in sitesExtents: - - if T_shape[-1] == -1: - T_shape = T_shape[:-1] - - MPS_site = np.random.rand(*(tuple(T_shape))) - - MPS_example.append(MPS_site) - - return MPS_example - -# Dummy circuit -def LTensor_circuit(wires, custom_MPS): - - # It is necessary to create an fake state to avoid complete from the preprocess - state_one = np.zeros(2**(wires-1), dtype=float) - state_one = state_one + state_one * 0j - state_one[0] = 1.0 + 0j - - dev = qml.device("lightning.tensor", wires=wires, cutoff=1e-7, max_bond_dim=128) - - dev_wires = dev.wires.tolist() - - @qml.qnode(dev) - def circuit(set_state=state_one): - - qml.StatePrep(set_state, wires=dev_wires[1:]) - - return qml.state() - - result = circuit() - - # print(f"Circuit result: \n{result}") - -# Dummy circuit -def LTensor_circuit_MPS(wires, custom_MPS, max_bond_dim): - - dev = qml.device("lightning.tensor", wires=wires, cutoff=1e-7, max_bond_dim=max_bond_dim) - - dev_wires = dev.wires.tolist() - - @qml.qnode(dev) - def circuit(custom_MPS=custom_MPS): - - qml.MPSPrep(mps=custom_MPS, wires=dev_wires[1:]) - - return qml.state() - - result = circuit() - - # print(f"Circuit result: \n{result}") - - -if __name__ == '__main__': - - wires = 13 - maxBondDim = 16 - - build_MPS(wires, maxBondDim) - - # ---------------------------------------------------------------------- - # print('-'*100) - # print("Lightning Tensor Base") - - # LTensor_circuit(wires,[]) # Empty custom_MPS - - # ---------------------------------------------------------------------- - print('-'*100) - print("Lightning Tensor Custom MPS") - - print('Custom MPS shape') - MPS_example = create_custom_MPS(wires, maxBondDim) - [print(f'{site.shape}') for site in MPS_example] - - LTensor_circuit_MPS(wires, MPS_example, maxBondDim) # Passing a custom_MPS - - - \ No newline at end of file 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 4fe2fc3920..d2c77eeea2 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/MPSTNCuda.hpp @@ -38,8 +38,6 @@ #include "tncudaError.hpp" #include "tncuda_helpers.hpp" -#include - /// @cond DEV namespace { namespace cuUtil = Pennylane::LightningGPU::Util; diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index c9c78e757c..337309665d 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -390,13 +390,6 @@ def execute( for circuit in circuits: if self._wire_map is not None: [circuit], _ = qml.map_wires(circuit, self._wire_map) - - # Tmp function to get the amount of gates - gates = {} - for i, ops in enumerate(circuit.__dict__['_ops']): - gates[ops._name] = gates.get(ops._name, 0) + 1 - print('FDX:', gates) - results.append( self.simulate( circuit, diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 1548a63cf9..584ccbeb88 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -120,8 +120,9 @@ def gate_matrix_decompose(gate_ops_matrix, wires, max_mpo_bond_dim, c_dtype): return mpos, sorted_wires -def setBondDims(num_qubits, max_bond_dim): - +def set_bond_dims(num_qubits: int, max_bond_dim:int) -> List: + """Compute the MPS bond dimensions on base to the number of wires.""" + log_max_bond_dim = np.log2(max_bond_dim) limit_dimension = 2 ** int(log_max_bond_dim) localBondDims = [limit_dimension for _ in range(num_qubits-1)] @@ -133,10 +134,10 @@ def setBondDims(num_qubits, max_bond_dim): return localBondDims -def setSitesExtents(num_qubits, max_bond_dim): +def set_sites_extents(num_qubits:int, max_bond_dim:int) -> List: """Compute the MPS sites dimensions on base to the number of wires.""" - bondDims = setBondDims(num_qubits, max_bond_dim) + bondDims = set_bond_dims(num_qubits, max_bond_dim) qubitDims = [2 for _ in range(num_qubits)] localSiteExtents = [] @@ -152,10 +153,10 @@ def setSitesExtents(num_qubits, max_bond_dim): return localSiteExtents -def custom_MPS_checks(MPS: List, num_wires: int, max_bond_dim: int): +def MPSPrep_check(MPS: List, num_wires: int, max_bond_dim: int)->None: """Check if the provided MPS has the correct dimension for C++ backend.""" - MPS_shape_dest = setSitesExtents(num_wires, max_bond_dim) + MPS_shape_dest = set_sites_extents(num_wires, max_bond_dim) MPS_shape_source = [list(site.shape) for site in MPS] @@ -346,7 +347,7 @@ def _apply_basis_state(self, state, wires): self._tensornet.setBasisState(state) - def _load_mps_state(self, state: List, wires: List): + def _load_mps_state(self, state: List): """Prepares an initial state using MPS. Args: @@ -359,7 +360,7 @@ def _load_mps_state(self, state: List, wires: List): Note: The correct MPS sites format and layout are user responsible. """ mps = state.mps - custom_MPS_checks(mps, self._num_wires, self._max_bond_dim) + MPSPrep_check(mps, self._num_wires, self._max_bond_dim) self._tensornet.updateMPSSitesData(mps) @@ -475,7 +476,7 @@ def apply_operations(self, operations): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] elif isinstance(operations[0], MPSPrep): - self._load_mps_state(operations[0], operations[0].wires) + self._load_mps_state(operations[0]) operations = operations[1:] diff --git a/pennylane_lightning/lightning_tensor/lightning_tensor.py b/pennylane_lightning/lightning_tensor/lightning_tensor.py index ae325ca5a2..9ad7f341b8 100644 --- a/pennylane_lightning/lightning_tensor/lightning_tensor.py +++ b/pennylane_lightning/lightning_tensor/lightning_tensor.py @@ -19,9 +19,6 @@ from numbers import Number from typing import Callable, Optional, Sequence, Tuple, Union from warnings import warn -from ctypes.util import find_library -from importlib import util as imp_util - import numpy as np import pennylane as qml @@ -269,7 +266,7 @@ def circuit(num_qubits): # pylint: disable=too-many-instance-attributes # So far we just consider the options for MPS simulator - _device_options = ("backend", "max_bond_dim", "cutoff", "cutoff_mode", "custom_MPS") + _device_options = ("backend", "max_bond_dim", "cutoff", "cutoff_mode") _CPP_BINARY_AVAILABLE = LT_CPP_BINARY_AVAILABLE _new_API = True @@ -293,11 +290,6 @@ def __init__( if not self._CPP_BINARY_AVAILABLE: raise ImportError("Pre-compiled binaries for lightning.tensor are not available. ") - if find_library("cutensornet") is None and not imp_util.find_spec("cuquantum"): - - raise ImportError( - "cuStateVec libraries not found. Please pip install the appropriate cuStateVec library in a virtual environment.") - if not accepted_methods(method): raise ValueError(f"Unsupported method: {method}") @@ -451,12 +443,6 @@ def execute( for circuit in circuits: if self._wire_map is not None: [circuit], _ = qml.map_wires(circuit, self._wire_map) - # Tmp function to print the number of gates - # gates = {} - # for i, ops in enumerate(circuit.__dict__['_ops']): - # gates[ops._name] = gates.get(ops._name, 0) + 1 - # total_gates = sum([gates[i] for i in gates]) - # print('Execute Gates:', gates, "Total:",total_gates) results.append(simulate(circuit, self._tensornet())) return tuple(results) diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index 638af52e2c..7d4435d0c4 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -31,6 +31,9 @@ LightningTensorNet, decompose_dense, gate_matrix_decompose, + set_bond_dims, + set_sites_extents, + MPSPrep_check, ) if not LightningDevice._CPP_BINARY_AVAILABLE: # pylint: disable=protected-access @@ -118,3 +121,56 @@ def test_gate_matrix_decompose(): assert np.allclose(sorted_wired, sorted(wires), atol=1e-6) assert np.allclose(unitary_f, original_gate, atol=1e-6) + +@pytest.mark.parametrize("n_qubits,max_bond,expected",[ + (2,128,[2]), + (8,128,[2, 4, 8, 16, 8, 4, 2]), + (8,8,[2, 4, 8, 8, 8, 4, 2]), + (15,2,[2 for _ in range(14)]), + ]) +def test_set_bond_dims(n_qubits,max_bond,expected): + + result = set_bond_dims(n_qubits,max_bond) + + assert len(result) == len(expected) + assert all([a == b for a, b in zip(result, expected)]) + +@pytest.mark.parametrize("n_qubits,max_bond,expected",[ + (2,128,[[2, 2], [2, 2]]), + (8,128,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), + (8,8,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), + (15,2,[[2,2]] + [[2,2,2] for _ in range(13)] + [[2,2]]), + + ]) +def test_set_sites_extents(n_qubits,max_bond,expected): + + result = set_sites_extents(n_qubits,max_bond) + + assert len(result) == len(expected) + assert all([a == b for a, b in zip(result, expected)]) + +@pytest.mark.parametrize("wires,max_bond,MPS_shape",[ + (2,128,[[2, 2], [2, 2]]), + (8,128,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), + (8,8,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), + (15,2,[[2,2]] + [[2,2,2] for _ in range(13)] + [[2,2]]), + + ]) +def test_MPSPrep_check_pass(wires,max_bond,MPS_shape): + MPS = [np.zeros(i) for i in MPS_shape] + + MPSPrep_check(MPS, wires, max_bond) + +@pytest.mark.parametrize("wires,max_bond,MPS_shape",[ + (2,128,[[2, 3], [3, 2]]), # Incorrect bond dim. + (8,128,[[2, 2], [2, 4, 4], [4, 4, 8], [8, 4, 16], [16, 4, 8], [8, 4, 4], [4, 4, 2], [2, 2]]), # Incorrect physical dim. + (8,8,[[2, 2], [3, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), # Incorrect only one bond dim. + (15,2,[[2,2]] + [[2,2,2] for _ in range(14)] + [[2,2]]), # Incorrect amount of sites + + ]) +def test_MPSPrep_check_fail(wires,max_bond,MPS_shape): + MPS = [np.zeros(i) for i in MPS_shape] + + with pytest.raises(ValueError, match="The custom MPS does not have the correct layout for lightning.tensor"): + MPSPrep_check(MPS, wires, max_bond) + From d0649c5d5b826fbfc3abbad862fdc17be06f295c Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Sat, 7 Dec 2024 23:44:18 +0000 Subject: [PATCH 09/30] Auto update version from '0.40.0-dev32' to '0.40.0-dev33' --- 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 95d01d2621..1706e33407 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.40.0-dev32" +__version__ = "0.40.0-dev33" From afd63ddab04fb2f3d3c342e2675e6a422ad4e15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Sat, 7 Dec 2024 23:46:38 +0000 Subject: [PATCH 10/30] apply format --- .../lightning_tensor/_tensornet.py | 59 ++++----- .../lightning_tensor/test_tensornet_class.py | 118 +++++++++++------- 2 files changed, 104 insertions(+), 73 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 584ccbeb88..6406d49afd 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -25,8 +25,7 @@ import numpy as np import pennylane as qml -from pennylane import BasisState, DeviceError, StatePrep -from pennylane import MPSPrep +from pennylane import BasisState, DeviceError, MPSPrep, StatePrep from pennylane.ops.op_math import Adjoint from pennylane.tape import QuantumScript from pennylane.wires import Wires @@ -120,51 +119,56 @@ def gate_matrix_decompose(gate_ops_matrix, wires, max_mpo_bond_dim, c_dtype): return mpos, sorted_wires -def set_bond_dims(num_qubits: int, max_bond_dim:int) -> List: + +def set_bond_dims(num_qubits: int, max_bond_dim: int) -> List: """Compute the MPS bond dimensions on base to the number of wires.""" log_max_bond_dim = np.log2(max_bond_dim) limit_dimension = 2 ** int(log_max_bond_dim) - localBondDims = [limit_dimension for _ in range(num_qubits-1)] - + localBondDims = [limit_dimension for _ in range(num_qubits - 1)] + for i in range(len(localBondDims)): - bondDim = min(i+1, num_qubits - i - 1) + bondDim = min(i + 1, num_qubits - i - 1) if bondDim <= log_max_bond_dim: localBondDims[i] = 2**bondDim - + return localBondDims -def set_sites_extents(num_qubits:int, max_bond_dim:int) -> List: + +def set_sites_extents(num_qubits: int, max_bond_dim: int) -> List: """Compute the MPS sites dimensions on base to the number of wires.""" - - bondDims = set_bond_dims(num_qubits, max_bond_dim) + + bondDims = set_bond_dims(num_qubits, max_bond_dim) qubitDims = [2 for _ in range(num_qubits)] localSiteExtents = [] for i in range(num_qubits): - if i == 0: + if i == 0: localSite = [qubitDims[i], bondDims[i]] elif i == num_qubits - 1: - localSite = [bondDims[i-1], qubitDims[i]] + localSite = [bondDims[i - 1], qubitDims[i]] else: - localSite = [bondDims[i-1], qubitDims[i], bondDims[i]] - + localSite = [bondDims[i - 1], qubitDims[i], bondDims[i]] + localSiteExtents.append(localSite) - + return localSiteExtents -def MPSPrep_check(MPS: List, num_wires: int, max_bond_dim: int)->None: + +def MPSPrep_check(MPS: List, num_wires: int, max_bond_dim: int) -> None: """Check if the provided MPS has the correct dimension for C++ backend.""" - + MPS_shape_dest = set_sites_extents(num_wires, max_bond_dim) - + MPS_shape_source = [list(site.shape) for site in MPS] - + same_shape = [s == d for s, d in zip(MPS_shape_source, MPS_shape_dest)] - + if not all(same_shape): - raise ValueError(f"The custom MPS does not have the correct layout for lightning.tensor.\n MPS source shape {MPS_shape_source}\n MPS destination shape {MPS_shape_dest}") - + raise ValueError( + f"The custom MPS does not have the correct layout for lightning.tensor.\n MPS source shape {MPS_shape_source}\n MPS destination shape {MPS_shape_dest}" + ) + # pylint: disable=too-many-instance-attributes class LightningTensorNet: @@ -346,25 +350,23 @@ def _apply_basis_state(self, state, wires): raise ValueError("BasisState parameter and wires must be of equal length.") self._tensornet.setBasisState(state) - + def _load_mps_state(self, state: List): """Prepares an initial state using MPS. Args: state (List): A list of different numpy array with the MPS sites values. The structure should be as follows: - [ (2, 2), (2, 2, 4), (4, 2, 8), ..., + [ (2, 2), (2, 2, 4), (4, 2, 8), ..., (8, 2, 4), (4, 2, 2), (2, 2) ] wires (List): wires that the provided computational state should be initialized on. - - Note: The correct MPS sites format and layout are user responsible. + + Note: The correct MPS sites format and layout are user responsible. """ mps = state.mps MPSPrep_check(mps, self._num_wires, self._max_bond_dim) self._tensornet.updateMPSSitesData(mps) - - def _apply_MPO(self, gate_matrix, wires): """Apply a matrix product operator to the quantum state. @@ -479,7 +481,6 @@ def apply_operations(self, operations): self._load_mps_state(operations[0]) operations = operations[1:] - self._apply_lightning(operations) def set_tensor_network(self, circuit: QuantumScript): diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index 7d4435d0c4..5fb7532130 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -29,11 +29,11 @@ else: from pennylane_lightning.lightning_tensor._tensornet import ( LightningTensorNet, + MPSPrep_check, decompose_dense, gate_matrix_decompose, set_bond_dims, set_sites_extents, - MPSPrep_check, ) if not LightningDevice._CPP_BINARY_AVAILABLE: # pylint: disable=protected-access @@ -122,55 +122,85 @@ def test_gate_matrix_decompose(): assert np.allclose(sorted_wired, sorted(wires), atol=1e-6) assert np.allclose(unitary_f, original_gate, atol=1e-6) -@pytest.mark.parametrize("n_qubits,max_bond,expected",[ - (2,128,[2]), - (8,128,[2, 4, 8, 16, 8, 4, 2]), - (8,8,[2, 4, 8, 8, 8, 4, 2]), - (15,2,[2 for _ in range(14)]), - ]) -def test_set_bond_dims(n_qubits,max_bond,expected): - - result = set_bond_dims(n_qubits,max_bond) - + +@pytest.mark.parametrize( + "n_qubits,max_bond,expected", + [ + (2, 128, [2]), + (8, 128, [2, 4, 8, 16, 8, 4, 2]), + (8, 8, [2, 4, 8, 8, 8, 4, 2]), + (15, 2, [2 for _ in range(14)]), + ], +) +def test_set_bond_dims(n_qubits, max_bond, expected): + + result = set_bond_dims(n_qubits, max_bond) + assert len(result) == len(expected) assert all([a == b for a, b in zip(result, expected)]) -@pytest.mark.parametrize("n_qubits,max_bond,expected",[ - (2,128,[[2, 2], [2, 2]]), - (8,128,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), - (8,8,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), - (15,2,[[2,2]] + [[2,2,2] for _ in range(13)] + [[2,2]]), - - ]) -def test_set_sites_extents(n_qubits,max_bond,expected): - - result = set_sites_extents(n_qubits,max_bond) - + +@pytest.mark.parametrize( + "n_qubits,max_bond,expected", + [ + (2, 128, [[2, 2], [2, 2]]), + ( + 8, + 128, + [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], + ), + (8, 8, [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), + (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(13)] + [[2, 2]]), + ], +) +def test_set_sites_extents(n_qubits, max_bond, expected): + + result = set_sites_extents(n_qubits, max_bond) + assert len(result) == len(expected) assert all([a == b for a, b in zip(result, expected)]) - -@pytest.mark.parametrize("wires,max_bond,MPS_shape",[ - (2,128,[[2, 2], [2, 2]]), - (8,128,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), - (8,8,[[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), - (15,2,[[2,2]] + [[2,2,2] for _ in range(13)] + [[2,2]]), - - ]) -def test_MPSPrep_check_pass(wires,max_bond,MPS_shape): + + +@pytest.mark.parametrize( + "wires,max_bond,MPS_shape", + [ + (2, 128, [[2, 2], [2, 2]]), + ( + 8, + 128, + [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], + ), + (8, 8, [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), + (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(13)] + [[2, 2]]), + ], +) +def test_MPSPrep_check_pass(wires, max_bond, MPS_shape): MPS = [np.zeros(i) for i in MPS_shape] - + MPSPrep_check(MPS, wires, max_bond) - -@pytest.mark.parametrize("wires,max_bond,MPS_shape",[ - (2,128,[[2, 3], [3, 2]]), # Incorrect bond dim. - (8,128,[[2, 2], [2, 4, 4], [4, 4, 8], [8, 4, 16], [16, 4, 8], [8, 4, 4], [4, 4, 2], [2, 2]]), # Incorrect physical dim. - (8,8,[[2, 2], [3, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), # Incorrect only one bond dim. - (15,2,[[2,2]] + [[2,2,2] for _ in range(14)] + [[2,2]]), # Incorrect amount of sites - - ]) -def test_MPSPrep_check_fail(wires,max_bond,MPS_shape): + + +@pytest.mark.parametrize( + "wires,max_bond,MPS_shape", + [ + (2, 128, [[2, 3], [3, 2]]), # Incorrect bond dim. + ( + 8, + 128, + [[2, 2], [2, 4, 4], [4, 4, 8], [8, 4, 16], [16, 4, 8], [8, 4, 4], [4, 4, 2], [2, 2]], + ), # Incorrect physical dim. + ( + 8, + 8, + [[2, 2], [3, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], + ), # Incorrect only one bond dim. + (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(14)] + [[2, 2]]), # Incorrect amount of sites + ], +) +def test_MPSPrep_check_fail(wires, max_bond, MPS_shape): MPS = [np.zeros(i) for i in MPS_shape] - - with pytest.raises(ValueError, match="The custom MPS does not have the correct layout for lightning.tensor"): + + with pytest.raises( + ValueError, match="The custom MPS does not have the correct layout for lightning.tensor" + ): MPSPrep_check(MPS, wires, max_bond) - From 86c0fce95bedb33542293f362f0d02406c8e2fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Sat, 7 Dec 2024 23:49:59 +0000 Subject: [PATCH 11/30] trigger CIs From ccf6e40820008238a3f1a2335fcb5852f2d12a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Sat, 7 Dec 2024 23:57:05 +0000 Subject: [PATCH 12/30] fix pylint --- pennylane_lightning/lightning_tensor/_tensornet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 6406d49afd..736e6c5267 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -125,7 +125,7 @@ def set_bond_dims(num_qubits: int, max_bond_dim: int) -> List: log_max_bond_dim = np.log2(max_bond_dim) limit_dimension = 2 ** int(log_max_bond_dim) - localBondDims = [limit_dimension for _ in range(num_qubits - 1)] + localBondDims = [limit_dimension] * (num_qubits - 1) for i in range(len(localBondDims)): bondDim = min(i + 1, num_qubits - i - 1) From 93b24805f067a97d06d502cea13395985a8079b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Mon, 16 Dec 2024 20:16:37 +0000 Subject: [PATCH 13/30] move the MPS shape chacker to Cpp --- .../lightning_tensor/tncuda/TNCuda.hpp | 25 ++++++ .../tncuda/bindings/LTensorTNCudaBindings.hpp | 13 +++ .../tncuda/tests/Tests_MPSTNCuda.cpp | 48 ++++++++++ pennylane_lightning/core/src/utils/Util.hpp | 30 +++++++ .../core/src/utils/tests/Test_Util.cpp | 12 +++ .../lightning_tensor/_tensornet.py | 71 +-------------- .../lightning_tensor/test_tensornet_class.py | 88 +------------------ 7 files changed, 131 insertions(+), 156 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp index f268af0474..e8a8ce5efa 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp @@ -252,6 +252,31 @@ class TNCuda : public TNCudaBase { host_data_size); } + /** + * @brief Check if the provided MPS has the correct dimension for C++ + * backend. + * + * @param MPS_shape_source Dimension list of incoming MPS. + */ + + void MPSShapeCheck( + const std::vector> &MPS_shape_source) { + bool sameShape = sitesExtents_ == MPS_shape_source; + if (!sameShape) { + auto MPS_shape_source_str = + Pennylane::Util::vector2DToString( + MPS_shape_source); + auto MPS_shape_dest_str = + Pennylane::Util::vector2DToString(sitesExtents_); + + PL_ABORT_IF_NOT( + sitesExtents_ == MPS_shape_source, + "The incoming MPS does not have the correct layout for " + "lightning.tensor.\n Incoming MPS: " + + MPS_shape_source_str + + "\n Destination MPS: " + MPS_shape_dest_str) + } + } /** * @brief Append multiple gates to the compute graph. * NOTE: This function does not update the quantum state but only appends 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 1522305a82..ae4ae6fd66 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 @@ -137,6 +137,19 @@ void registerBackendClassSpecificBindingsMPS(PyClass &pyclass) { .def( "updateMPSSitesData", [](TensorNet &tensor_network, std::vector &tensors) { + // Extract the incoming MPS shape + std::vector> MPS_shape_source; + for (std::size_t idx = 0; idx < tensors.size(); idx++) { + py::buffer_info numpyArrayInfo = tensors[idx].request(); + auto MPS_site_source_shape = numpyArrayInfo.shape; + std::vector MPS_site_source( + MPS_site_source_shape.begin(), + MPS_site_source_shape.end()); + MPS_shape_source.push_back(std::move(MPS_site_source)); + } + + tensor_network.MPSShapeCheck(MPS_shape_source); + for (std::size_t idx = 0; idx < tensors.size(); idx++) { py::buffer_info numpyArrayInfo = tensors[idx].request(); auto *data_ptr = static_cast *>( 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 b75c272697..a359014bf4 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 @@ -120,6 +120,54 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { } } +TEMPLATE_TEST_CASE("MPSTNCuda::MPSShapeCheck()", "[MPSTNCuda]", float, double) { + const std::size_t num_qubits = 4; + const std::size_t maxBondDim = 8; + SECTION("Correct incoming MPS shape") { + + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> correct_shape{ + {2, 2}, {2, 2, 4}, {4, 2, 2}, {2, 2}}; + + REQUIRE_NOTHROW(mps_state.MPSShapeCheck(correct_shape)); + } + + SECTION("Incorrect incoming MPS shape, bond dimension") { + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> incorrect_shape{ + {2, 2}, {2, 2, 2}, {2, 2, 2}, {2, 2}}; + + REQUIRE_THROWS_WITH( + mps_state.MPSShapeCheck(incorrect_shape), + Catch::Matchers::Contains("The incoming MPS does not have the " + "correct layout for lightning.tensor")); + } + SECTION("Incorrect incoming MPS shape, physical dimension") { + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> incorrect_shape{ + {4, 2}, {2, 4, 4}, {4, 4, 2}, {2, 4}}; + + REQUIRE_THROWS_WITH( + mps_state.MPSShapeCheck(incorrect_shape), + Catch::Matchers::Contains("The incoming MPS does not have the " + "correct layout for lightning.tensor")); + } + SECTION("Incorrect incoming MPS shape, number sites") { + MPSTNCuda mps_state{num_qubits, maxBondDim}; + + std::vector> incorrect_shape{ + {2, 2}, {2, 2, 2}, {2, 2}}; + + REQUIRE_THROWS_WITH( + mps_state.MPSShapeCheck(incorrect_shape), + Catch::Matchers::Contains("The incoming MPS does not have the " + "correct layout for lightning.tensor")); + } +} + TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", float, double) { std::vector> basisStates = { diff --git a/pennylane_lightning/core/src/utils/Util.hpp b/pennylane_lightning/core/src/utils/Util.hpp index 6f512ac40d..bf5d25651e 100644 --- a/pennylane_lightning/core/src/utils/Util.hpp +++ b/pennylane_lightning/core/src/utils/Util.hpp @@ -592,4 +592,34 @@ bool areVecsDisjoint(const std::vector &v1, const std::vector &v2) { } return true; } + +/** + * @brief Convert a 2D vector to string. + * @tparam T Data type. + * @param vec Vector to convert. + * + * @return std::string String with the vector values. + */ +template +std::string vector2DToString(const std::vector> &vec) { + std::ostringstream oss; + oss << "["; + + for (std::size_t i = 0; i < vec.size(); ++i) { + oss << "["; + for (std::size_t j = 0; j < vec[i].size(); ++j) { + oss << vec[i][j]; + if (j != vec[i].size() - 1) { + oss << ", "; // Add a comma between elements in the inner vector + } + } + oss << "]"; + if (i != vec.size() - 1) { + oss << ", "; // Add a comma between inner vectors + } + } + oss << "]"; + return oss.str(); // Return the resulting string +} + } // namespace Pennylane::Util diff --git a/pennylane_lightning/core/src/utils/tests/Test_Util.cpp b/pennylane_lightning/core/src/utils/tests/Test_Util.cpp index 2ba66c779f..709eb6dae8 100644 --- a/pennylane_lightning/core/src/utils/tests/Test_Util.cpp +++ b/pennylane_lightning/core/src/utils/tests/Test_Util.cpp @@ -233,3 +233,15 @@ TEST_CASE("Util::areVecsDisjoint", "[Util][LinearAlgebra]") { REQUIRE(areVecsDisjoint(vec0, vec1) == false); } } + +TEST_CASE("Utils::vector2DToString", "[Utils]") { + SECTION("Test for convert 2Dvector to string") { + std::vector> vec{ + {2, 2, 4}, {4, 2, 8}, {8, 2, 8}}; + std::string ref_str{"[[2, 2, 4], [4, 2, 8], [8, 2, 8]]"}; + + std::string vec2str = vector2DToString(vec); + + REQUIRE(ref_str == vec2str); + } +} \ No newline at end of file diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 24f796f3e9..1684f40956 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -26,8 +26,6 @@ except ImportError: pass -from typing import List - import numpy as np import pennylane as qml from pennylane import BasisState, DeviceError, MPSPrep, StatePrep @@ -125,56 +123,6 @@ def gate_matrix_decompose(gate_ops_matrix, wires, max_mpo_bond_dim, c_dtype): return mpos, sorted_wires -def set_bond_dims(num_qubits: int, max_bond_dim: int) -> List: - """Compute the MPS bond dimensions on base to the number of wires.""" - - log_max_bond_dim = np.log2(max_bond_dim) - limit_dimension = 2 ** int(log_max_bond_dim) - localBondDims = [limit_dimension] * (num_qubits - 1) - - for i in range(len(localBondDims)): - bondDim = min(i + 1, num_qubits - i - 1) - if bondDim <= log_max_bond_dim: - localBondDims[i] = 2**bondDim - - return localBondDims - - -def set_sites_extents(num_qubits: int, max_bond_dim: int) -> List: - """Compute the MPS sites dimensions on base to the number of wires.""" - - bondDims = set_bond_dims(num_qubits, max_bond_dim) - qubitDims = [2 for _ in range(num_qubits)] - - localSiteExtents = [] - for i in range(num_qubits): - if i == 0: - localSite = [qubitDims[i], bondDims[i]] - elif i == num_qubits - 1: - localSite = [bondDims[i - 1], qubitDims[i]] - else: - localSite = [bondDims[i - 1], qubitDims[i], bondDims[i]] - - localSiteExtents.append(localSite) - - return localSiteExtents - - -def MPSPrep_check(MPS: List, num_wires: int, max_bond_dim: int) -> None: - """Check if the provided MPS has the correct dimension for C++ backend.""" - - MPS_shape_dest = set_sites_extents(num_wires, max_bond_dim) - - MPS_shape_source = [list(site.shape) for site in MPS] - - same_shape = [s == d for s, d in zip(MPS_shape_source, MPS_shape_dest)] - - if not all(same_shape): - raise ValueError( - f"The custom MPS does not have the correct layout for lightning.tensor.\n MPS source shape {MPS_shape_source}\n MPS destination shape {MPS_shape_dest}" - ) - - # pylint: disable=too-many-instance-attributes class LightningTensorNet: """Lightning tensornet class. @@ -376,22 +324,6 @@ def _apply_basis_state(self, state, wires): self._tensornet.setBasisState(state) - def _load_mps_state(self, state: List): - """Prepares an initial state using MPS. - - Args: - state (List): A list of different numpy array with the MPS sites values. The structure should be as follows: - [ (2, 2), (2, 2, 4), (4, 2, 8), ..., - (8, 2, 4), (4, 2, 2), (2, 2) ] - wires (List): wires that the provided computational state should be - initialized on. - - Note: The correct MPS sites format and layout are user responsible. - """ - mps = state.mps - MPSPrep_check(mps, self._num_wires, self._max_bond_dim) - self._tensornet.updateMPSSitesData(mps) - def _apply_MPO(self, gate_matrix, wires): """Apply a matrix product operator to the quantum state (MPS method only). @@ -513,7 +445,8 @@ def apply_operations(self, operations): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] elif isinstance(operations[0], MPSPrep): - self._load_mps_state(operations[0]) + mps = operations[0].mps + self._tensornet.updateMPSSitesData(mps) operations = operations[1:] self._apply_lightning(operations) diff --git a/tests/lightning_tensor/test_tensornet_class.py b/tests/lightning_tensor/test_tensornet_class.py index 74530c47d7..64f367ed7a 100644 --- a/tests/lightning_tensor/test_tensornet_class.py +++ b/tests/lightning_tensor/test_tensornet_class.py @@ -25,11 +25,8 @@ else: from pennylane_lightning.lightning_tensor._tensornet import ( LightningTensorNet, - MPSPrep_check, decompose_dense, gate_matrix_decompose, - set_bond_dims, - set_sites_extents, ) if not LightningDevice._CPP_BINARY_AVAILABLE: # pylint: disable=protected-access @@ -74,7 +71,7 @@ def test_wrong_device_name(): def test_wrong_method_name(): - """Test an invalid device name""" + """Test an invalid method name""" with pytest.raises(qml.DeviceError, match="The method "): LightningTensorNet(3, max_bond_dim=5, device_name="lightning.tensor", method="spider_web") @@ -138,86 +135,3 @@ def test_gate_matrix_decompose(): assert np.allclose(sorted_wired, sorted(wires), atol=1e-6) assert np.allclose(unitary_f, original_gate, atol=1e-6) - - -@pytest.mark.parametrize( - "n_qubits,max_bond,expected", - [ - (2, 128, [2]), - (8, 128, [2, 4, 8, 16, 8, 4, 2]), - (8, 8, [2, 4, 8, 8, 8, 4, 2]), - (15, 2, [2 for _ in range(14)]), - ], -) -def test_set_bond_dims(n_qubits, max_bond, expected): - - result = set_bond_dims(n_qubits, max_bond) - - assert len(result) == len(expected) - assert all([a == b for a, b in zip(result, expected)]) - - -@pytest.mark.parametrize( - "n_qubits,max_bond,expected", - [ - (2, 128, [[2, 2], [2, 2]]), - ( - 8, - 128, - [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], - ), - (8, 8, [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), - (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(13)] + [[2, 2]]), - ], -) -def test_set_sites_extents(n_qubits, max_bond, expected): - - result = set_sites_extents(n_qubits, max_bond) - - assert len(result) == len(expected) - assert all([a == b for a, b in zip(result, expected)]) - - -@pytest.mark.parametrize( - "wires,max_bond,MPS_shape", - [ - (2, 128, [[2, 2], [2, 2]]), - ( - 8, - 128, - [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], - ), - (8, 8, [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), - (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(13)] + [[2, 2]]), - ], -) -def test_MPSPrep_check_pass(wires, max_bond, MPS_shape): - MPS = [np.zeros(i) for i in MPS_shape] - - MPSPrep_check(MPS, wires, max_bond) - - -@pytest.mark.parametrize( - "wires,max_bond,MPS_shape", - [ - (2, 128, [[2, 3], [3, 2]]), # Incorrect bond dim. - ( - 8, - 128, - [[2, 2], [2, 4, 4], [4, 4, 8], [8, 4, 16], [16, 4, 8], [8, 4, 4], [4, 4, 2], [2, 2]], - ), # Incorrect physical dim. - ( - 8, - 8, - [[2, 2], [3, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], - ), # Incorrect only one bond dim. - (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(14)] + [[2, 2]]), # Incorrect amount of sites - ], -) -def test_MPSPrep_check_fail(wires, max_bond, MPS_shape): - MPS = [np.zeros(i) for i in MPS_shape] - - with pytest.raises( - ValueError, match="The custom MPS does not have the correct layout for lightning.tensor" - ): - MPSPrep_check(MPS, wires, max_bond) From f4d2a18dd56ac3e56133c119610cbf2fb59c69c4 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 16 Dec 2024 20:17:02 +0000 Subject: [PATCH 14/30] Auto update version from '0.40.0-dev36' to '0.40.0-dev38' --- 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 69b64a3658..48a152c2da 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.40.0-dev36" +__version__ = "0.40.0-dev38" From c3ba71dc5f53e2b833b19f22b070a233af9bf1a3 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Mon, 16 Dec 2024 20:22:01 +0000 Subject: [PATCH 15/30] Auto update version from '0.40.0-dev37' to '0.40.0-dev38' --- 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 87a488e558..48a152c2da 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.40.0-dev37" +__version__ = "0.40.0-dev38" From 98e65d9a4e41b71488cd59dd03fbcc68cbd6ae3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Mon, 16 Dec 2024 20:23:27 +0000 Subject: [PATCH 16/30] fix codefactor --- .../simulators/lightning_tensor/tncuda/tests/Tests_MPSTNCuda.cpp | 1 - 1 file changed, 1 deletion(-) 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 a359014bf4..bca7f6ea63 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 @@ -124,7 +124,6 @@ TEMPLATE_TEST_CASE("MPSTNCuda::MPSShapeCheck()", "[MPSTNCuda]", float, double) { const std::size_t num_qubits = 4; const std::size_t maxBondDim = 8; SECTION("Correct incoming MPS shape") { - MPSTNCuda mps_state{num_qubits, maxBondDim}; std::vector> correct_shape{ From de866a061cb2bb2f84c22e121f26fd7a4beda951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Tue, 17 Dec 2024 18:35:09 +0000 Subject: [PATCH 17/30] added test in Python Layer --- .../lightning_tensor/_tensornet.py | 10 ++- .../lightning_tensor/test_lightning_tensor.py | 85 +++++++++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 1684f40956..11fc3b3db8 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -445,9 +445,13 @@ def apply_operations(self, operations): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] elif isinstance(operations[0], MPSPrep): - mps = operations[0].mps - self._tensornet.updateMPSSitesData(mps) - operations = operations[1:] + if self.method == "tn": + raise DeviceError("Exact Tensor Network does not support MPSPrep") + + if self.method == "mps": + mps = operations[0].mps + self._tensornet.updateMPSSitesData(mps) + operations = operations[1:] self._apply_lightning(operations) diff --git a/tests/lightning_tensor/test_lightning_tensor.py b/tests/lightning_tensor/test_lightning_tensor.py index ce1cb5b4ae..4299bc8303 100644 --- a/tests/lightning_tensor/test_lightning_tensor.py +++ b/tests/lightning_tensor/test_lightning_tensor.py @@ -26,6 +26,8 @@ pytest.skip("Skipping tests for the LightningTensor class.", allow_module_level=True) else: from pennylane_lightning.lightning_tensor import LightningTensor + from pennylane_lightning.lightning_tensor_ops import LightningException + if not LightningDevice._CPP_BINARY_AVAILABLE: # pylint: disable=protected-access pytest.skip("Device doesn't have C++ support yet.", allow_module_level=True) @@ -157,3 +159,86 @@ def test_execute_and_compute_vjp(self, method): match="The computation of vector-Jacobian product has yet to be implemented for the lightning.tensor device.", ): dev.execute_and_compute_vjp(circuits=None, cotangents=None) + +@pytest.mark.parametrize( + "wires,max_bond,MPS_shape", + [ + (2, 128, [[2, 2], [2, 2]]), + ( + 8, + 128, + [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], + ), + (8, 8, [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 8], [8, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]]), + (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(13)] + [[2, 2]]), + ], +) +def test_MPSPrep_check_pass(wires, max_bond, MPS_shape): + """Test the correct behavior regarding MPS shape of MPSPrep.""" + MPS = [np.zeros(i) for i in MPS_shape] + dev = LightningTensor(wires=wires, method='mps', max_bond_dim=max_bond) + dev_wires = dev.wires.tolist() + + def circuit(MPS): + qml.MPSPrep(mps=MPS, wires=dev_wires) + return qml.state() + + qnode_ltensor = qml.QNode(circuit, dev) + + try: + _ = qnode_ltensor(MPS) + except Exception as excinfo: + pytest.fail(f"Unexpected exception raised: {excinfo}") + +@pytest.mark.parametrize( + "wires,max_bond,MPS_shape", + [ + ( + 8, + 8, + [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], + ), # Incorrect max bond dim. + (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(14)] + [[2, 2]]), # Incorrect amount of sites + ], +) +def test_MPSPrep_check_fail(wires, max_bond, MPS_shape): + """Test the exceptions regarding MPS shape of MPSPrep.""" + + MPS = [np.zeros(i) for i in MPS_shape] + dev = LightningTensor(wires=wires, method='mps', max_bond_dim=max_bond) + dev_wires = dev.wires.tolist() + + def circuit(MPS): + qml.MPSPrep(mps=MPS, wires=dev_wires) + return qml.state() + + qnode_ltensor = qml.QNode(circuit, dev) + + with pytest.raises( + LightningException, match="The incoming MPS does not have the correct layout for lightning.tensor" + ): + _ = qnode_ltensor(MPS) + +@pytest.mark.parametrize( + "wires, MPS_shape", + [ + (2, [[2, 2], [2, 2]]), + ], +) +def test_MPSPrep_with_tn(wires, MPS_shape): + """Test the exception of MPSPrep with the method exact tensor network (tn).""" + + MPS = [np.zeros(i) for i in MPS_shape] + dev = LightningTensor(wires=wires, method='tn') + dev_wires = dev.wires.tolist() + + def circuit(MPS): + qml.MPSPrep(mps=MPS, wires=dev_wires) + return qml.state() + + qnode_ltensor = qml.QNode(circuit, dev) + + with pytest.raises( + qml.DeviceError, match="Exact Tensor Network does not support MPSPrep" + ): + _ = qnode_ltensor(MPS) From 0f88b7ea0bec3a62fdcd8e6a167a1dc366b49785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Tue, 17 Dec 2024 18:38:03 +0000 Subject: [PATCH 18/30] apply format --- .../lightning_tensor/test_lightning_tensor.py | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/tests/lightning_tensor/test_lightning_tensor.py b/tests/lightning_tensor/test_lightning_tensor.py index 4299bc8303..fdd9773005 100644 --- a/tests/lightning_tensor/test_lightning_tensor.py +++ b/tests/lightning_tensor/test_lightning_tensor.py @@ -27,7 +27,7 @@ else: from pennylane_lightning.lightning_tensor import LightningTensor from pennylane_lightning.lightning_tensor_ops import LightningException - + if not LightningDevice._CPP_BINARY_AVAILABLE: # pylint: disable=protected-access pytest.skip("Device doesn't have C++ support yet.", allow_module_level=True) @@ -159,7 +159,8 @@ def test_execute_and_compute_vjp(self, method): match="The computation of vector-Jacobian product has yet to be implemented for the lightning.tensor device.", ): dev.execute_and_compute_vjp(circuits=None, cotangents=None) - + + @pytest.mark.parametrize( "wires,max_bond,MPS_shape", [ @@ -176,20 +177,21 @@ def test_execute_and_compute_vjp(self, method): def test_MPSPrep_check_pass(wires, max_bond, MPS_shape): """Test the correct behavior regarding MPS shape of MPSPrep.""" MPS = [np.zeros(i) for i in MPS_shape] - dev = LightningTensor(wires=wires, method='mps', max_bond_dim=max_bond) + dev = LightningTensor(wires=wires, method="mps", max_bond_dim=max_bond) dev_wires = dev.wires.tolist() - + def circuit(MPS): qml.MPSPrep(mps=MPS, wires=dev_wires) return qml.state() - + qnode_ltensor = qml.QNode(circuit, dev) - - try: + + try: _ = qnode_ltensor(MPS) - except Exception as excinfo: + except Exception as excinfo: pytest.fail(f"Unexpected exception raised: {excinfo}") + @pytest.mark.parametrize( "wires,max_bond,MPS_shape", [ @@ -197,7 +199,7 @@ def circuit(MPS): 8, 8, [[2, 2], [2, 2, 4], [4, 2, 8], [8, 2, 16], [16, 2, 8], [8, 2, 4], [4, 2, 2], [2, 2]], - ), # Incorrect max bond dim. + ), # Incorrect max bond dim. (15, 2, [[2, 2]] + [[2, 2, 2] for _ in range(14)] + [[2, 2]]), # Incorrect amount of sites ], ) @@ -205,20 +207,22 @@ def test_MPSPrep_check_fail(wires, max_bond, MPS_shape): """Test the exceptions regarding MPS shape of MPSPrep.""" MPS = [np.zeros(i) for i in MPS_shape] - dev = LightningTensor(wires=wires, method='mps', max_bond_dim=max_bond) + dev = LightningTensor(wires=wires, method="mps", max_bond_dim=max_bond) dev_wires = dev.wires.tolist() - + def circuit(MPS): qml.MPSPrep(mps=MPS, wires=dev_wires) return qml.state() - + qnode_ltensor = qml.QNode(circuit, dev) with pytest.raises( - LightningException, match="The incoming MPS does not have the correct layout for lightning.tensor" + LightningException, + match="The incoming MPS does not have the correct layout for lightning.tensor", ): _ = qnode_ltensor(MPS) + @pytest.mark.parametrize( "wires, MPS_shape", [ @@ -229,16 +233,14 @@ def test_MPSPrep_with_tn(wires, MPS_shape): """Test the exception of MPSPrep with the method exact tensor network (tn).""" MPS = [np.zeros(i) for i in MPS_shape] - dev = LightningTensor(wires=wires, method='tn') + dev = LightningTensor(wires=wires, method="tn") dev_wires = dev.wires.tolist() - + def circuit(MPS): qml.MPSPrep(mps=MPS, wires=dev_wires) return qml.state() - + qnode_ltensor = qml.QNode(circuit, dev) - with pytest.raises( - qml.DeviceError, match="Exact Tensor Network does not support MPSPrep" - ): + with pytest.raises(qml.DeviceError, match="Exact Tensor Network does not support MPSPrep"): _ = qnode_ltensor(MPS) From 03762a4f04c23674088e70fdef3f8f607c81d4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Tue, 17 Dec 2024 18:57:15 +0000 Subject: [PATCH 19/30] solve no binaries --- tests/lightning_tensor/test_lightning_tensor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/lightning_tensor/test_lightning_tensor.py b/tests/lightning_tensor/test_lightning_tensor.py index fdd9773005..e4d3e3d817 100644 --- a/tests/lightning_tensor/test_lightning_tensor.py +++ b/tests/lightning_tensor/test_lightning_tensor.py @@ -18,7 +18,7 @@ import numpy as np import pennylane as qml import pytest -from conftest import LightningDevice, device_name # tested device +from conftest import LightningDevice, LightningException, device_name from pennylane.tape import QuantumScript from pennylane.wires import Wires @@ -26,7 +26,6 @@ pytest.skip("Skipping tests for the LightningTensor class.", allow_module_level=True) else: from pennylane_lightning.lightning_tensor import LightningTensor - from pennylane_lightning.lightning_tensor_ops import LightningException if not LightningDevice._CPP_BINARY_AVAILABLE: # pylint: disable=protected-access From 1b0ae0c922a854338bb605cdac3bf86c672bcf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Wed, 18 Dec 2024 19:05:59 +0000 Subject: [PATCH 20/30] create a getter for sitesExtents_ --- .../lightning_tensor/tncuda/TNCuda.hpp | 35 ++---- .../tncuda/bindings/LTensorTNCudaBindings.hpp | 6 +- .../tncuda/tests/Tests_MPSTNCuda.cpp | 109 ++++++++++-------- .../tncuda_utils/tests/Test_TNCuda_utils.cpp | 49 ++++++++ .../utils/tncuda_utils/tncuda_helpers.hpp | 25 ++++ 5 files changed, 149 insertions(+), 75 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp index e8a8ce5efa..1f5dccb203 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp @@ -252,31 +252,6 @@ class TNCuda : public TNCudaBase { host_data_size); } - /** - * @brief Check if the provided MPS has the correct dimension for C++ - * backend. - * - * @param MPS_shape_source Dimension list of incoming MPS. - */ - - void MPSShapeCheck( - const std::vector> &MPS_shape_source) { - bool sameShape = sitesExtents_ == MPS_shape_source; - if (!sameShape) { - auto MPS_shape_source_str = - Pennylane::Util::vector2DToString( - MPS_shape_source); - auto MPS_shape_dest_str = - Pennylane::Util::vector2DToString(sitesExtents_); - - PL_ABORT_IF_NOT( - sitesExtents_ == MPS_shape_source, - "The incoming MPS does not have the correct layout for " - "lightning.tensor.\n Incoming MPS: " + - MPS_shape_source_str + - "\n Destination MPS: " + MPS_shape_dest_str) - } - } /** * @brief Append multiple gates to the compute graph. * NOTE: This function does not update the quantum state but only appends @@ -524,6 +499,16 @@ class TNCuda : public TNCudaBase { projected_mode_values, numHyperSamples); } + /** + * @brief Get a const vector reference of sitesExtents_. + * + * @return const std::vector> + */ + [[nodiscard]] auto getSitesExtents() + -> const std::vector> & { + return sitesExtents_; + } + protected: /** * @brief Get a vector of pointers to tensor data of each site. 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 ae4ae6fd66..9ee370f407 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 @@ -33,13 +33,14 @@ #include "TypeList.hpp" #include "Util.hpp" #include "cuda_helpers.hpp" +#include "tncuda_helpers.hpp" /// @cond DEV namespace { using namespace Pennylane; using namespace Pennylane::Bindings; using namespace Pennylane::LightningGPU::Util; -using Pennylane::LightningTensor::TNCuda::MPSTNCuda; +using namespace Pennylane::LightningTensor::TNCuda::Util; } // namespace /// @endcond @@ -148,7 +149,8 @@ void registerBackendClassSpecificBindingsMPS(PyClass &pyclass) { MPS_shape_source.push_back(std::move(MPS_site_source)); } - tensor_network.MPSShapeCheck(MPS_shape_source); + const auto &MPS_shape_dest = tensor_network.getSitesExtents(); + MPSShapeCheck(MPS_shape_dest, MPS_shape_source); for (std::size_t idx = 0; idx < tensors.size(); idx++) { py::buffer_info numpyArrayInfo = tensors[idx].request(); 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 bca7f6ea63..b76814893f 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 @@ -120,53 +120,6 @@ TEMPLATE_TEST_CASE("MPSTNCuda::setIthMPSSite", "[MPSTNCuda]", float, double) { } } -TEMPLATE_TEST_CASE("MPSTNCuda::MPSShapeCheck()", "[MPSTNCuda]", float, double) { - const std::size_t num_qubits = 4; - const std::size_t maxBondDim = 8; - SECTION("Correct incoming MPS shape") { - MPSTNCuda mps_state{num_qubits, maxBondDim}; - - std::vector> correct_shape{ - {2, 2}, {2, 2, 4}, {4, 2, 2}, {2, 2}}; - - REQUIRE_NOTHROW(mps_state.MPSShapeCheck(correct_shape)); - } - - SECTION("Incorrect incoming MPS shape, bond dimension") { - MPSTNCuda mps_state{num_qubits, maxBondDim}; - - std::vector> incorrect_shape{ - {2, 2}, {2, 2, 2}, {2, 2, 2}, {2, 2}}; - - REQUIRE_THROWS_WITH( - mps_state.MPSShapeCheck(incorrect_shape), - Catch::Matchers::Contains("The incoming MPS does not have the " - "correct layout for lightning.tensor")); - } - SECTION("Incorrect incoming MPS shape, physical dimension") { - MPSTNCuda mps_state{num_qubits, maxBondDim}; - - std::vector> incorrect_shape{ - {4, 2}, {2, 4, 4}, {4, 4, 2}, {2, 4}}; - - REQUIRE_THROWS_WITH( - mps_state.MPSShapeCheck(incorrect_shape), - Catch::Matchers::Contains("The incoming MPS does not have the " - "correct layout for lightning.tensor")); - } - SECTION("Incorrect incoming MPS shape, number sites") { - MPSTNCuda mps_state{num_qubits, maxBondDim}; - - std::vector> incorrect_shape{ - {2, 2}, {2, 2, 2}, {2, 2}}; - - REQUIRE_THROWS_WITH( - mps_state.MPSShapeCheck(incorrect_shape), - Catch::Matchers::Contains("The incoming MPS does not have the " - "correct layout for lightning.tensor")); - } -} - TEMPLATE_TEST_CASE("MPSTNCuda::SetBasisStates() & reset()", "[MPSTNCuda]", float, double) { std::vector> basisStates = { @@ -370,4 +323,64 @@ TEMPLATE_TEST_CASE("MPOTNCuda::getBondDims()", "[MPOTNCuda]", float, double) { CHECK(bondDims == expected_bondDims); } -} \ No newline at end of file +} + +TEMPLATE_TEST_CASE("MPSTNCuda::getSitesExtents()", "[MPSTNCuda]", float, + double) { + SECTION("Check if sitesExtents retrun is correctly with 3 qubits") { + const std::size_t num_qubits = 3; + const std::size_t maxBondDim = 128; + const DevTag dev_tag{0, 0}; + + const std::vector> reference{ + {{2, 2}, {2, 2, 2}, {2, 2}}}; + + MPSTNCuda mps{num_qubits, maxBondDim, dev_tag}; + + const auto &sitesExtents = mps.getSitesExtents(); + + CHECK(reference == sitesExtents); + } + + SECTION("Check if sitesExtents retrun is correctly with 8 qubits") { + const std::size_t num_qubits = 8; + const std::size_t maxBondDim = 128; + const DevTag dev_tag{0, 0}; + + const std::vector> reference{{{2, 2}, + {2, 2, 4}, + {4, 2, 8}, + {8, 2, 16}, + {16, 2, 8}, + {8, 2, 4}, + {4, 2, 2}, + {2, 2}}}; + + MPSTNCuda mps{num_qubits, maxBondDim, dev_tag}; + + const auto &sitesExtents = mps.getSitesExtents(); + + CHECK(reference == sitesExtents); + } + SECTION("Check if sitesExtents retrun is correctly with 8 qubits and " + "maxBondDim=8") { + const std::size_t num_qubits = 8; + const std::size_t maxBondDim = 8; + const DevTag dev_tag{0, 0}; + + const std::vector> reference{{{2, 2}, + {2, 2, 4}, + {4, 2, 8}, + {8, 2, 8}, + {8, 2, 8}, + {8, 2, 4}, + {4, 2, 2}, + {2, 2}}}; + + MPSTNCuda mps{num_qubits, maxBondDim, dev_tag}; + + const auto &sitesExtents = mps.getSitesExtents(); + + CHECK(reference == sitesExtents); + } +} diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tests/Test_TNCuda_utils.cpp b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tests/Test_TNCuda_utils.cpp index 63c399b1ba..7d4d5f2767 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tests/Test_TNCuda_utils.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tests/Test_TNCuda_utils.cpp @@ -84,3 +84,52 @@ TEST_CASE("swap_op_wires_queue", "[TNCuda_utils]") { REQUIRE(swap_wires_queue[1] == swap_wires_queue_ref1); } } + +TEST_CASE("MPSShapeCheck", "[TNCuda_utils]") { + SECTION("Correct incoming MPS shape") { + std::vector> MPS_shape_dest{ + {2, 2}, {2, 2, 4}, {4, 2, 2}, {2, 2}}; + + std::vector> MPS_shape_source{ + {2, 2}, {2, 2, 4}, {4, 2, 2}, {2, 2}}; + + REQUIRE_NOTHROW(MPSShapeCheck(MPS_shape_dest, MPS_shape_source)); + } + + SECTION("Incorrect incoming MPS shape, bond dimension") { + std::vector> MPS_shape_dest{ + {2, 2}, {2, 2, 4}, {4, 2, 2}, {2, 2}}; + + std::vector> incorrect_MPS_shape{ + {2, 2}, {2, 2, 2}, {2, 2, 2}, {2, 2}}; + + REQUIRE_THROWS_WITH( + MPSShapeCheck(MPS_shape_dest, incorrect_MPS_shape), + Catch::Matchers::Contains("The incoming MPS does not have the " + "correct layout for lightning.tensor")); + } + SECTION("Incorrect incoming MPS shape, physical dimension") { + std::vector> MPS_shape_dest{ + {2, 2}, {2, 2, 4}, {4, 2, 2}, {2, 2}}; + + std::vector> incorrect_shape{ + {4, 2}, {2, 4, 4}, {4, 4, 2}, {2, 4}}; + + REQUIRE_THROWS_WITH( + MPSShapeCheck(MPS_shape_dest, incorrect_shape), + Catch::Matchers::Contains("The incoming MPS does not have the " + "correct layout for lightning.tensor")); + } + SECTION("Incorrect incoming MPS shape, number sites") { + std::vector> MPS_shape_dest{ + {2, 2}, {2, 2, 4}, {4, 2, 2}, {2, 2}}; + + std::vector> incorrect_shape{ + {2, 2}, {2, 2, 2}, {2, 2}}; + + REQUIRE_THROWS_WITH( + MPSShapeCheck(MPS_shape_dest, incorrect_shape), + Catch::Matchers::Contains("The incoming MPS does not have the " + "correct layout for lightning.tensor")); + } +} diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp index 4fadfadb40..661b5048fe 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp @@ -194,4 +194,29 @@ inline auto create_swap_wire_pair_queue(const std::vector &wires) return {local_wires, swap_wires_queue}; } +/** + * @brief Check if the provided MPS has the correct dimension for C++ + * backend. + * + * @param MPS_shape_dest Dimension list of destination MPS. + * @param MPS_shape_source Dimension list of incoming MPS. + */ +inline void MPSShapeCheck( + const std::vector> &MPS_shape_dest, + const std::vector> &MPS_shape_source) { + + if (!(MPS_shape_dest == MPS_shape_source)) { + auto MPS_shape_source_str = + Pennylane::Util::vector2DToString(MPS_shape_source); + auto MPS_shape_dest_str = + Pennylane::Util::vector2DToString(MPS_shape_dest); + + PL_ABORT_IF_NOT(MPS_shape_dest == MPS_shape_source, + "The incoming MPS does not have the correct layout for " + "lightning.tensor.\n Incoming MPS: " + + MPS_shape_source_str + + "\n Destination MPS: " + MPS_shape_dest_str) + } +} + } // namespace Pennylane::LightningTensor::TNCuda::Util From 8d09f69d2f15d0005958b6de4d0ddb3ababc9d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Wed, 18 Dec 2024 19:06:32 +0000 Subject: [PATCH 21/30] apply format --- .../lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp index 661b5048fe..d589bc45ec 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp @@ -201,9 +201,9 @@ inline auto create_swap_wire_pair_queue(const std::vector &wires) * @param MPS_shape_dest Dimension list of destination MPS. * @param MPS_shape_source Dimension list of incoming MPS. */ -inline void MPSShapeCheck( - const std::vector> &MPS_shape_dest, - const std::vector> &MPS_shape_source) { +inline void +MPSShapeCheck(const std::vector> &MPS_shape_dest, + const std::vector> &MPS_shape_source) { if (!(MPS_shape_dest == MPS_shape_source)) { auto MPS_shape_source_str = From aba5ac40d8fa7ebdf618d104fe99453608abcb15 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 18 Dec 2024 19:06:57 +0000 Subject: [PATCH 22/30] Auto update version from '0.40.0-dev38' to '0.40.0-dev40' --- 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 48a152c2da..0e752dbe5e 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.40.0-dev38" +__version__ = "0.40.0-dev40" From 160ad672008d5da5cc0b7856e8a8850dd94c3f33 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Wed, 18 Dec 2024 19:08:23 +0000 Subject: [PATCH 23/30] Auto update version from '0.40.0-dev39' to '0.40.0-dev40' --- 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 e50c1c959a..0e752dbe5e 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.40.0-dev39" +__version__ = "0.40.0-dev40" From b132719a437656b923be89520ac8e2a1e290a9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Thu, 19 Dec 2024 06:28:40 +0000 Subject: [PATCH 24/30] suggestion Ali and Shuli --- .../core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp | 2 +- .../lightning_tensor/tncuda/bindings/LTensorTNCudaBindings.hpp | 2 +- .../lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp | 2 +- pennylane_lightning/core/src/utils/tests/Test_Util.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp index 1f5dccb203..e41501fa45 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp @@ -504,7 +504,7 @@ class TNCuda : public TNCudaBase { * * @return const std::vector> */ - [[nodiscard]] auto getSitesExtents() + [[nodiscard]] auto getSitesExtents() const -> const std::vector> & { return sitesExtents_; } 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 9ee370f407..9892a95b6d 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 @@ -146,7 +146,7 @@ void registerBackendClassSpecificBindingsMPS(PyClass &pyclass) { std::vector MPS_site_source( MPS_site_source_shape.begin(), MPS_site_source_shape.end()); - MPS_shape_source.push_back(std::move(MPS_site_source)); + MPS_shape_source.emplace_back(std::move(MPS_site_source)); } const auto &MPS_shape_dest = tensor_network.getSitesExtents(); diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp index d589bc45ec..4f036e3002 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp @@ -205,7 +205,7 @@ inline void MPSShapeCheck(const std::vector> &MPS_shape_dest, const std::vector> &MPS_shape_source) { - if (!(MPS_shape_dest == MPS_shape_source)) { + if (MPS_shape_dest != MPS_shape_source) { auto MPS_shape_source_str = Pennylane::Util::vector2DToString(MPS_shape_source); auto MPS_shape_dest_str = diff --git a/pennylane_lightning/core/src/utils/tests/Test_Util.cpp b/pennylane_lightning/core/src/utils/tests/Test_Util.cpp index 709eb6dae8..8a775d5497 100644 --- a/pennylane_lightning/core/src/utils/tests/Test_Util.cpp +++ b/pennylane_lightning/core/src/utils/tests/Test_Util.cpp @@ -244,4 +244,4 @@ TEST_CASE("Utils::vector2DToString", "[Utils]") { REQUIRE(ref_str == vec2str); } -} \ No newline at end of file +} From e9f2789bb32df9bd67db0780e9ff830655c0e328 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 19 Dec 2024 06:29:16 +0000 Subject: [PATCH 25/30] Auto update version from '0.40.0-dev40' to '0.40.0-dev42' --- 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 0e752dbe5e..30f24595a9 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.40.0-dev40" +__version__ = "0.40.0-dev42" From 814b7befe24b6357cf2d6f3996aa0a059efd24c5 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Thu, 19 Dec 2024 06:29:58 +0000 Subject: [PATCH 26/30] Auto update version from '0.40.0-dev41' to '0.40.0-dev42' --- 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 f811d3d60e..30f24595a9 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.40.0-dev41" +__version__ = "0.40.0-dev42" From fb7e7e53e13a5a81274970dad185c7da06eed2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Thu, 19 Dec 2024 06:31:38 +0000 Subject: [PATCH 27/30] solve codefactor --- .../lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp index 4f036e3002..8cc9f81a03 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp @@ -204,7 +204,6 @@ inline auto create_swap_wire_pair_queue(const std::vector &wires) inline void MPSShapeCheck(const std::vector> &MPS_shape_dest, const std::vector> &MPS_shape_source) { - if (MPS_shape_dest != MPS_shape_source) { auto MPS_shape_source_str = Pennylane::Util::vector2DToString(MPS_shape_source); From 25bfe00dfe91c31ac2eefe5430778df59330dfbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Fri, 20 Dec 2024 00:08:05 +0000 Subject: [PATCH 28/30] suggestion Ali Joseph and Shuli --- .../lightning_tensor/tncuda/TNCuda.hpp | 50 +++++++++---------- .../tncuda/tests/Tests_MPSTNCuda.cpp | 8 +-- .../utils/tncuda_utils/tncuda_helpers.hpp | 9 +--- pennylane_lightning/core/src/utils/Util.hpp | 29 ----------- .../core/src/utils/tests/Test_Util.cpp | 12 ----- .../lightning_tensor/_tensornet.py | 12 ++--- .../lightning_tensor/test_lightning_tensor.py | 5 +- 7 files changed, 36 insertions(+), 89 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp index ca3ab1391e..c36885a9f9 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp @@ -60,32 +60,6 @@ class TNCuda : public TNCudaBase { using ComplexT = std::complex; using BaseType = TNCudaBase; - protected: - // Note both maxBondDim_ and bondDims_ are used for both MPS and Exact - // Tensor Network. Per Exact Tensor Network, maxBondDim_ is 1 and bondDims_ - // is {1}. Per Exact Tensor Network, setting bondDims_ allows call to - // appendInitialMPSState_() to append the initial state to the Exact Tensor - // Network state. - const std::size_t - maxBondDim_; // maxBondDim_ default is 1 for Exact Tensor Network - const std::vector - bondDims_; // bondDims_ default is {1} for Exact Tensor Network - - private: - const std::vector> sitesModes_; - const std::vector> sitesExtents_; - const std::vector> sitesExtents_int64_; - - SharedCublasCaller cublascaller_; - - std::shared_ptr> gate_cache_; - std::set gate_ids_; - - std::vector identiy_gate_ids_; - - std::vector> tensors_; - std::vector> tensors_out_; - public: TNCuda() = delete; @@ -510,6 +484,16 @@ class TNCuda : public TNCudaBase { } protected: + // Note both maxBondDim_ and bondDims_ are used for both MPS and Exact + // Tensor Network. Per Exact Tensor Network, maxBondDim_ is 1 and bondDims_ + // is {1}. Per Exact Tensor Network, setting bondDims_ allows call to + // appendInitialMPSState_() to append the initial state to the Exact Tensor + // Network state. + const std::size_t + maxBondDim_; // maxBondDim_ default is 1 for Exact Tensor Network + const std::vector + bondDims_; // bondDims_ default is {1} for Exact Tensor Network + /** * @brief Get a vector of pointers to tensor data of each site. * @@ -588,6 +572,20 @@ class TNCuda : public TNCudaBase { } private: + const std::vector> sitesModes_; + const std::vector> sitesExtents_; + const std::vector> sitesExtents_int64_; + + SharedCublasCaller cublascaller_; + + std::shared_ptr> gate_cache_; + std::set gate_ids_; + + std::vector identiy_gate_ids_; + + std::vector> tensors_; + std::vector> tensors_out_; + /** * @brief Get accessor of a state tensor * 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 b76814893f..f63ef70847 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 @@ -291,7 +291,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getDataVector()", "[MPSTNCuda]", float, double) { TEMPLATE_TEST_CASE("MPOTNCuda::getBondDims()", "[MPOTNCuda]", float, double) { using cp_t = std::complex; - SECTION("Check if bondDims is correctly set") { + SECTION("Check if bondDims is correct set") { const std::size_t num_qubits = 3; const std::size_t maxBondDim = 128; const DevTag dev_tag{0, 0}; @@ -327,7 +327,7 @@ TEMPLATE_TEST_CASE("MPOTNCuda::getBondDims()", "[MPOTNCuda]", float, double) { TEMPLATE_TEST_CASE("MPSTNCuda::getSitesExtents()", "[MPSTNCuda]", float, double) { - SECTION("Check if sitesExtents retrun is correctly with 3 qubits") { + SECTION("Check if sitesExtents retrun is correct with 3 qubits") { const std::size_t num_qubits = 3; const std::size_t maxBondDim = 128; const DevTag dev_tag{0, 0}; @@ -342,7 +342,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getSitesExtents()", "[MPSTNCuda]", float, CHECK(reference == sitesExtents); } - SECTION("Check if sitesExtents retrun is correctly with 8 qubits") { + SECTION("Check if sitesExtents retrun is correct with 8 qubits") { const std::size_t num_qubits = 8; const std::size_t maxBondDim = 128; const DevTag dev_tag{0, 0}; @@ -362,7 +362,7 @@ TEMPLATE_TEST_CASE("MPSTNCuda::getSitesExtents()", "[MPSTNCuda]", float, CHECK(reference == sitesExtents); } - SECTION("Check if sitesExtents retrun is correctly with 8 qubits and " + SECTION("Check if sitesExtents retrun is correct with 8 qubits and " "maxBondDim=8") { const std::size_t num_qubits = 8; const std::size_t maxBondDim = 8; diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp index 8cc9f81a03..b03b0f2b7a 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp @@ -205,16 +205,9 @@ inline void MPSShapeCheck(const std::vector> &MPS_shape_dest, const std::vector> &MPS_shape_source) { if (MPS_shape_dest != MPS_shape_source) { - auto MPS_shape_source_str = - Pennylane::Util::vector2DToString(MPS_shape_source); - auto MPS_shape_dest_str = - Pennylane::Util::vector2DToString(MPS_shape_dest); - PL_ABORT_IF_NOT(MPS_shape_dest == MPS_shape_source, "The incoming MPS does not have the correct layout for " - "lightning.tensor.\n Incoming MPS: " + - MPS_shape_source_str + - "\n Destination MPS: " + MPS_shape_dest_str) + "lightning.tensor.") } } diff --git a/pennylane_lightning/core/src/utils/Util.hpp b/pennylane_lightning/core/src/utils/Util.hpp index bf5d25651e..70ec857aaa 100644 --- a/pennylane_lightning/core/src/utils/Util.hpp +++ b/pennylane_lightning/core/src/utils/Util.hpp @@ -593,33 +593,4 @@ bool areVecsDisjoint(const std::vector &v1, const std::vector &v2) { return true; } -/** - * @brief Convert a 2D vector to string. - * @tparam T Data type. - * @param vec Vector to convert. - * - * @return std::string String with the vector values. - */ -template -std::string vector2DToString(const std::vector> &vec) { - std::ostringstream oss; - oss << "["; - - for (std::size_t i = 0; i < vec.size(); ++i) { - oss << "["; - for (std::size_t j = 0; j < vec[i].size(); ++j) { - oss << vec[i][j]; - if (j != vec[i].size() - 1) { - oss << ", "; // Add a comma between elements in the inner vector - } - } - oss << "]"; - if (i != vec.size() - 1) { - oss << ", "; // Add a comma between inner vectors - } - } - oss << "]"; - return oss.str(); // Return the resulting string -} - } // namespace Pennylane::Util diff --git a/pennylane_lightning/core/src/utils/tests/Test_Util.cpp b/pennylane_lightning/core/src/utils/tests/Test_Util.cpp index 8a775d5497..2ba66c779f 100644 --- a/pennylane_lightning/core/src/utils/tests/Test_Util.cpp +++ b/pennylane_lightning/core/src/utils/tests/Test_Util.cpp @@ -233,15 +233,3 @@ TEST_CASE("Util::areVecsDisjoint", "[Util][LinearAlgebra]") { REQUIRE(areVecsDisjoint(vec0, vec1) == false); } } - -TEST_CASE("Utils::vector2DToString", "[Utils]") { - SECTION("Test for convert 2Dvector to string") { - std::vector> vec{ - {2, 2, 4}, {4, 2, 8}, {8, 2, 8}}; - std::string ref_str{"[[2, 2, 4], [4, 2, 8], [8, 2, 8]]"}; - - std::string vec2str = vector2DToString(vec); - - REQUIRE(ref_str == vec2str); - } -} diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 11fc3b3db8..0b6256918b 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -433,26 +433,26 @@ def apply_operations(self, operations): # State preparation is currently done in Python if operations: # make sure operations[0] exists if isinstance(operations[0], StatePrep): - if self.method == "tn": - raise DeviceError("Exact Tensor Network does not support StatePrep") - if self.method == "mps": self._apply_state_vector( operations[0].parameters[0].copy(), operations[0].wires ) operations = operations[1:] + + if self.method == "tn": + raise DeviceError("Exact Tensor Network does not support StatePrep") elif isinstance(operations[0], BasisState): self._apply_basis_state(operations[0].parameters[0], operations[0].wires) operations = operations[1:] elif isinstance(operations[0], MPSPrep): - if self.method == "tn": - raise DeviceError("Exact Tensor Network does not support MPSPrep") - if self.method == "mps": mps = operations[0].mps self._tensornet.updateMPSSitesData(mps) operations = operations[1:] + if self.method == "tn": + raise DeviceError("Exact Tensor Network does not support MPSPrep") + self._apply_lightning(operations) def set_tensor_network(self, circuit: QuantumScript): diff --git a/tests/lightning_tensor/test_lightning_tensor.py b/tests/lightning_tensor/test_lightning_tensor.py index e4d3e3d817..984ec0031b 100644 --- a/tests/lightning_tensor/test_lightning_tensor.py +++ b/tests/lightning_tensor/test_lightning_tensor.py @@ -185,10 +185,7 @@ def circuit(MPS): qnode_ltensor = qml.QNode(circuit, dev) - try: - _ = qnode_ltensor(MPS) - except Exception as excinfo: - pytest.fail(f"Unexpected exception raised: {excinfo}") + _ = qnode_ltensor(MPS) @pytest.mark.parametrize( From 8af4303156cc146a335dc2b41d01df2c1e0b0547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Fri, 20 Dec 2024 00:12:48 +0000 Subject: [PATCH 29/30] changelog update --- .github/CHANGELOG.md | 3 +++ pennylane_lightning/lightning_tensor/_tensornet.py | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index e265b3424e..fb008b06a2 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -29,6 +29,9 @@ ### Improvements +* Optimize lightning.tensor by adding direct MPS sites data set with `qml.MPSPrep`. + [(#983)](https://github.com/PennyLaneAI/pennylane-lightning/pull/983) + * Replace the `dummy_tensor_update` method with the `cutensornetStateCaptureMPS`API to ensure that further gates apply is allowed after the `cutensornetStateCompute` call. [(#1028)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1028/) diff --git a/pennylane_lightning/lightning_tensor/_tensornet.py b/pennylane_lightning/lightning_tensor/_tensornet.py index 0b6256918b..c74e664adb 100644 --- a/pennylane_lightning/lightning_tensor/_tensornet.py +++ b/pennylane_lightning/lightning_tensor/_tensornet.py @@ -438,7 +438,6 @@ def apply_operations(self, operations): operations[0].parameters[0].copy(), operations[0].wires ) operations = operations[1:] - if self.method == "tn": raise DeviceError("Exact Tensor Network does not support StatePrep") elif isinstance(operations[0], BasisState): From 206105f8994c03cf796872087cd63eda96fa9171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Alfredo=20Nu=C3=B1ez=20Meneses?= Date: Fri, 20 Dec 2024 16:51:10 +0000 Subject: [PATCH 30/30] Joseph's suggestions --- .../src/simulators/lightning_tensor/tncuda/TNCuda.hpp | 4 ++-- .../utils/tncuda_utils/tncuda_helpers.hpp | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp index c36885a9f9..6352bcc481 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/tncuda/TNCuda.hpp @@ -485,8 +485,8 @@ class TNCuda : public TNCudaBase { protected: // Note both maxBondDim_ and bondDims_ are used for both MPS and Exact - // Tensor Network. Per Exact Tensor Network, maxBondDim_ is 1 and bondDims_ - // is {1}. Per Exact Tensor Network, setting bondDims_ allows call to + // Tensor Network. For Exact Tensor Network, maxBondDim_ is 1 and bondDims_ + // is {1}. For Exact Tensor Network, setting bondDims_ allows call to // appendInitialMPSState_() to append the initial state to the Exact Tensor // Network state. const std::size_t diff --git a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp index b03b0f2b7a..67e5a3d8ce 100644 --- a/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_tensor/utils/tncuda_utils/tncuda_helpers.hpp @@ -204,11 +204,9 @@ inline auto create_swap_wire_pair_queue(const std::vector &wires) inline void MPSShapeCheck(const std::vector> &MPS_shape_dest, const std::vector> &MPS_shape_source) { - if (MPS_shape_dest != MPS_shape_source) { - PL_ABORT_IF_NOT(MPS_shape_dest == MPS_shape_source, - "The incoming MPS does not have the correct layout for " - "lightning.tensor.") - } + PL_ABORT_IF_NOT(MPS_shape_dest == MPS_shape_source, + "The incoming MPS does not have the correct layout for " + "lightning.tensor.") } } // namespace Pennylane::LightningTensor::TNCuda::Util