Skip to content

Commit

Permalink
Merge branch 'master' into statePrep_MPS
Browse files Browse the repository at this point in the history
  • Loading branch information
LuisAlfredoNu committed Dec 16, 2024
2 parents ccf6e40 + e9a3b80 commit c1206e7
Show file tree
Hide file tree
Showing 24 changed files with 1,805 additions and 608 deletions.
16 changes: 14 additions & 2 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,20 @@

### Improvements

* Update the python layer UI of Lightning Tensor.
[(#1022)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1022/)

* Catalyst device interfaces support dynamic shots, and no longer parses the device init op's attribute dictionary for a static shots literal.
[(#1017)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1017)

* Update the logic for enabling `grad_on_execution` during device execution.
[(#1016)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1016)

* Reduce flaky test and increase test shots count.
[(#1015)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1015)

* Update the logic for enabling `grad_on_execution` during device execution.
[(#1016)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1016)
* Add Exact Tensor Network cpp binding.
[(#1014)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1014/)

* Reverse Lightning Qubit generators vector insertion order.
[(#1009)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1009)
Expand Down Expand Up @@ -78,11 +84,17 @@

### Documentation

* Add the exact tensor network to the Lightning-Tensor docs.
[(#1021)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1021)

* Update Lightning-Tensor installation docs and usage suggestions.
[(#979)](https://github.com/PennyLaneAI/pennylane-lightning/pull/979)

### Bug fixes

* Fix Lightning Kokkos `[[maybe_unused]]` and `exp2` errors with hipcc.
[(#1018)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1018)

* Pin `jax[cpu]==0.4.28` for compatibility with PennyLane and Catalyst.
[(#1019)](https://github.com/PennyLaneAI/pennylane-lightning/pull/1019)

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests_gpu_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ jobs:
run: |
rm -rf build
PL_BACKEND=lightning_qubit python scripts/configure_pyproject_toml.py || true
PL_BACKEND=lightning_qubit SKIP_COMPILATION=True python -m pip install . -vv
PL_BACKEND=lightning_qubit python -m pip install . -vv
rm -rf build
PL_BACKEND=${{ matrix.pl_backend }} python scripts/configure_pyproject_toml.py || true
Expand Down
41 changes: 23 additions & 18 deletions doc/lightning_tensor/device.rst
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
Lightning Tensor device
=======================

The ``lightning.tensor`` device is a tensor network simulator device. The device is built on top of the `cutensornet <https://docs.nvidia.com/cuda/cuquantum/latest/cutensornet/index.html>`__ from the NVIDIA cuQuantum SDK, enabling GPU-accelerated simulation of quantum tensor network evolution. This device is designed to simulate large-scale quantum circuits using tensor networks. For small circuits, state-vector simulator plugins may be more suitable.
The ``lightning.tensor`` device is a tensor network simulator, supporting both the Matrix Product State (MPS) and Exact Tensor Network methods. The device is built on top of the `cutensornet <https://docs.nvidia.com/cuda/cuquantum/latest/cutensornet/index.html>`__ from the NVIDIA cuQuantum SDK, enabling GPU-accelerated simulation of quantum tensor network evolution. This device is designed to simulate large-scale quantum circuits using tensor networks. For small circuits, state-vector simulator plugins may be more suitable.

A ``lightning.tensor`` device can be loaded simply using:
The ``lightning.tensor`` device defaults to the Matrix Product State (MPS) method, and can be loaded using:

.. code-block:: python
import pennylane as qml
dev = qml.device("lightning.tensor", wires=100)
By default, the device represents the quantum state approximated as a Matrix Product State (MPS).
By default, the device approximates the quantum state using an MPS.
The default setup for the MPS tensor network approximation is:
- ``max_bond_dim`` (maximum bond dimension) defaults to ``128`` .
- ``cutoff`` (singular value truncation threshold) defaults to ``0`` .
- ``cutoff_mode`` (singular value truncation mode) defaults to ``abs`` , considering the absolute values of the singular values; Alternatively, users can opt to set ``cutoff_mode`` to ``rel`` to consider the relative values of the singular values.
Note that the ``cutensornet`` will automatically determine the reduced extent of the bond dimension based on the lowest among the multiple truncation cutoffs (``max_bond_dim``, ``cutoff-abs`` and ``cutoff-rel``). For more details on how the ``cutoff`` works, please check it out the `cuQuantum documentation <https://docs.nvidia.com/cuda/cuquantum/latest/cutensornet/api/types.html#cutensornettensorsvdconfigattributes-t>`__.
Note that the ``cutensornet`` will automatically determine the reduced extent of the bond dimension based on the lowest among the multiple truncation cutoffs (``max_bond_dim``, ``cutoff-abs`` and ``cutoff-rel``). For more details on how the ``cutoff`` works, please check the `cuQuantum documentation <https://docs.nvidia.com/cuda/cuquantum/latest/cutensornet/api/types.html#cutensornettensorsvdconfigattributes-t>`__.

The ``lightning.tensor`` device dispatches all operations to be performed on a CUDA-capable GPU of generation SM 7.0 (Volta)
and greater. This device supports both exact and finite shots measurements. Currently, the supported differentiation methods are parameter-shift and finite-diff. Note that the MPS backend of lightning.tensor supports multi-wire gates via Matrix Product Operators (MPO).

The ``lightning.tensor`` device is designed for expectation value calculations. Measurements of ``qml.probs()`` or ``qml.state()`` return dense vectors of dimension :math:`2^{n_\text{qubits}}`, so they should only be used for small systems.

.. note:: ``qml.Hermitian`` is currently only supported for single wires. You can use ``qml.pauli_decompose`` on smaller matrices to obtain a compatible Pauli decomposition in the meantime.

Users also have the flexibility to customize these parameters according to their specific needs with:
Users also have the flexibility to customize MPS parameters according to their specific needs with:

.. code-block:: python
import pennylane as qml
import numpy as np
num_qubits = 100
Expand All @@ -41,7 +33,21 @@ Users also have the flexibility to customize these parameters according to their
dev = qml.device("lightning.tensor", wires=num_qubits, method="mps", **device_kwargs_mps)
The ``lightning.tensor`` device allows users to get quantum circuit gradients using the ``parameter-shift`` method. This can be enabled at the PennyLane ``QNode`` level with:
Users can also run the ``lightning.tensor`` device in the **Exact Tensor Network** mode by setting the ``method`` argument to ``"tn"``:

.. code-block:: python
import pennylane as qml
dev = qml.device("lightning.tensor", wires=100, method="tn")
The lightning.tensor device dispatches all operations to be performed on a CUDA-capable GPU of generation SM 7.0+ (Volta and later)
and greater. This device supports both exact and finite shots measurements. Currently, the supported differentiation methods are parameter-shift and finite-diff. Note that the MPS backend of ``lightning.tensor`` supports multi-wire gates via Matrix Product Operators (MPO).

The ``lightning.tensor`` device is designed for expectation value calculations. Measurements of :func:`~pennylane.probs` or :func:`~pennylane.state` return dense vectors of dimension :math:`2^{\text{n_qubits}}`, so they should only be used for small systems.

.. note:: Currently only single-wire :class:`~pennylane.Hermitian` observables are supported. You can use :func:`~pennylane.pauli_decompose` on smaller matrices to obtain a compatible Pauli decomposition in the meantime.

The ``lightning.tensor`` device allows users to get quantum circuit gradients using the :func:`~pennylane.gradients.param_shift` method. This can be enabled at the PennyLane :class:`~pennylane.QNode` level with:

.. code-block:: python
Expand All @@ -59,7 +65,7 @@ Note that as ``lightning.tensor`` cannot be cleaned up like other state-vector d
Operations and observables support
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The "lightning.tensor" supports all gate operations supported by PennyLane.
The ``lightning.tensor`` supports all gate operations supported by PennyLane, with the exception of :class:`~pennylane.StatePrep`, which is *not supported* by the *Exact Tensor Network* method.

**Supported operations:**

Expand Down Expand Up @@ -128,9 +134,9 @@ The "lightning.tensor" supports all gate operations supported by PennyLane.

**Supported observables:**

The ``lightning.tensor`` supports all observables supported by the Lightning state-vector simulators, besides ``qml.SparseHamiltonian``, ``qml.Projector`` and limited support to ``qml.Hamiltonian``, ``qml.Prod`` since ``lightning.tensor`` only supports 1-wire Hermitian observables.
The ``lightning.tensor`` supports all observables supported by the Lightning state-vector simulators, besides :class:`~pennylane.SparseHamiltonian`, :class:`~pennylane.Projector` and limited support to :class:`~pennylane.ops.op_math.Sum`, :class:`~pennylane.ops.op_math.Prod` since ``lightning.tensor`` only supports 1-wire :class:`~pennylane.Hermitian` observables.

Users can not create a ``Hamiltonian`` or ``Prod`` observable from ``Hamiltonian`` observables.
Users cannot create a :class:`~pennylane.ops.op_math.Sum` observable or a :class:`~pennylane.ops.op_math.Prod` observable from :class:`~pennylane.ops.op_math.Sum` observables.



Expand All @@ -143,7 +149,6 @@ Users can not create a ``Hamiltonian`` or ``Prod`` observable from ``Hamiltonian

~pennylane.ops.op_math.Exp
~pennylane.Hadamard
~pennylane.Hamiltonian
~pennylane.Hermitian
~pennylane.Identity
~pennylane.PauliX
Expand Down
120 changes: 83 additions & 37 deletions pennylane_lightning/core/_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,18 @@ class QuantumScriptSerializer:
use_csingle (bool): whether to use np.complex64 instead of np.complex128
use_mpi (bool, optional): If using MPI to accelerate calculation. Defaults to False.
split_obs (Union[bool, int], optional): If splitting the observables in a list. Defaults to False.
tensor_backend (str): If using `lightning.tensor` and select the TensorNetwork backend, mps or exact. Default to ''
"""

# pylint: disable=import-outside-toplevel, too-many-instance-attributes, c-extension-no-member, too-many-branches, too-many-statements
# pylint: disable=import-outside-toplevel, too-many-instance-attributes, c-extension-no-member, too-many-branches, too-many-statements too-many-positional-arguments too-many-arguments
def __init__(
self, device_name, use_csingle: bool = False, use_mpi: bool = False, split_obs: bool = False
self,
device_name,
use_csingle: bool = False,
use_mpi: bool = False,
split_obs: bool = False,
tensor_backend: str = str(),
):
self.use_csingle = use_csingle
self.device_name = device_name
Expand Down Expand Up @@ -95,43 +101,14 @@ def __init__(
else:
raise DeviceError(f'The device name "{device_name}" is not a valid option.')

if device_name == "lightning.tensor":
self.tensornetwork_c64 = lightning_ops.TensorNetC64
self.tensornetwork_c128 = lightning_ops.TensorNetC128
else:
self.statevector_c64 = lightning_ops.StateVectorC64
self.statevector_c128 = lightning_ops.StateVectorC128

self.named_obs_c64 = lightning_ops.observables.NamedObsC64
self.named_obs_c128 = lightning_ops.observables.NamedObsC128
self.hermitian_obs_c64 = lightning_ops.observables.HermitianObsC64
self.hermitian_obs_c128 = lightning_ops.observables.HermitianObsC128
self.tensor_prod_obs_c64 = lightning_ops.observables.TensorProdObsC64
self.tensor_prod_obs_c128 = lightning_ops.observables.TensorProdObsC128
self.hamiltonian_c64 = lightning_ops.observables.HamiltonianC64
self.hamiltonian_c128 = lightning_ops.observables.HamiltonianC128

if device_name != "lightning.tensor":
self.sparse_hamiltonian_c64 = lightning_ops.observables.SparseHamiltonianC64
self.sparse_hamiltonian_c128 = lightning_ops.observables.SparseHamiltonianC128

self._use_mpi = use_mpi

if self._use_mpi:
self.statevector_mpi_c64 = lightning_ops.StateVectorMPIC64
self.statevector_mpi_c128 = lightning_ops.StateVectorMPIC128
self.named_obs_mpi_c64 = lightning_ops.observablesMPI.NamedObsMPIC64
self.named_obs_mpi_c128 = lightning_ops.observablesMPI.NamedObsMPIC128
self.hermitian_obs_mpi_c64 = lightning_ops.observablesMPI.HermitianObsMPIC64
self.hermitian_obs_mpi_c128 = lightning_ops.observablesMPI.HermitianObsMPIC128
self.tensor_prod_obs_mpi_c64 = lightning_ops.observablesMPI.TensorProdObsMPIC64
self.tensor_prod_obs_mpi_c128 = lightning_ops.observablesMPI.TensorProdObsMPIC128
self.hamiltonian_mpi_c64 = lightning_ops.observablesMPI.HamiltonianMPIC64
self.hamiltonian_mpi_c128 = lightning_ops.observablesMPI.HamiltonianMPIC128
self.sparse_hamiltonian_mpi_c64 = lightning_ops.observablesMPI.SparseHamiltonianMPIC64
self.sparse_hamiltonian_mpi_c128 = lightning_ops.observablesMPI.SparseHamiltonianMPIC128

self._mpi_manager = lightning_ops.MPIManager
if device_name in ["lightning.qubit", "lightning.kokkos", "lightning.gpu"]:
assert tensor_backend == str()
self._set_lightning_state_bindings(lightning_ops)
else:
self._tensor_backend = tensor_backend
self._set_lightning_tensor_bindings(tensor_backend, lightning_ops)

@property
def ctype(self):
Expand Down Expand Up @@ -193,6 +170,75 @@ def sparse_hamiltonian_obs(self):
)
return self.sparse_hamiltonian_c64 if self.use_csingle else self.sparse_hamiltonian_c128

def _set_lightning_state_bindings(self, lightning_ops):
"""Define the variables needed to access the modules from the C++ bindings for state vector."""

self.statevector_c64 = lightning_ops.StateVectorC64
self.statevector_c128 = lightning_ops.StateVectorC128

self.named_obs_c64 = lightning_ops.observables.NamedObsC64
self.named_obs_c128 = lightning_ops.observables.NamedObsC128
self.hermitian_obs_c64 = lightning_ops.observables.HermitianObsC64
self.hermitian_obs_c128 = lightning_ops.observables.HermitianObsC128
self.tensor_prod_obs_c64 = lightning_ops.observables.TensorProdObsC64
self.tensor_prod_obs_c128 = lightning_ops.observables.TensorProdObsC128
self.hamiltonian_c64 = lightning_ops.observables.HamiltonianC64
self.hamiltonian_c128 = lightning_ops.observables.HamiltonianC128

self.sparse_hamiltonian_c64 = lightning_ops.observables.SparseHamiltonianC64
self.sparse_hamiltonian_c128 = lightning_ops.observables.SparseHamiltonianC128

if self._use_mpi:
self.statevector_mpi_c64 = lightning_ops.StateVectorMPIC64
self.statevector_mpi_c128 = lightning_ops.StateVectorMPIC128

self.named_obs_mpi_c64 = lightning_ops.observablesMPI.NamedObsMPIC64
self.named_obs_mpi_c128 = lightning_ops.observablesMPI.NamedObsMPIC128
self.hermitian_obs_mpi_c64 = lightning_ops.observablesMPI.HermitianObsMPIC64
self.hermitian_obs_mpi_c128 = lightning_ops.observablesMPI.HermitianObsMPIC128
self.tensor_prod_obs_mpi_c64 = lightning_ops.observablesMPI.TensorProdObsMPIC64
self.tensor_prod_obs_mpi_c128 = lightning_ops.observablesMPI.TensorProdObsMPIC128
self.hamiltonian_mpi_c64 = lightning_ops.observablesMPI.HamiltonianMPIC64
self.hamiltonian_mpi_c128 = lightning_ops.observablesMPI.HamiltonianMPIC128

self.sparse_hamiltonian_mpi_c64 = lightning_ops.observablesMPI.SparseHamiltonianMPIC64
self.sparse_hamiltonian_mpi_c128 = lightning_ops.observablesMPI.SparseHamiltonianMPIC128

self._mpi_manager = lightning_ops.MPIManager

def _set_lightning_tensor_bindings(self, tensor_backend, lightning_ops):
"""Define the variables needed to access the modules from the C++ bindings for tensor network."""
if tensor_backend == "mps":
self.tensornetwork_c64 = lightning_ops.mpsTensorNetC64
self.tensornetwork_c128 = lightning_ops.mpsTensorNetC128

self.named_obs_c64 = lightning_ops.observables.mpsNamedObsC64
self.named_obs_c128 = lightning_ops.observables.mpsNamedObsC128
self.hermitian_obs_c64 = lightning_ops.observables.mpsHermitianObsC64
self.hermitian_obs_c128 = lightning_ops.observables.mpsHermitianObsC128
self.tensor_prod_obs_c64 = lightning_ops.observables.mpsTensorProdObsC64
self.tensor_prod_obs_c128 = lightning_ops.observables.mpsTensorProdObsC128
self.hamiltonian_c64 = lightning_ops.observables.mpsHamiltonianC64
self.hamiltonian_c128 = lightning_ops.observables.mpsHamiltonianC128

elif tensor_backend == "tn":
self.tensornetwork_c64 = lightning_ops.exactTensorNetC64
self.tensornetwork_c128 = lightning_ops.exactTensorNetC128

self.named_obs_c64 = lightning_ops.observables.exactNamedObsC64
self.named_obs_c128 = lightning_ops.observables.exactNamedObsC128
self.hermitian_obs_c64 = lightning_ops.observables.exactHermitianObsC64
self.hermitian_obs_c128 = lightning_ops.observables.exactHermitianObsC128
self.tensor_prod_obs_c64 = lightning_ops.observables.exactTensorProdObsC64
self.tensor_prod_obs_c128 = lightning_ops.observables.exactTensorProdObsC128
self.hamiltonian_c64 = lightning_ops.observables.exactHamiltonianC64
self.hamiltonian_c128 = lightning_ops.observables.exactHamiltonianC128

else:
raise ValueError(
f"Unsupported method: {tensor_backend}. Supported methods are 'mps' (Matrix Product State) and 'tn' (Exact Tensor Network)."
)

def _named_obs(self, observable, wires_map: dict = None):
"""Serializes a Named observable"""
wires = [wires_map[w] for w in observable.wires] if wires_map else observable.wires.tolist()
Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/core/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.40.0-dev33"
__version__ = "0.40.0-dev36"
2 changes: 1 addition & 1 deletion pennylane_lightning/core/src/bindings/Bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,6 @@ PYBIND11_MODULE(
// Register bindings for backend-specific info:
registerBackendSpecificInfo(m);

registerLightningTensorClassBindings<TensorNetBackends>(m);
registerLightningTensorClassBindings<TensorNetworkBackends>(m);
}
#endif
Loading

0 comments on commit c1206e7

Please sign in to comment.