pennylane-lightning-tensor 0.42.0__cp313-cp313-manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pennylane_lightning/lightning_tensor/__init__.py +18 -0
- pennylane_lightning/lightning_tensor/_measurements.py +426 -0
- pennylane_lightning/lightning_tensor/_tensornet.py +787 -0
- pennylane_lightning/lightning_tensor/lightning_tensor.py +615 -0
- pennylane_lightning/lightning_tensor_ops.cpython-313-aarch64-linux-gnu.so +0 -0
- pennylane_lightning_tensor-0.42.0.dist-info/METADATA +220 -0
- pennylane_lightning_tensor-0.42.0.dist-info/RECORD +12 -0
- pennylane_lightning_tensor-0.42.0.dist-info/WHEEL +5 -0
- pennylane_lightning_tensor-0.42.0.dist-info/entry_points.txt +2 -0
- pennylane_lightning_tensor-0.42.0.dist-info/licenses/LICENSE +212 -0
- pennylane_lightning_tensor-0.42.0.dist-info/top_level.txt +2 -0
- pennylane_lightning_tensor.libs/libgomp-98df74fd.so.1.0.0 +0 -0
@@ -0,0 +1,615 @@
|
|
1
|
+
# Copyright 2024 Xanadu Quantum Technologies Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
"""
|
15
|
+
This module contains the LightningTensor class that inherits from the new device interface.
|
16
|
+
It is a device to perform tensor network simulations of quantum circuits using `cutensornet`.
|
17
|
+
"""
|
18
|
+
from dataclasses import replace
|
19
|
+
from numbers import Number
|
20
|
+
from typing import Callable, Optional, Sequence, Tuple, Union
|
21
|
+
from warnings import warn
|
22
|
+
|
23
|
+
import numpy as np
|
24
|
+
import pennylane as qml
|
25
|
+
from pennylane.devices import DefaultExecutionConfig, Device, ExecutionConfig
|
26
|
+
from pennylane.devices.modifiers import simulator_tracking, single_tape_support
|
27
|
+
from pennylane.devices.preprocess import (
|
28
|
+
decompose,
|
29
|
+
validate_device_wires,
|
30
|
+
validate_measurements,
|
31
|
+
validate_observables,
|
32
|
+
)
|
33
|
+
from pennylane.operation import Operator
|
34
|
+
from pennylane.tape import QuantumScript, QuantumTape
|
35
|
+
from pennylane.transforms.core import TransformProgram
|
36
|
+
from pennylane.typing import Result, ResultBatch
|
37
|
+
|
38
|
+
from pennylane_lightning.core._version import __version__
|
39
|
+
|
40
|
+
from ._measurements import LightningTensorMeasurements
|
41
|
+
from ._tensornet import LightningTensorNet
|
42
|
+
|
43
|
+
try:
|
44
|
+
# pylint: disable=import-error, unused-import
|
45
|
+
from pennylane_lightning.lightning_tensor_ops import (
|
46
|
+
backend_info,
|
47
|
+
get_gpu_arch,
|
48
|
+
is_gpu_supported,
|
49
|
+
)
|
50
|
+
|
51
|
+
if not is_gpu_supported(): # pragma: no cover
|
52
|
+
raise ValueError(f"CUDA device is an unsupported version: {get_gpu_arch()}")
|
53
|
+
|
54
|
+
LT_CPP_BINARY_AVAILABLE = True
|
55
|
+
|
56
|
+
except ImportError as ex:
|
57
|
+
warn(str(ex), UserWarning)
|
58
|
+
LT_CPP_BINARY_AVAILABLE = False
|
59
|
+
|
60
|
+
Result_or_ResultBatch = Union[Result, ResultBatch]
|
61
|
+
QuantumTapeBatch = Sequence[QuantumTape]
|
62
|
+
QuantumTape_or_Batch = Union[QuantumTape, QuantumTapeBatch]
|
63
|
+
PostprocessingFn = Callable[[ResultBatch], Result_or_ResultBatch]
|
64
|
+
|
65
|
+
|
66
|
+
_backends = frozenset({"cutensornet"})
|
67
|
+
# The set of supported backends.
|
68
|
+
|
69
|
+
_methods = frozenset({"mps", "tn"})
|
70
|
+
# The set of supported methods.
|
71
|
+
|
72
|
+
_operations = frozenset(
|
73
|
+
{
|
74
|
+
"Identity",
|
75
|
+
"BasisState",
|
76
|
+
"MPSPrep",
|
77
|
+
"QubitUnitary",
|
78
|
+
"ControlledQubitUnitary",
|
79
|
+
"DiagonalQubitUnitary",
|
80
|
+
"PauliX",
|
81
|
+
"PauliY",
|
82
|
+
"PauliZ",
|
83
|
+
"Hadamard",
|
84
|
+
"GlobalPhase",
|
85
|
+
"S",
|
86
|
+
"Adjoint(S)",
|
87
|
+
"T",
|
88
|
+
"Adjoint(T)",
|
89
|
+
"SX",
|
90
|
+
"Adjoint(SX)",
|
91
|
+
"CNOT",
|
92
|
+
"SWAP",
|
93
|
+
"ISWAP",
|
94
|
+
"Adjoint(ISWAP)",
|
95
|
+
"PSWAP",
|
96
|
+
"Adjoint(SISWAP)",
|
97
|
+
"SISWAP",
|
98
|
+
"SQISW",
|
99
|
+
"CSWAP",
|
100
|
+
"Toffoli",
|
101
|
+
"CY",
|
102
|
+
"CZ",
|
103
|
+
"PhaseShift",
|
104
|
+
"ControlledPhaseShift",
|
105
|
+
"C(Hadamard)",
|
106
|
+
"C(S)",
|
107
|
+
"C(T)",
|
108
|
+
"C(PhaseShift)",
|
109
|
+
"C(RX)",
|
110
|
+
"C(RY)",
|
111
|
+
"C(RZ)",
|
112
|
+
"C(Rot)",
|
113
|
+
"C(IsingXX)",
|
114
|
+
"C(IsingYY)",
|
115
|
+
"C(IsingZZ)",
|
116
|
+
"C(IsingXY)",
|
117
|
+
"C(SingleExcitation)",
|
118
|
+
"C(SingleExcitationPlus)",
|
119
|
+
"C(SingleExcitationMinus)",
|
120
|
+
"C(DoubleExcitation)",
|
121
|
+
"C(DoubleExcitationMinus)",
|
122
|
+
"C(DoubleExcitationPlus)",
|
123
|
+
"C(GlobalPhase)",
|
124
|
+
"C(MultiRZ)",
|
125
|
+
"RX",
|
126
|
+
"RY",
|
127
|
+
"RZ",
|
128
|
+
"Rot",
|
129
|
+
"CRX",
|
130
|
+
"CRY",
|
131
|
+
"CRZ",
|
132
|
+
"CRot",
|
133
|
+
"IsingXX",
|
134
|
+
"IsingYY",
|
135
|
+
"IsingZZ",
|
136
|
+
"IsingXY",
|
137
|
+
"SingleExcitation",
|
138
|
+
"SingleExcitationPlus",
|
139
|
+
"SingleExcitationMinus",
|
140
|
+
"DoubleExcitation",
|
141
|
+
"DoubleExcitationPlus",
|
142
|
+
"DoubleExcitationMinus",
|
143
|
+
"QubitCarry",
|
144
|
+
"QubitSum",
|
145
|
+
"OrbitalRotation",
|
146
|
+
"ECR",
|
147
|
+
"BlockEncode",
|
148
|
+
"C(BlockEncode)",
|
149
|
+
}
|
150
|
+
)
|
151
|
+
|
152
|
+
_observables = frozenset(
|
153
|
+
{
|
154
|
+
"PauliX",
|
155
|
+
"PauliY",
|
156
|
+
"PauliZ",
|
157
|
+
"Hadamard",
|
158
|
+
"Hermitian",
|
159
|
+
"Identity",
|
160
|
+
"LinearCombination",
|
161
|
+
"Sum",
|
162
|
+
"SProd",
|
163
|
+
"Prod",
|
164
|
+
"Exp",
|
165
|
+
}
|
166
|
+
)
|
167
|
+
# The set of supported observables.
|
168
|
+
|
169
|
+
|
170
|
+
def stopping_condition(op: Operator) -> bool:
|
171
|
+
"""A function that determines whether or not an operation is supported by ``lightning.tensor``."""
|
172
|
+
if isinstance(op, qml.ControlledQubitUnitary):
|
173
|
+
return True
|
174
|
+
|
175
|
+
if isinstance(op, qml.MPSPrep):
|
176
|
+
return True
|
177
|
+
|
178
|
+
if op.name in ("C(SProd)", "C(Exp)"):
|
179
|
+
return True
|
180
|
+
|
181
|
+
return op.has_matrix and op.name in _operations
|
182
|
+
|
183
|
+
|
184
|
+
def simulate(circuit: QuantumScript, tensornet: LightningTensorNet) -> Result:
|
185
|
+
"""Simulate a single quantum script.
|
186
|
+
|
187
|
+
Args:
|
188
|
+
circuit (QuantumTape): The single circuit to simulate
|
189
|
+
tensornet (LightningTensorNet): handle to Lightning tensor network
|
190
|
+
|
191
|
+
Returns:
|
192
|
+
Tuple[TensorLike]: The results of the simulation
|
193
|
+
|
194
|
+
Note that this function can return measurements for non-commuting observables simultaneously.
|
195
|
+
"""
|
196
|
+
tensornet.reset_state()
|
197
|
+
tensornet.set_tensor_network(circuit)
|
198
|
+
return LightningTensorMeasurements(tensornet).measure_tensor_network(circuit)
|
199
|
+
|
200
|
+
|
201
|
+
def accepted_observables(obs: Operator) -> bool:
|
202
|
+
"""A function that determines whether or not an observable is supported by ``lightning.tensor``."""
|
203
|
+
return obs.name in _observables
|
204
|
+
|
205
|
+
|
206
|
+
def accepted_backends(backend: str) -> bool:
|
207
|
+
"""A function that determines whether or not a backend is supported by ``lightning.tensor``."""
|
208
|
+
return backend in _backends
|
209
|
+
|
210
|
+
|
211
|
+
def accepted_methods(method: str) -> bool:
|
212
|
+
"""A function that determines whether or not a method is supported by ``lightning.tensor``."""
|
213
|
+
return method in _methods
|
214
|
+
|
215
|
+
|
216
|
+
@simulator_tracking
|
217
|
+
@single_tape_support
|
218
|
+
class LightningTensor(Device):
|
219
|
+
"""PennyLane Lightning Tensor device.
|
220
|
+
|
221
|
+
A device to perform tensor network operations on a quantum circuit.
|
222
|
+
|
223
|
+
This device is designed to simulate large-scale quantum circuits using tensor network methods. For
|
224
|
+
small circuits, other devices like ``lightning.qubit``, ``lightning.gpu`` or ``lightning.kokkos`` are
|
225
|
+
recommended.
|
226
|
+
|
227
|
+
Currently, the Matrix Product State (MPS) and the Exact Tensor Network methods are supported as implemented in the ``cutensornet`` backend.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
wires (Optional[int, list]): The number of wires to initialize the device with. Defaults to ``None`` if not specified, and the device will allocate the number of wires depending on the circuit to execute.
|
231
|
+
Defaults to ``None`` if not specified.
|
232
|
+
shots (int): Measurements are performed drawing ``shots`` times from a discrete random variable distribution associated with a state vector and an observable. Defaults to ``None`` if not specified. Setting
|
233
|
+
to ``None`` results in computing statistics like expectation values and
|
234
|
+
variances analytically.
|
235
|
+
method (str): Supported method. The supported methods are ``"mps"`` (Matrix Product State) and ``"tn"`` (Exact Tensor Network). Default is ``"mps"``.
|
236
|
+
c_dtype: Datatypes for the tensor representation. Must be one of
|
237
|
+
``numpy.complex64`` or ``numpy.complex128``. Default is ``numpy.complex128``.
|
238
|
+
Keyword Args:
|
239
|
+
max_bond_dim (int): (Only for ``method=mps``) The maximum bond dimension to be used in the MPS simulation. Default is 128.
|
240
|
+
The accuracy of the wavefunction representation comes with a memory tradeoff which can be
|
241
|
+
tuned with `max_bond_dim`. The larger the internal bond dimension, the more entanglement can
|
242
|
+
be described but the larger the memory requirements. Note that GPUs are ill-suited (i.e. less
|
243
|
+
competitive compared with CPUs) for simulating circuits with low bond dimensions and/or circuit
|
244
|
+
layers with a single or few gates because the arithmetic intensity is lower.
|
245
|
+
cutoff (float): (Only for ``method=mps``) The threshold used to truncate the singular values of the MPS tensors. The default is 0.
|
246
|
+
cutoff_mode (str): (Only for ``method=mps``) Singular value truncation mode for MPS tensors. The options are ``"rel"`` and ``"abs"``. Default is ``"abs"``.
|
247
|
+
backend (str): Supported backend. Currently, only ``cutensornet`` is supported. Default is ``cutensornet``.
|
248
|
+
|
249
|
+
**Example for the MPS method**
|
250
|
+
|
251
|
+
.. code-block:: python
|
252
|
+
|
253
|
+
import pennylane as qml
|
254
|
+
|
255
|
+
num_qubits = 100
|
256
|
+
|
257
|
+
dev = qml.device("lightning.tensor", wires=num_qubits, max_bond_dim=32)
|
258
|
+
|
259
|
+
@qml.qnode(dev)
|
260
|
+
def circuit(num_qubits):
|
261
|
+
for qubit in range(0, num_qubits - 1):
|
262
|
+
qml.CZ(wires=[qubit, qubit + 1])
|
263
|
+
qml.X(wires=[qubit])
|
264
|
+
qml.Z(wires=[qubit + 1])
|
265
|
+
return qml.expval(qml.Z(0))
|
266
|
+
|
267
|
+
>>> print(circuit(num_qubits))
|
268
|
+
-1.0
|
269
|
+
|
270
|
+
**Example for the Exact Tensor Network method**
|
271
|
+
|
272
|
+
.. code-block:: python
|
273
|
+
|
274
|
+
import pennylane as qml
|
275
|
+
|
276
|
+
num_qubits = 100
|
277
|
+
|
278
|
+
dev = qml.device("lightning.tensor", wires=num_qubits, method="tn")
|
279
|
+
|
280
|
+
@qml.qnode(dev)
|
281
|
+
def circuit(num_qubits):
|
282
|
+
for qubit in range(0, num_qubits - 1):
|
283
|
+
qml.CZ(wires=[qubit, qubit + 1])
|
284
|
+
qml.X(wires=[qubit])
|
285
|
+
qml.Z(wires=[qubit + 1])
|
286
|
+
return qml.expval(qml.Z(0))
|
287
|
+
|
288
|
+
>>> print(circuit(num_qubits))
|
289
|
+
-1.0
|
290
|
+
"""
|
291
|
+
|
292
|
+
# pylint: disable=too-many-instance-attributes
|
293
|
+
pennylane_requires = ">=0.41"
|
294
|
+
version = __version__
|
295
|
+
|
296
|
+
_device_options = {
|
297
|
+
"mps": ("backend", "max_bond_dim", "cutoff", "cutoff_mode"),
|
298
|
+
"tn": ("backend"),
|
299
|
+
}
|
300
|
+
|
301
|
+
_CPP_BINARY_AVAILABLE = LT_CPP_BINARY_AVAILABLE
|
302
|
+
|
303
|
+
# TODO: Move supported ops/obs to TOML file
|
304
|
+
operations = _operations
|
305
|
+
# The names of the supported operations.
|
306
|
+
|
307
|
+
observables = _observables
|
308
|
+
# The names of the supported observables.
|
309
|
+
|
310
|
+
# pylint: disable=too-many-arguments,too-many-branches
|
311
|
+
def __init__(
|
312
|
+
self,
|
313
|
+
*,
|
314
|
+
wires=None,
|
315
|
+
shots=None,
|
316
|
+
method: str = "mps",
|
317
|
+
c_dtype=np.complex128,
|
318
|
+
**kwargs,
|
319
|
+
):
|
320
|
+
if not self._CPP_BINARY_AVAILABLE:
|
321
|
+
raise ImportError("Pre-compiled binaries for lightning.tensor are not available. ")
|
322
|
+
|
323
|
+
if not accepted_methods(method):
|
324
|
+
raise ValueError(
|
325
|
+
f"Unsupported method: {method}. Supported methods are 'mps' (Matrix Product State) and 'tn' (Exact Tensor Network)."
|
326
|
+
)
|
327
|
+
|
328
|
+
if c_dtype not in [np.complex64, np.complex128]: # pragma: no cover
|
329
|
+
raise TypeError(f"Unsupported complex type: {c_dtype}")
|
330
|
+
|
331
|
+
super().__init__(wires=wires, shots=shots)
|
332
|
+
|
333
|
+
if isinstance(wires, int) or wires is None:
|
334
|
+
self._wire_map = None # should just use wires as is
|
335
|
+
else:
|
336
|
+
self._wire_map = {w: i for i, w in enumerate(self.wires)}
|
337
|
+
|
338
|
+
self._num_wires = len(self.wires) if self.wires else None
|
339
|
+
self._method = method
|
340
|
+
self._c_dtype = c_dtype
|
341
|
+
|
342
|
+
self._backend = kwargs.get("backend", "cutensornet")
|
343
|
+
|
344
|
+
for arg in kwargs:
|
345
|
+
if arg not in self._device_options[self._method]:
|
346
|
+
raise TypeError(
|
347
|
+
f"Unexpected argument: {arg} during initialization of the lightning.tensor device."
|
348
|
+
)
|
349
|
+
|
350
|
+
if not accepted_backends(self._backend):
|
351
|
+
raise ValueError(f"Unsupported backend: {self._backend}")
|
352
|
+
if self._method == "mps":
|
353
|
+
self._max_bond_dim = kwargs.get("max_bond_dim", 128)
|
354
|
+
self._cutoff = kwargs.get("cutoff", 0)
|
355
|
+
self._cutoff_mode = kwargs.get("cutoff_mode", "abs")
|
356
|
+
|
357
|
+
if not isinstance(self._max_bond_dim, int) or self._max_bond_dim < 1:
|
358
|
+
raise ValueError("The maximum bond dimension must be an integer greater than 0.")
|
359
|
+
if not isinstance(self._cutoff, (int, float)) or self._cutoff < 0:
|
360
|
+
raise ValueError("The cutoff must be a non-negative number.")
|
361
|
+
if self._cutoff_mode not in ["rel", "abs"]:
|
362
|
+
raise ValueError(f"Unsupported cutoff mode: {self._cutoff_mode}")
|
363
|
+
|
364
|
+
@property
|
365
|
+
def name(self):
|
366
|
+
"""The name of the device."""
|
367
|
+
return "lightning.tensor"
|
368
|
+
|
369
|
+
@property
|
370
|
+
def num_wires(self):
|
371
|
+
"""Number of wires addressed on this device."""
|
372
|
+
return self._num_wires
|
373
|
+
|
374
|
+
@property
|
375
|
+
def backend(self):
|
376
|
+
"""Supported backend."""
|
377
|
+
return self._backend
|
378
|
+
|
379
|
+
@property
|
380
|
+
def method(self):
|
381
|
+
"""Supported method."""
|
382
|
+
return self._method
|
383
|
+
|
384
|
+
@property
|
385
|
+
def c_dtype(self):
|
386
|
+
"""Tensor complex data type."""
|
387
|
+
return self._c_dtype
|
388
|
+
|
389
|
+
def _tensornet(self, num_wires):
|
390
|
+
"""Return the tensornet object."""
|
391
|
+
if self.method == "mps":
|
392
|
+
return LightningTensorNet(
|
393
|
+
num_wires,
|
394
|
+
self._method,
|
395
|
+
self._c_dtype,
|
396
|
+
device_name=self.name,
|
397
|
+
max_bond_dim=self._max_bond_dim,
|
398
|
+
cutoff=self._cutoff,
|
399
|
+
cutoff_mode=self._cutoff_mode,
|
400
|
+
)
|
401
|
+
return LightningTensorNet(num_wires, self._method, self._c_dtype, device_name=self.name)
|
402
|
+
|
403
|
+
dtype = c_dtype
|
404
|
+
|
405
|
+
def _setup_execution_config(
|
406
|
+
self, config: Optional[ExecutionConfig] = DefaultExecutionConfig
|
407
|
+
) -> ExecutionConfig:
|
408
|
+
"""
|
409
|
+
Update the execution config with choices for how the device should be used and the device options.
|
410
|
+
"""
|
411
|
+
# TODO: add options for gradients next quarter
|
412
|
+
|
413
|
+
updated_values = {}
|
414
|
+
|
415
|
+
new_device_options = dict(config.device_options)
|
416
|
+
for option in self._device_options[self.method]:
|
417
|
+
if option not in new_device_options:
|
418
|
+
new_device_options[option] = getattr(self, f"_{option}", None)
|
419
|
+
|
420
|
+
return replace(config, **updated_values, device_options=new_device_options)
|
421
|
+
|
422
|
+
def dynamic_wires_from_circuit(self, circuit):
|
423
|
+
"""Map circuit wires to Pennylane ``default.qubit`` standard wire order.
|
424
|
+
|
425
|
+
Args:
|
426
|
+
circuit (QuantumTape): The circuit to execute.
|
427
|
+
|
428
|
+
Returns:
|
429
|
+
QuantumTape: The updated circuit with the wires mapped to the standard wire order.
|
430
|
+
"""
|
431
|
+
|
432
|
+
return circuit.map_to_standard_wires() if self.num_wires is None else circuit
|
433
|
+
|
434
|
+
def preprocess(
|
435
|
+
self,
|
436
|
+
execution_config: ExecutionConfig = DefaultExecutionConfig,
|
437
|
+
):
|
438
|
+
"""This function defines the device transform program to be applied and an updated device configuration.
|
439
|
+
|
440
|
+
Args:
|
441
|
+
execution_config (Union[ExecutionConfig, Sequence[ExecutionConfig]]): A data structure describing the
|
442
|
+
parameters needed to fully describe the execution.
|
443
|
+
|
444
|
+
Returns:
|
445
|
+
TransformProgram, ExecutionConfig: A transform program that when called returns :class:`~.QuantumTape`'s that the
|
446
|
+
device can natively execute as well as a postprocessing function to be called after execution, and a configuration
|
447
|
+
with unset specifications filled in.
|
448
|
+
|
449
|
+
This device currently:
|
450
|
+
|
451
|
+
* Does not support derivatives.
|
452
|
+
* Does not support vector-Jacobian products.
|
453
|
+
"""
|
454
|
+
|
455
|
+
config = self._setup_execution_config(execution_config)
|
456
|
+
|
457
|
+
program = TransformProgram()
|
458
|
+
|
459
|
+
program.add_transform(validate_measurements, name=self.name)
|
460
|
+
program.add_transform(validate_observables, accepted_observables, name=self.name)
|
461
|
+
program.add_transform(validate_device_wires, self._wires, name=self.name)
|
462
|
+
program.add_transform(
|
463
|
+
decompose,
|
464
|
+
stopping_condition=stopping_condition,
|
465
|
+
stopping_condition_shots=stopping_condition,
|
466
|
+
skip_initial_state_prep=True,
|
467
|
+
name=self.name,
|
468
|
+
)
|
469
|
+
return program, config
|
470
|
+
|
471
|
+
# pylint: disable=unused-argument
|
472
|
+
def execute(
|
473
|
+
self,
|
474
|
+
circuits: QuantumTape_or_Batch,
|
475
|
+
execution_config: ExecutionConfig = DefaultExecutionConfig,
|
476
|
+
) -> Result_or_ResultBatch:
|
477
|
+
"""Execute a circuit or a batch of circuits and turn it into results.
|
478
|
+
|
479
|
+
Args:
|
480
|
+
circuits (Union[QuantumTape, Sequence[QuantumTape]]): the quantum circuits to be executed.
|
481
|
+
execution_config (ExecutionConfig): a data structure with additional information required for execution.
|
482
|
+
|
483
|
+
Returns:
|
484
|
+
TensorLike, tuple[TensorLike], tuple[tuple[TensorLike]]: A numeric result of the computation.
|
485
|
+
"""
|
486
|
+
|
487
|
+
results = []
|
488
|
+
|
489
|
+
for circuit in circuits:
|
490
|
+
if self._wire_map is not None:
|
491
|
+
[circuit], _ = qml.map_wires(circuit, self._wire_map)
|
492
|
+
results.append(
|
493
|
+
simulate(
|
494
|
+
self.dynamic_wires_from_circuit(circuit),
|
495
|
+
self._tensornet(
|
496
|
+
self.num_wires if self.num_wires is not None else circuit.num_wires
|
497
|
+
),
|
498
|
+
)
|
499
|
+
)
|
500
|
+
|
501
|
+
return tuple(results)
|
502
|
+
|
503
|
+
# pylint: disable=unused-argument
|
504
|
+
def supports_derivatives(
|
505
|
+
self,
|
506
|
+
execution_config: Optional[ExecutionConfig] = None,
|
507
|
+
circuit: Optional[qml.tape.QuantumTape] = None,
|
508
|
+
) -> bool:
|
509
|
+
"""Check whether or not derivatives are available for a given configuration and circuit.
|
510
|
+
|
511
|
+
Args:
|
512
|
+
execution_config (ExecutionConfig): The configuration of the desired derivative calculation.
|
513
|
+
circuit (QuantumTape): An optional circuit to check derivatives support for.
|
514
|
+
|
515
|
+
Returns:
|
516
|
+
Bool: Whether or not a derivative can be calculated provided the given information.
|
517
|
+
|
518
|
+
"""
|
519
|
+
return False
|
520
|
+
|
521
|
+
def compute_derivatives(
|
522
|
+
self,
|
523
|
+
circuits: QuantumTape_or_Batch,
|
524
|
+
execution_config: ExecutionConfig = DefaultExecutionConfig,
|
525
|
+
):
|
526
|
+
"""Calculate the Jacobian of either a single or a batch of circuits on the device.
|
527
|
+
|
528
|
+
Args:
|
529
|
+
circuits (Union[QuantumTape, Sequence[QuantumTape]]): the circuits to calculate derivatives for.
|
530
|
+
execution_config (ExecutionConfig): a data structure with all additional information required for execution.
|
531
|
+
|
532
|
+
Returns:
|
533
|
+
Tuple: The Jacobian for each trainable parameter.
|
534
|
+
"""
|
535
|
+
raise NotImplementedError(
|
536
|
+
"The computation of derivatives has yet to be implemented for the lightning.tensor device."
|
537
|
+
)
|
538
|
+
|
539
|
+
def execute_and_compute_derivatives(
|
540
|
+
self,
|
541
|
+
circuits: QuantumTape_or_Batch,
|
542
|
+
execution_config: ExecutionConfig = DefaultExecutionConfig,
|
543
|
+
):
|
544
|
+
"""Compute the results and Jacobians of circuits at the same time.
|
545
|
+
|
546
|
+
Args:
|
547
|
+
circuits (Union[QuantumTape, Sequence[QuantumTape]]): the circuits or batch of circuits.
|
548
|
+
execution_config (ExecutionConfig): a data structure with all additional information required for execution.
|
549
|
+
|
550
|
+
Returns:
|
551
|
+
tuple: A numeric result of the computation and the gradient.
|
552
|
+
"""
|
553
|
+
raise NotImplementedError(
|
554
|
+
"The computation of derivatives has yet to be implemented for the lightning.tensor device."
|
555
|
+
)
|
556
|
+
|
557
|
+
# pylint: disable=unused-argument
|
558
|
+
def supports_vjp(
|
559
|
+
self,
|
560
|
+
execution_config: Optional[ExecutionConfig] = None,
|
561
|
+
circuit: Optional[QuantumTape] = None,
|
562
|
+
) -> bool:
|
563
|
+
"""Whether or not this device defines a custom vector-Jacobian product.
|
564
|
+
|
565
|
+
Args:
|
566
|
+
execution_config (ExecutionConfig): The configuration of the desired derivative calculation.
|
567
|
+
circuit (QuantumTape): An optional circuit to check derivatives support for.
|
568
|
+
|
569
|
+
Returns:
|
570
|
+
Bool: Whether or not a derivative can be calculated provided the given information.
|
571
|
+
"""
|
572
|
+
return False
|
573
|
+
|
574
|
+
def compute_vjp(
|
575
|
+
self,
|
576
|
+
circuits: QuantumTape_or_Batch,
|
577
|
+
cotangents: Tuple[Number],
|
578
|
+
execution_config: ExecutionConfig = DefaultExecutionConfig,
|
579
|
+
):
|
580
|
+
r"""The vector-Jacobian product used in reverse-mode differentiation.
|
581
|
+
|
582
|
+
Args:
|
583
|
+
circuits (Union[QuantumTape, Sequence[QuantumTape]]): the circuit or batch of circuits.
|
584
|
+
cotangents (Tuple[Number, Tuple[Number]]): Gradient-output vector. Must have shape matching the output shape of the
|
585
|
+
corresponding circuit. If the circuit has a single output, ``cotangents`` may be a single number, not an iterable
|
586
|
+
of numbers.
|
587
|
+
execution_config (ExecutionConfig): a data structure with all additional information required for execution.
|
588
|
+
|
589
|
+
Returns:
|
590
|
+
tensor-like: A numeric result of computing the vector-Jacobian product.
|
591
|
+
"""
|
592
|
+
raise NotImplementedError(
|
593
|
+
"The computation of vector-Jacobian product has yet to be implemented for the lightning.tensor device."
|
594
|
+
)
|
595
|
+
|
596
|
+
def execute_and_compute_vjp(
|
597
|
+
self,
|
598
|
+
circuits: QuantumTape_or_Batch,
|
599
|
+
cotangents: Tuple[Number],
|
600
|
+
execution_config: ExecutionConfig = DefaultExecutionConfig,
|
601
|
+
):
|
602
|
+
"""Calculate both the results and the vector-Jacobian product used in reverse-mode differentiation.
|
603
|
+
|
604
|
+
Args:
|
605
|
+
circuits (Union[QuantumTape, Sequence[QuantumTape]]): the circuit or batch of circuits to be executed.
|
606
|
+
cotangents (Tuple[Number, Tuple[Number]]): Gradient-output vector. Must have shape matching the output shape of the
|
607
|
+
corresponding circuit.
|
608
|
+
execution_config (ExecutionConfig): a data structure with all additional information required for execution.
|
609
|
+
|
610
|
+
Returns:
|
611
|
+
Tuple, Tuple: the result of executing the scripts and the numeric result of computing the vector-Jacobian product
|
612
|
+
"""
|
613
|
+
raise NotImplementedError(
|
614
|
+
"The computation of vector-Jacobian product has yet to be implemented for the lightning.tensor device."
|
615
|
+
)
|