Skip to content

Commit

Permalink
Finalize documentation for the default.tensor device (#5719)
Browse files Browse the repository at this point in the history
**Context:** We finalize the documentation for the new `default.tensor`
device, introduced in #5699.

**Description of the Change:** As above.

**Benefits:** Documentations with usage examples are required to show
users how to use the new quantum device.

**Possible Drawbacks:** None, as we are simply adding documentation to
an existing quantum device.

**Related GitHub Issues:** None.

**Related Shortcut Story**
[sc-62925]

---------

Co-authored-by: albi3ro <chrissie.c.l@gmail.com>
  • Loading branch information
PietropaoloFrisoni and albi3ro authored May 29, 2024
1 parent f5b805b commit 9d6a846
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 14 deletions.
3 changes: 3 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@

<h3>Documentation 📝</h3>

* The documentation for the `default.tensor` device has been added.
[(#5719)](https://github.com/PennyLaneAI/pennylane/pull/5719)

* A small typo was fixed in the docstring for `qml.sample`.
[(#5685)](https://github.com/PennyLaneAI/pennylane/pull/5685)

Expand Down
3 changes: 3 additions & 0 deletions pennylane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ def device(name, *args, **kwargs):
* :mod:`'default.clifford' <pennylane.devices.default_clifford>`: an efficient
simulator of Clifford circuits.
* :mod:`'default.tensor' <pennylane.devices.default_tensor>`: a simulator
of quantum circuits based on tensor networks.
Additional devices are supported through plugins — see
the `available plugins <https://pennylane.ai/plugins.html>`_ for more
details. To list all currently installed devices, run
Expand Down
1 change: 1 addition & 0 deletions pennylane/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
default_qutrit
default_qutrit_mixed
default_clifford
default_tensor
null_qubit
tests
Expand Down
112 changes: 98 additions & 14 deletions pennylane/devices/default_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module contains the default.tensor device to perform tensor network simulation of a quantum circuit using ``quimb``.
This module contains the default.tensor device to perform tensor network simulations of quantum circuits using ``quimb``.
"""
import copy
from dataclasses import replace
Expand Down Expand Up @@ -144,24 +144,104 @@ def accepted_observables(obs: qml.operation.Operator) -> bool:
@simulator_tracking
@single_tape_support
class DefaultTensor(Device):
"""A PennyLane device to perform tensor network operations on a quantum circuit using
"""A PennyLane device to perform tensor network simulations of quantum circuits using
`quimb <https://github.com/jcmgray/quimb/>`_.
This device is designed to simulate large-scale quantum circuits using tensor networks. For small circuits, other devices like ``default.qubit`` may be more suitable.
The backend uses the ``quimb`` library to perform the tensor network operations, and different methods can be used to simulate the quantum circuit.
Currently, only the Matrix Product State (MPS) method is supported, based on ``quimb``'s ``CircuitMPS`` class.
This device does not currently support finite shots or differentiation.
The currently supported measurement types are expectation values and variances.
Args:
wires (int, Iterable[Number, str]): Number of wires present on the device, or iterable that
contains unique labels for the wires as numbers (i.e., ``[-1, 0, 2]``) or strings
(``['aux_wire', 'q1', 'q2']``).
method (str): Supported method. Currently, only ``"mps"`` is supported.
dtype (type): Datatype for the tensor representation. Must be one of ``np.complex64`` or ``np.complex128``.
Default is ``np.complex128``.
**kwargs: keyword arguments. The following options are currently supported:
``max_bond_dim`` (int): Maximum bond dimension for the MPS simulator.
It corresponds to the number of Schmidt coefficients retained at the end of the SVD algorithm when applying gates. Default is ``None``.
``cutoff`` (float): Truncation threshold for the Schmidt coefficients in a MPS simulator. Default is ``np.finfo(dtype).eps``.
``contract`` (str): The contraction method for applying gates. It can be either ``auto-mps`` or ``nonlocal``.
``nonlocal`` turns each gate into a MPO and applies it directly to the MPS, while ``auto-mps`` swaps nonlocal qubits in 2-qubit gates to be next
to each other before applying the gate, then swaps them back. Default is ``auto-mps``.
dtype (type): Data type for the tensor representation. Must be one of ``np.complex64`` or ``np.complex128``.
**kwargs: keyword arguments for the device, passed to the ``quimb`` backend.
Keyword Args:
max_bond_dim (int): Maximum bond dimension for the MPS method.
It corresponds to the maximum number of Schmidt coefficients retained at the end of the SVD algorithm when applying gates. Default is ``None``.
cutoff (float): Truncation threshold for the Schmidt coefficients in the MPS method. Default is the machine limit for the given tensor data type,
retrieved with the ``numpy.finfo`` function.
contract (str): The contraction method for applying gates in the MPS method. It can be either ``auto-mps`` or ``nonlocal``.
``nonlocal`` turns each gate into a Matrix Product Operator (MPO) and applies it directly to the MPS,
while ``auto-mps`` swaps nonlocal qubits in 2-qubit gates to be next to each other before applying the gate,
then swaps them back. Default is ``auto-mps``.
**Example:**
The following code shows how to create a simple short-depth quantum circuit with 100 qubits using the ``default.tensor`` device.
Depending on the machine, the execution time for this circuit is around 0.3 seconds:
.. code-block:: python
import pennylane as qml
num_qubits = 100
dev = qml.device("default.tensor", wires=num_qubits)
@qml.qnode(dev)
def circuit(num_qubits):
for qubit in range(0, num_qubits - 1):
qml.CZ(wires=[qubit, qubit + 1])
qml.X(wires=[qubit])
qml.Z(wires=[qubit + 1])
return qml.expval(qml.Z(0))
>>> circuit(num_qubits)
tensor(-1., requires_grad=True)
.. details::
:title: Usage Details
We can provide additional keyword arguments to the device to customize the simulation. These are passed to the ``quimb`` backend.
In the following example, we consider a slightly more complex circuit. We use the ``default.tensor`` device with the MPS method,
setting the maximum bond dimension to 100 and the cutoff to 1e-16. We set ``"auto-mps"`` as the contraction technique to apply gates.
.. code-block:: python
import pennylane as qml
import numpy as np
theta = 0.5
phi = 0.1
num_qubits = 50
device_kwargs = {"max_bond_dim": 100, "cutoff": 1e-16, "contract": "auto-mps"}
dev = qml.device("default.tensor", wires=num_qubits, **device_kwargs)
@qml.qnode(dev)
def circuit(theta, phi, num_qubits):
for qubit in range(num_qubits - 4):
qml.X(wires=qubit)
qml.RX(theta, wires=qubit + 1)
qml.CNOT(wires=[qubit, qubit + 1])
qml.DoubleExcitation(phi, wires=[qubit, qubit + 1, qubit + 3, qubit + 4])
qml.CSWAP(wires=[qubit + 1, qubit + 3, qubit + 4])
qml.RY(theta, wires=qubit + 1)
qml.Toffoli(wires=[qubit + 1, qubit + 3, qubit + 4])
return [
qml.expval(qml.Z(0)),
qml.expval(qml.Hamiltonian([np.pi, np.e], [qml.Z(15) @ qml.Y(25), qml.Hadamard(40)])),
qml.var(qml.Y(20)),
]
>>> circuit(theta, phi, num_qubits)
[-0.9953099539219951, 0.0036631029671767208, 0.9999999876072984]
After the first execution, the time to run this circuit for 50 qubits is around 0.5 seconds depending on the machine.
Increasing the number of qubits to 500 brings the execution time to approximately 15 seconds, and for 1000 qubits to around 50 seconds.
The time complexity and the accuracy of the results also depend on the chosen keyword arguments for the device, such as the maximum bond dimension.
The specific structure of the circuit significantly affects how the time complexity and accuracy of the simulation scale with these parameters.
"""

# pylint: disable=too-many-instance-attributes
Expand Down Expand Up @@ -258,7 +338,11 @@ def dtype(self):
return self._dtype

def _reset_state(self) -> None:
"""Reset the MPS."""
"""
Reset the MPS.
This method modifies the tensor state of the device.
"""
self._circuitMPS = qtn.CircuitMPS(psi0=self._initial_mps())

def _initial_mps(self) -> "qtn.MatrixProductState":
Expand Down Expand Up @@ -382,7 +466,7 @@ def simulate(self, circuit: QuantumScript) -> Result:
def _apply_operation(self, op: qml.operation.Operator) -> None:
"""Apply a single operator to the circuit, keeping the state always in a MPS form.
Internally it uses `quimb`'s `apply_gate` method.
Internally it uses `quimb`'s `apply_gate` method. This method modifies the tensor state of the device.
Args:
op (Operator): The operation to apply.
Expand Down

0 comments on commit 9d6a846

Please sign in to comment.