pennylane-lightning-kokkos 0.43.0__cp312-cp312-manylinux_2_26_aarch64.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.
@@ -0,0 +1,455 @@
1
+ # Copyright 2018-2023 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
+ r"""
15
+ This module contains the :class:`~.LightningKokkos` class, a PennyLane simulator device that
16
+ interfaces with C++ for fast linear algebra calculations.
17
+ """
18
+
19
+ from dataclasses import replace
20
+ from functools import partial, reduce
21
+ from pathlib import Path
22
+ from typing import List, Optional, Union
23
+ from warnings import warn
24
+
25
+ import numpy as np
26
+ import pennylane as qml
27
+ from numpy.random import BitGenerator, Generator, SeedSequence
28
+ from numpy.typing import ArrayLike
29
+ from pennylane.devices import ExecutionConfig
30
+ from pennylane.devices.capabilities import OperatorProperties
31
+ from pennylane.devices.modifiers import simulator_tracking, single_tape_support
32
+ from pennylane.devices.preprocess import (
33
+ decompose,
34
+ device_resolve_dynamic_wires,
35
+ no_sampling,
36
+ validate_adjoint_trainable_params,
37
+ validate_device_wires,
38
+ validate_measurements,
39
+ validate_observables,
40
+ )
41
+ from pennylane.exceptions import DecompositionUndefinedError, DeviceError
42
+ from pennylane.measurements import MidMeasureMP
43
+ from pennylane.operation import Operator
44
+ from pennylane.ops import Conditional, PauliRot, Prod, SProd, Sum
45
+ from pennylane.transforms import defer_measurements, dynamic_one_shot
46
+ from pennylane.transforms.core import TransformProgram
47
+
48
+ from pennylane_lightning.lightning_base.lightning_base import (
49
+ LightningBase,
50
+ QuantumTape_or_Batch,
51
+ Result_or_ResultBatch,
52
+ resolve_mcm_method,
53
+ )
54
+
55
+ try:
56
+ from pennylane_lightning.lightning_kokkos_ops import backend_info
57
+
58
+ LK_CPP_BINARY_AVAILABLE = True
59
+ except ImportError as ex:
60
+ warn(str(ex), UserWarning)
61
+ LK_CPP_BINARY_AVAILABLE = False
62
+ backend_info = None
63
+
64
+ from ._adjoint_jacobian import LightningKokkosAdjointJacobian
65
+ from ._measurements import LightningKokkosMeasurements
66
+ from ._state_vector import LightningKokkosStateVector
67
+
68
+ _to_matrix_ops = {
69
+ "BlockEncode": OperatorProperties(),
70
+ "DiagonalQubitUnitary": OperatorProperties(),
71
+ "ECR": OperatorProperties(),
72
+ "ISWAP": OperatorProperties(),
73
+ "OrbitalRotation": OperatorProperties(),
74
+ "QubitCarry": OperatorProperties(),
75
+ "QubitSum": OperatorProperties(),
76
+ "SISWAP": OperatorProperties(),
77
+ "SQISW": OperatorProperties(),
78
+ }
79
+
80
+
81
+ def stopping_condition(op: Operator, allow_mcms: bool = True) -> bool:
82
+ """A function that determines whether or not an operation is supported by ``lightning.kokkos``."""
83
+ if isinstance(op, qml.PauliRot):
84
+ word = op._hyperparameters["pauli_word"] # pylint: disable=protected-access
85
+ # decomposes to IsingXX, etc. for n <= 2
86
+ return reduce(lambda x, y: x + (y != "I"), word, 0) > 2
87
+
88
+ if isinstance(op, MidMeasureMP):
89
+ return allow_mcms
90
+
91
+ return _supports_operation(op.name)
92
+
93
+
94
+ # need to create these once so we can compare in tests
95
+ allow_mcms_stopping_condition = partial(stopping_condition, allow_mcms=True)
96
+ no_mcms_stopping_condition = partial(stopping_condition, allow_mcms=False)
97
+
98
+
99
+ def accepted_observables(obs: Operator) -> bool:
100
+ """A function that determines whether or not an observable is supported by ``lightning.kokkos``."""
101
+ return _supports_observable(obs.name)
102
+
103
+
104
+ def adjoint_observables(obs: Operator) -> bool:
105
+ """A function that determines whether or not an observable is supported by ``lightning.kokkos``
106
+ when using the adjoint differentiation method."""
107
+ if isinstance(obs, qml.Projector):
108
+ return False
109
+
110
+ if isinstance(obs, SProd):
111
+ return adjoint_observables(obs.base)
112
+
113
+ if isinstance(obs, (Sum, Prod)):
114
+ return all(adjoint_observables(o) for o in obs)
115
+
116
+ return _supports_observable(obs.name)
117
+
118
+
119
+ def adjoint_measurements(mp: qml.measurements.MeasurementProcess) -> bool:
120
+ """Specifies whether or not an observable is compatible with adjoint differentiation on DefaultQubit."""
121
+ return isinstance(mp, qml.measurements.ExpectationMP)
122
+
123
+
124
+ def _supports_adjoint(circuit, device_wires=None):
125
+ if circuit is None:
126
+ return True
127
+
128
+ prog = TransformProgram()
129
+ _add_adjoint_transforms(prog, device_wires=device_wires)
130
+
131
+ try:
132
+ prog((circuit,))
133
+ except (DecompositionUndefinedError, DeviceError, AttributeError):
134
+ return False
135
+ return True
136
+
137
+
138
+ def _adjoint_ops(op: qml.operation.Operator) -> bool:
139
+ """Specify whether or not an Operator is supported by adjoint differentiation."""
140
+
141
+ return not isinstance(op, (Conditional, MidMeasureMP, PauliRot)) and (
142
+ not any(qml.math.requires_grad(d) for d in op.data)
143
+ or (op.num_params == 1 and op.has_generator)
144
+ )
145
+
146
+
147
+ def _add_adjoint_transforms(program: TransformProgram, device_wires=None) -> None:
148
+ """Private helper function for ``preprocess`` that adds the transforms specific
149
+ for adjoint differentiation.
150
+
151
+ Args:
152
+ program (TransformProgram): where we will add the adjoint differentiation transforms
153
+
154
+ Side Effects:
155
+ Adds transforms to the input program.
156
+
157
+ """
158
+
159
+ name = "adjoint + lightning.kokkos"
160
+ program.add_transform(no_sampling, name=name)
161
+ program.add_transform(qml.transforms.broadcast_expand)
162
+ program.add_transform(
163
+ decompose,
164
+ stopping_condition=_adjoint_ops,
165
+ name=name,
166
+ skip_initial_state_prep=False,
167
+ device_wires=device_wires,
168
+ target_gates=LightningKokkos.capabilities.operations.keys(),
169
+ )
170
+ program.add_transform(validate_observables, accepted_observables, name=name)
171
+ program.add_transform(
172
+ validate_measurements, analytic_measurements=adjoint_measurements, name=name
173
+ )
174
+ program.add_transform(validate_adjoint_trainable_params)
175
+
176
+
177
+ @simulator_tracking
178
+ @single_tape_support
179
+ class LightningKokkos(LightningBase):
180
+ """PennyLane Lightning Kokkos device.
181
+
182
+ A device that interfaces with C++ to perform fast linear algebra calculations on CPUs or GPUs using `Kokkos`.
183
+
184
+ Use of this device requires pre-built binaries or compilation from source. Check out the
185
+ :doc:`/lightning_kokkos/installation` guide for more details.
186
+
187
+ Args:
188
+ 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.
189
+ c_dtype: Datatypes for statevector representation. Must be one of
190
+ ``np.complex64`` or ``np.complex128``.
191
+ shots (int): How many times the circuit should be evaluated (or sampled) to estimate
192
+ the expectation values. Defaults to ``None`` if not specified. Setting
193
+ to ``None`` results in computing statistics like expectation values and
194
+ variances analytically.
195
+ seed (Union[str, None, int, array_like[int], SeedSequence, BitGenerator, Generator]): A
196
+ seed-like parameter matching that of ``seed`` for ``numpy.random.default_rng``, or
197
+ a request to seed from numpy's global random number generator.
198
+ The default, ``seed="global"`` pulls a seed from NumPy's global generator. ``seed=None``
199
+ will pull a seed from the OS entropy.
200
+ mpi (bool): Use MPI to distribute statevector across multiple processes.
201
+ kokkos_args (InitializationSettings): binding for Kokkos::InitializationSettings
202
+ (threading parameters).
203
+ """
204
+
205
+ # General device options
206
+ _device_options = ("c_dtype", "batch_obs")
207
+
208
+ # Device specific options
209
+ _CPP_BINARY_AVAILABLE = LK_CPP_BINARY_AVAILABLE
210
+ _backend_info = backend_info if LK_CPP_BINARY_AVAILABLE else None
211
+ kokkos_config = {}
212
+
213
+ # The configuration file declares the capabilities of the device
214
+ config_filepath = Path(__file__).parent / "lightning_kokkos.toml"
215
+
216
+ # TODO: This is to communicate to Catalyst in qjit-compiled workflows that these operations
217
+ # should be converted to QubitUnitary instead of their original decompositions. Remove
218
+ # this when customizable multiple decomposition pathways are implemented
219
+ _to_matrix_ops = _to_matrix_ops
220
+
221
+ def __init__( # pylint: disable=too-many-arguments
222
+ self,
223
+ wires: Union[int, List] = None,
224
+ *,
225
+ c_dtype: Union[np.complex128, np.complex64] = np.complex128,
226
+ shots: Union[int, List] = None,
227
+ batch_obs: bool = False,
228
+ seed: Union[str, None, int, ArrayLike, SeedSequence, BitGenerator, Generator] = "global",
229
+ # Kokkos arguments
230
+ mpi: bool = False,
231
+ kokkos_args=None,
232
+ ):
233
+ if not self._CPP_BINARY_AVAILABLE:
234
+ raise ImportError(
235
+ "Pre-compiled binaries for lightning.kokkos are not available. "
236
+ "To manually compile from source, follow the instructions at "
237
+ "https://docs.pennylane.ai/projects/lightning/en/stable/dev/installation.html."
238
+ )
239
+
240
+ super().__init__(
241
+ wires=wires,
242
+ c_dtype=c_dtype,
243
+ shots=shots,
244
+ seed=seed,
245
+ batch_obs=batch_obs,
246
+ )
247
+
248
+ # Set the attributes to call the Lightning classes
249
+ self._set_lightning_classes()
250
+
251
+ self._mpi = mpi
252
+ if mpi:
253
+ if wires is None:
254
+ raise DeviceError("Lightning-Kokkos-MPI does not support dynamic wires allocation.")
255
+ self._statevector = self.LightningStateVector(
256
+ num_wires=len(self.wires),
257
+ dtype=self.c_dtype,
258
+ kokkos_args=kokkos_args,
259
+ mpi=True,
260
+ rng=self._rng,
261
+ )
262
+ else:
263
+ self._statevector = None
264
+ self._sv_init_kwargs = {"kokkos_args": kokkos_args}
265
+
266
+ @property
267
+ def name(self):
268
+ """The name of the device."""
269
+ return "lightning.kokkos"
270
+
271
+ def _set_lightning_classes(self):
272
+ """Load the LightningStateVector, LightningMeasurements, LightningAdjointJacobian as class attribute"""
273
+ self.LightningStateVector = LightningKokkosStateVector
274
+ self.LightningMeasurements = LightningKokkosMeasurements
275
+ self.LightningAdjointJacobian = LightningKokkosAdjointJacobian
276
+
277
+ def setup_execution_config(
278
+ self, config: ExecutionConfig | None = None, circuit: qml.tape.QuantumScript | None = None
279
+ ) -> ExecutionConfig:
280
+ """
281
+ Update the execution config with choices for how the device should be used and the device options.
282
+ """
283
+ if config is None:
284
+ config = ExecutionConfig()
285
+ updated_values = {}
286
+
287
+ # It is necessary to set the mcmc default configuration to complete the requirements of ExecuteConfig
288
+ mcmc_default = {"mcmc": False, "kernel_name": None, "num_burnin": 0, "rng": None}
289
+
290
+ for option, _ in config.device_options.items():
291
+ if option not in self._device_options and option not in mcmc_default:
292
+ raise DeviceError(f"device option {option} not present on {self}")
293
+
294
+ if config.gradient_method == "best":
295
+ updated_values["gradient_method"] = "adjoint"
296
+ if config.use_device_jacobian_product is None:
297
+ updated_values["use_device_jacobian_product"] = config.gradient_method in (
298
+ "best",
299
+ "adjoint",
300
+ )
301
+ if config.use_device_gradient is None:
302
+ updated_values["use_device_gradient"] = config.gradient_method in ("best", "adjoint")
303
+ if (
304
+ config.use_device_gradient
305
+ or updated_values.get("use_device_gradient", False)
306
+ and config.grad_on_execution is None
307
+ ):
308
+ updated_values["grad_on_execution"] = True
309
+
310
+ new_device_options = dict(config.device_options)
311
+ for option in self._device_options:
312
+ if option not in new_device_options:
313
+ new_device_options[option] = getattr(self, f"_{option}", None)
314
+
315
+ new_device_options.update(mcmc_default)
316
+
317
+ mcm_config = resolve_mcm_method(config.mcm_config, circuit, "lightning.kokkos")
318
+ updated_values["mcm_config"] = mcm_config
319
+ return replace(config, **updated_values, device_options=new_device_options)
320
+
321
+ def preprocess_transforms(
322
+ self, execution_config: ExecutionConfig | None = None
323
+ ) -> TransformProgram:
324
+ """This function defines the device transform program to be applied and an updated device configuration.
325
+
326
+ Args:
327
+ execution_config (Union[ExecutionConfig, Sequence[ExecutionConfig]]): A data structure describing the
328
+ parameters needed to fully describe the execution.
329
+
330
+ Returns:
331
+ TransformProgram, ExecutionConfig: A transform program that when called returns :class:`~.QuantumTape`'s that the
332
+ device can natively execute as well as a postprocessing function to be called after execution, and a configuration
333
+ with unset specifications filled in.
334
+
335
+ This device:
336
+
337
+ * Supports any qubit operations that provide a matrix
338
+ * Currently does not support finite shots
339
+ * Currently does not intrinsically support parameter broadcasting
340
+
341
+ """
342
+ if execution_config is None:
343
+ execution_config = ExecutionConfig()
344
+ exec_config = execution_config
345
+ program = TransformProgram()
346
+
347
+ if qml.capture.enabled():
348
+ if exec_config.mcm_config.mcm_method == "deferred":
349
+ program.add_transform(qml.defer_measurements, num_wires=len(self.wires))
350
+ program.add_transform(qml.transforms.decompose, gate_set=no_mcms_stopping_condition)
351
+ return program
352
+
353
+ program.add_transform(validate_measurements, name=self.name)
354
+ program.add_transform(validate_observables, accepted_observables, name=self.name)
355
+ if exec_config.mcm_config.mcm_method == "deferred":
356
+ program.add_transform(defer_measurements, allow_postselect=False)
357
+ _stopping_condition = no_mcms_stopping_condition
358
+ else:
359
+ _stopping_condition = allow_mcms_stopping_condition
360
+
361
+ program.add_transform(
362
+ decompose,
363
+ stopping_condition=_stopping_condition,
364
+ skip_initial_state_prep=True,
365
+ name=self.name,
366
+ device_wires=self.wires,
367
+ target_gates=self.capabilities.operations.keys(),
368
+ )
369
+
370
+ _allow_resets = exec_config.mcm_config.mcm_method != "deferred"
371
+ program.add_transform(
372
+ device_resolve_dynamic_wires, wires=self.wires, allow_resets=_allow_resets
373
+ )
374
+ program.add_transform(validate_device_wires, self.wires, name=self.name)
375
+ if exec_config.mcm_config.mcm_method == "one-shot":
376
+ program.add_transform(
377
+ dynamic_one_shot, postselect_mode=exec_config.mcm_config.postselect_mode
378
+ )
379
+
380
+ program.add_transform(qml.transforms.broadcast_expand)
381
+
382
+ if exec_config.gradient_method == "adjoint":
383
+ _add_adjoint_transforms(program, device_wires=self.wires)
384
+ return program
385
+
386
+ # pylint: disable=unused-argument
387
+ def execute(
388
+ self,
389
+ circuits: QuantumTape_or_Batch,
390
+ execution_config: ExecutionConfig | None = None,
391
+ ) -> Result_or_ResultBatch:
392
+ """Execute a circuit or a batch of circuits and turn it into results.
393
+
394
+ Args:
395
+ circuits (Union[QuantumTape, Sequence[QuantumTape]]): the quantum circuits to be executed
396
+ execution_config (ExecutionConfig): a datastructure with additional information required for execution
397
+
398
+ Returns:
399
+ TensorLike, tuple[TensorLike], tuple[tuple[TensorLike]]: A numeric result of the computation.
400
+ """
401
+ if execution_config is None:
402
+ execution_config = ExecutionConfig()
403
+ results = []
404
+ for circuit in circuits:
405
+ if self._wire_map is not None:
406
+ [circuit], _ = qml.map_wires(circuit, self._wire_map)
407
+ results.append(
408
+ self.simulate(
409
+ self.dynamic_wires_from_circuit(circuit),
410
+ self._statevector,
411
+ postselect_mode=execution_config.mcm_config.postselect_mode,
412
+ mcm_method=execution_config.mcm_config.mcm_method,
413
+ )
414
+ )
415
+
416
+ return tuple(results)
417
+
418
+ def supports_derivatives(
419
+ self,
420
+ execution_config: ExecutionConfig | None = None,
421
+ circuit: Optional[qml.tape.QuantumTape] = None,
422
+ ) -> bool:
423
+ """Check whether or not derivatives are available for a given configuration and circuit.
424
+
425
+ ``LightningKokkos`` supports adjoint differentiation with analytic results.
426
+
427
+ Args:
428
+ execution_config (ExecutionConfig): The configuration of the desired derivative calculation
429
+ circuit (QuantumTape): An optional circuit to check derivatives support for.
430
+
431
+ Returns:
432
+ Bool: Whether or not a derivative can be calculated provided the given information
433
+
434
+ """
435
+ if execution_config is None and circuit is None:
436
+ return True
437
+
438
+ if execution_config and execution_config.gradient_method in {"adjoint", "best"}:
439
+ if circuit is None:
440
+ return True
441
+ return _supports_adjoint(circuit=circuit, device_wires=self.wires)
442
+
443
+ return False
444
+
445
+ @staticmethod
446
+ def get_c_interface():
447
+ """Returns a tuple consisting of the device name, and
448
+ the location to the shared object with the C/C++ device implementation.
449
+ """
450
+
451
+ return LightningBase.get_c_interface_impl("LightningKokkosSimulator", "lightning_kokkos")
452
+
453
+
454
+ _supports_operation = LightningKokkos.capabilities.supports_operation
455
+ _supports_observable = LightningKokkos.capabilities.supports_observable
@@ -0,0 +1,131 @@
1
+ schema = 3
2
+
3
+ # The set of all gate types supported at the runtime execution interface of the
4
+ # device, i.e., what is supported by the `execute` method of the Device API.
5
+ # The gate definition has the following format:
6
+ #
7
+ # GATE = { properties = [ PROPS ], conditions = [ CONDS ] }
8
+ #
9
+ # where PROPS and CONS are zero or more comma separated quoted strings.
10
+ #
11
+ # PROPS: zero or more comma-separated quoted strings:
12
+ # - "controllable": if a controlled version of this gate is supported.
13
+ # - "invertible": if the adjoint of this operation is supported.
14
+ # - "differentiable": if device gradient is supported for this gate.
15
+ # CONDS: zero or more comma-separated quoted strings:
16
+ # - "analytic" or "finiteshots": if this operation is only supported in
17
+ # either analytic execution or with shots, respectively.
18
+ # - "terms-commute": if this composite operator is only supported
19
+ # given that its terms commute. Only relevant for Prod, SProd, Sum,
20
+ # LinearCombination, and Hamiltonian.
21
+ #
22
+ [operators.gates]
23
+
24
+ CNOT = { properties = [ "invertible", "differentiable" ] }
25
+ ControlledPhaseShift = { properties = [ "invertible", "differentiable" ] }
26
+ CRot = { properties = [ "invertible" ] }
27
+ CRX = { properties = [ "invertible", "differentiable" ] }
28
+ CRY = { properties = [ "invertible", "differentiable" ] }
29
+ CRZ = { properties = [ "invertible", "differentiable" ] }
30
+ CSWAP = { properties = [ "invertible", "differentiable" ] }
31
+ CY = { properties = [ "invertible", "differentiable" ] }
32
+ CZ = { properties = [ "invertible", "differentiable" ] }
33
+ DoubleExcitationMinus = { properties = [ "invertible", "controllable", "differentiable" ] }
34
+ DoubleExcitationPlus = { properties = [ "invertible", "controllable", "differentiable" ] }
35
+ DoubleExcitation = { properties = [ "invertible", "controllable", "differentiable" ] }
36
+ GlobalPhase = { properties = [ "invertible", "controllable", "differentiable" ] }
37
+ Hadamard = { properties = [ "invertible", "controllable", "differentiable" ] }
38
+ Identity = { properties = [ "invertible", "differentiable" ] }
39
+ IsingXX = { properties = [ "invertible", "controllable", "differentiable" ] }
40
+ IsingXY = { properties = [ "invertible", "controllable", "differentiable" ] }
41
+ IsingYY = { properties = [ "invertible", "controllable", "differentiable" ] }
42
+ IsingZZ = { properties = [ "invertible", "controllable", "differentiable" ] }
43
+ MultiRZ = { properties = [ "invertible", "controllable", "differentiable" ] }
44
+ PauliX = { properties = [ "invertible", "controllable", "differentiable" ] }
45
+ PauliY = { properties = [ "invertible", "controllable", "differentiable" ] }
46
+ PauliZ = { properties = [ "invertible", "controllable", "differentiable" ] }
47
+ PhaseShift = { properties = [ "invertible", "controllable", "differentiable" ] }
48
+ PSWAP = { properties = [ "invertible", "controllable", "differentiable" ] }
49
+ QubitUnitary = { properties = [ "invertible", "controllable" ] }
50
+ Rot = { properties = [ "invertible", "controllable" ] }
51
+ RX = { properties = [ "invertible", "controllable", "differentiable" ] }
52
+ RY = { properties = [ "invertible", "controllable", "differentiable" ] }
53
+ RZ = { properties = [ "invertible", "controllable", "differentiable" ] }
54
+ SingleExcitationMinus = { properties = [ "invertible", "controllable", "differentiable" ] }
55
+ SingleExcitationPlus = { properties = [ "invertible", "controllable", "differentiable" ] }
56
+ SingleExcitation = { properties = [ "invertible", "controllable", "differentiable" ] }
57
+ S = { properties = [ "invertible", "controllable", "differentiable" ] }
58
+ SWAP = { properties = [ "invertible", "controllable", "differentiable" ] }
59
+ Toffoli = { properties = [ "invertible", "differentiable" ] }
60
+ T = { properties = [ "invertible", "controllable", "differentiable" ] }
61
+ SX = { properties = [ "invertible", "controllable", "differentiable" ] }
62
+
63
+ # Operations supported by the execution in Python but not directly supported by the backend
64
+ [pennylane.operators.gates]
65
+
66
+ MultiControlledX = {}
67
+ ControlledQubitUnitary = {}
68
+ GlobalPhase = { properties = [ "invertible", "controllable", "differentiable" ] }
69
+ BlockEncode = { properties = [ "controllable" ] }
70
+ DiagonalQubitUnitary = {}
71
+ ECR = {}
72
+ ISWAP = {}
73
+ OrbitalRotation = {}
74
+ QubitCarry = {}
75
+ QubitSum = {}
76
+ SISWAP = {}
77
+ SQISW = {}
78
+
79
+ # Observables supported by the device
80
+ [operators.observables]
81
+
82
+ Identity = { properties = [ "differentiable" ] }
83
+ PauliX = { properties = [ "differentiable" ] }
84
+ PauliY = { properties = [ "differentiable" ] }
85
+ PauliZ = { properties = [ "differentiable" ] }
86
+ Hadamard = { properties = [ "differentiable" ] }
87
+ Hermitian = { properties = [ "differentiable" ] }
88
+ SparseHamiltonian = { properties = [ "differentiable" ] }
89
+ Sum = { properties = [ "differentiable" ] }
90
+ SProd = { properties = [ "differentiable" ] }
91
+ Prod = { properties = [ "differentiable" ] }
92
+ Exp = { properties = [ "differentiable" ] }
93
+ LinearCombination = { properties = [ "differentiable" ] }
94
+
95
+ [pennylane.operators.observables]
96
+
97
+ Projector = {}
98
+
99
+ [measurement_processes]
100
+
101
+ ExpectationMP = {}
102
+ VarianceMP = {}
103
+ ProbabilityMP = {}
104
+ StateMP = { conditions = [ "analytic" ] }
105
+ SampleMP = { conditions = [ "finiteshots" ] }
106
+ CountsMP = { conditions = [ "finiteshots" ] }
107
+
108
+ # Additional support that the device may provide. All accepted fields and their
109
+ # default values are listed below. Any fields missing from the TOML file will be
110
+ # set to their default values.
111
+ [compilation]
112
+
113
+ # Whether the device is compatible with qjit.
114
+ qjit_compatible = true
115
+
116
+ # Whether the device requires run time generation of the quantum circuit.
117
+ runtime_code_generation = false
118
+
119
+ # The methods of handling mid-circuit measurements that the device supports, e.g.,
120
+ # "one-shot", "device", "tree-traversal", etc. An empty list indicates that the device
121
+ # does not support mid-circuit measurements.
122
+ supported_mcm_methods = [ "device", "one-shot", "tree-traversal" ]
123
+
124
+ # Whether the device supports dynamic qubit allocation/deallocation.
125
+ dynamic_qubit_management = false
126
+
127
+ # Whether simultaneous measurements of non-commuting observables is supported.
128
+ non_commuting_observables = true
129
+
130
+ # Whether the device supports initial state preparation.
131
+ initial_state_prep = true