Skip to content

Commit 9d6a846

Browse files
Finalize documentation for the default.tensor device (#5719)
**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>
1 parent f5b805b commit 9d6a846

File tree

4 files changed

+105
-14
lines changed

4 files changed

+105
-14
lines changed

doc/releases/changelog-dev.md

+3
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@
155155

156156
<h3>Documentation 📝</h3>
157157

158+
* The documentation for the `default.tensor` device has been added.
159+
[(#5719)](https://github.com/PennyLaneAI/pennylane/pull/5719)
160+
158161
* A small typo was fixed in the docstring for `qml.sample`.
159162
[(#5685)](https://github.com/PennyLaneAI/pennylane/pull/5685)
160163

pennylane/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ def device(name, *args, **kwargs):
223223
* :mod:`'default.clifford' <pennylane.devices.default_clifford>`: an efficient
224224
simulator of Clifford circuits.
225225
226+
* :mod:`'default.tensor' <pennylane.devices.default_tensor>`: a simulator
227+
of quantum circuits based on tensor networks.
228+
226229
Additional devices are supported through plugins — see
227230
the `available plugins <https://pennylane.ai/plugins.html>`_ for more
228231
details. To list all currently installed devices, run

pennylane/devices/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
default_qutrit
3737
default_qutrit_mixed
3838
default_clifford
39+
default_tensor
3940
null_qubit
4041
tests
4142

pennylane/devices/default_tensor.py

+98-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
"""
15-
This module contains the default.tensor device to perform tensor network simulation of a quantum circuit using ``quimb``.
15+
This module contains the default.tensor device to perform tensor network simulations of quantum circuits using ``quimb``.
1616
"""
1717
import copy
1818
from dataclasses import replace
@@ -144,24 +144,104 @@ def accepted_observables(obs: qml.operation.Operator) -> bool:
144144
@simulator_tracking
145145
@single_tape_support
146146
class DefaultTensor(Device):
147-
"""A PennyLane device to perform tensor network operations on a quantum circuit using
147+
"""A PennyLane device to perform tensor network simulations of quantum circuits using
148148
`quimb <https://github.com/jcmgray/quimb/>`_.
149149
150+
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.
151+
152+
The backend uses the ``quimb`` library to perform the tensor network operations, and different methods can be used to simulate the quantum circuit.
153+
Currently, only the Matrix Product State (MPS) method is supported, based on ``quimb``'s ``CircuitMPS`` class.
154+
155+
This device does not currently support finite shots or differentiation.
156+
The currently supported measurement types are expectation values and variances.
157+
150158
Args:
151159
wires (int, Iterable[Number, str]): Number of wires present on the device, or iterable that
152160
contains unique labels for the wires as numbers (i.e., ``[-1, 0, 2]``) or strings
153161
(``['aux_wire', 'q1', 'q2']``).
154162
method (str): Supported method. Currently, only ``"mps"`` is supported.
155-
dtype (type): Datatype for the tensor representation. Must be one of ``np.complex64`` or ``np.complex128``.
156-
Default is ``np.complex128``.
157-
**kwargs: keyword arguments. The following options are currently supported:
158-
159-
``max_bond_dim`` (int): Maximum bond dimension for the MPS simulator.
160-
It corresponds to the number of Schmidt coefficients retained at the end of the SVD algorithm when applying gates. Default is ``None``.
161-
``cutoff`` (float): Truncation threshold for the Schmidt coefficients in a MPS simulator. Default is ``np.finfo(dtype).eps``.
162-
``contract`` (str): The contraction method for applying gates. It can be either ``auto-mps`` or ``nonlocal``.
163-
``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
164-
to each other before applying the gate, then swaps them back. Default is ``auto-mps``.
163+
dtype (type): Data type for the tensor representation. Must be one of ``np.complex64`` or ``np.complex128``.
164+
**kwargs: keyword arguments for the device, passed to the ``quimb`` backend.
165+
166+
Keyword Args:
167+
max_bond_dim (int): Maximum bond dimension for the MPS method.
168+
It corresponds to the maximum number of Schmidt coefficients retained at the end of the SVD algorithm when applying gates. Default is ``None``.
169+
cutoff (float): Truncation threshold for the Schmidt coefficients in the MPS method. Default is the machine limit for the given tensor data type,
170+
retrieved with the ``numpy.finfo`` function.
171+
contract (str): The contraction method for applying gates in the MPS method. It can be either ``auto-mps`` or ``nonlocal``.
172+
``nonlocal`` turns each gate into a Matrix Product Operator (MPO) and applies it directly to the MPS,
173+
while ``auto-mps`` swaps nonlocal qubits in 2-qubit gates to be next to each other before applying the gate,
174+
then swaps them back. Default is ``auto-mps``.
175+
176+
**Example:**
177+
178+
The following code shows how to create a simple short-depth quantum circuit with 100 qubits using the ``default.tensor`` device.
179+
Depending on the machine, the execution time for this circuit is around 0.3 seconds:
180+
181+
.. code-block:: python
182+
183+
import pennylane as qml
184+
185+
num_qubits = 100
186+
187+
dev = qml.device("default.tensor", wires=num_qubits)
188+
189+
@qml.qnode(dev)
190+
def circuit(num_qubits):
191+
for qubit in range(0, num_qubits - 1):
192+
qml.CZ(wires=[qubit, qubit + 1])
193+
qml.X(wires=[qubit])
194+
qml.Z(wires=[qubit + 1])
195+
return qml.expval(qml.Z(0))
196+
197+
>>> circuit(num_qubits)
198+
tensor(-1., requires_grad=True)
199+
200+
201+
.. details::
202+
:title: Usage Details
203+
204+
We can provide additional keyword arguments to the device to customize the simulation. These are passed to the ``quimb`` backend.
205+
206+
In the following example, we consider a slightly more complex circuit. We use the ``default.tensor`` device with the MPS method,
207+
setting the maximum bond dimension to 100 and the cutoff to 1e-16. We set ``"auto-mps"`` as the contraction technique to apply gates.
208+
209+
.. code-block:: python
210+
211+
import pennylane as qml
212+
import numpy as np
213+
214+
theta = 0.5
215+
phi = 0.1
216+
num_qubits = 50
217+
device_kwargs = {"max_bond_dim": 100, "cutoff": 1e-16, "contract": "auto-mps"}
218+
219+
dev = qml.device("default.tensor", wires=num_qubits, **device_kwargs)
220+
221+
@qml.qnode(dev)
222+
def circuit(theta, phi, num_qubits):
223+
for qubit in range(num_qubits - 4):
224+
qml.X(wires=qubit)
225+
qml.RX(theta, wires=qubit + 1)
226+
qml.CNOT(wires=[qubit, qubit + 1])
227+
qml.DoubleExcitation(phi, wires=[qubit, qubit + 1, qubit + 3, qubit + 4])
228+
qml.CSWAP(wires=[qubit + 1, qubit + 3, qubit + 4])
229+
qml.RY(theta, wires=qubit + 1)
230+
qml.Toffoli(wires=[qubit + 1, qubit + 3, qubit + 4])
231+
return [
232+
qml.expval(qml.Z(0)),
233+
qml.expval(qml.Hamiltonian([np.pi, np.e], [qml.Z(15) @ qml.Y(25), qml.Hadamard(40)])),
234+
qml.var(qml.Y(20)),
235+
]
236+
237+
>>> circuit(theta, phi, num_qubits)
238+
[-0.9953099539219951, 0.0036631029671767208, 0.9999999876072984]
239+
240+
After the first execution, the time to run this circuit for 50 qubits is around 0.5 seconds depending on the machine.
241+
Increasing the number of qubits to 500 brings the execution time to approximately 15 seconds, and for 1000 qubits to around 50 seconds.
242+
243+
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.
244+
The specific structure of the circuit significantly affects how the time complexity and accuracy of the simulation scale with these parameters.
165245
"""
166246

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

260340
def _reset_state(self) -> None:
261-
"""Reset the MPS."""
341+
"""
342+
Reset the MPS.
343+
344+
This method modifies the tensor state of the device.
345+
"""
262346
self._circuitMPS = qtn.CircuitMPS(psi0=self._initial_mps())
263347

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

0 commit comments

Comments
 (0)