Skip to content

Commit cead5eb

Browse files
authored
Merge branch 'master' into technical-assignement
2 parents 8e27978 + 45a67d4 commit cead5eb

File tree

9 files changed

+275
-506
lines changed

9 files changed

+275
-506
lines changed

.github/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323

2424
### Improvements
2525

26+
* The TOML files for the devices are updated to use the new schema for declaring device capabilities.
27+
[(#988)](https://github.com/PennyLaneAI/pennylane-lightning/pull/988)
28+
2629
* Unify excitation gates memory layout to row-major for both LGPU and LT.
2730
[(#959)](https://github.com/PennyLaneAI/pennylane-lightning/pull/959)
2831

@@ -52,7 +55,7 @@
5255

5356
This release contains contributions from (in alphabetical order):
5457

55-
Ali Asadi, Joseph Lee, Anton Naim Ibrahim, Luis Alfredo Nuñez Meneses, Andrija Paurevic, Shuli Shu, Raul Torres, Haochen Paul Wang
58+
Ali Asadi, Astral Cai, Joseph Lee, Anton Naim Ibrahim, Luis Alfredo Nuñez Meneses, Andrija Paurevic, Shuli Shu, Raul Torres, Haochen Paul Wang
5659

5760
---
5861

doc/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ cutensornet-cu12
1818
wheel
1919
sphinxext-opengraph
2020
matplotlib
21+
git+https://github.com/PennyLaneAI/pennylane.git@master

pennylane_lightning/lightning_gpu/lightning_gpu.py

Lines changed: 33 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import numpy as np
3131
import pennylane as qml
3232
from pennylane.devices import DefaultExecutionConfig, ExecutionConfig
33-
from pennylane.devices.default_qubit import adjoint_ops
33+
from pennylane.devices.capabilities import OperatorProperties
3434
from pennylane.devices.modifiers import simulator_tracking, single_tape_support
3535
from pennylane.devices.preprocess import (
3636
decompose,
@@ -43,7 +43,7 @@
4343
)
4444
from pennylane.measurements import MidMeasureMP
4545
from pennylane.operation import DecompositionUndefinedError, Operator
46-
from pennylane.ops import Prod, SProd, Sum
46+
from pennylane.ops import Conditional, PauliRot, Prod, SProd, Sum
4747
from pennylane.tape import QuantumScript
4848
from pennylane.transforms.core import TransformProgram
4949
from pennylane.typing import Result
@@ -74,135 +74,25 @@
7474
from ._mpi_handler import MPIHandler
7575
from ._state_vector import LightningGPUStateVector
7676

77-
# The set of supported operations.
78-
_operations = frozenset(
79-
{
80-
"Identity",
81-
"QubitUnitary",
82-
"ControlledQubitUnitary",
83-
"MultiControlledX",
84-
"DiagonalQubitUnitary",
85-
"PauliX",
86-
"PauliY",
87-
"PauliZ",
88-
"MultiRZ",
89-
"GlobalPhase",
90-
"C(PauliX)",
91-
"C(PauliY)",
92-
"C(PauliZ)",
93-
"C(Hadamard)",
94-
"C(S)",
95-
"C(T)",
96-
"C(PhaseShift)",
97-
"C(RX)",
98-
"C(RY)",
99-
"C(RZ)",
100-
"C(Rot)",
101-
"C(SWAP)",
102-
"C(IsingXX)",
103-
"C(IsingXY)",
104-
"C(IsingYY)",
105-
"C(IsingZZ)",
106-
"C(SingleExcitation)",
107-
"C(SingleExcitationMinus)",
108-
"C(SingleExcitationPlus)",
109-
"C(DoubleExcitation)",
110-
"C(DoubleExcitationMinus)",
111-
"C(DoubleExcitationPlus)",
112-
"C(MultiRZ)",
113-
"C(GlobalPhase)",
114-
"Hadamard",
115-
"S",
116-
"Adjoint(S)",
117-
"T",
118-
"Adjoint(T)",
119-
"SX",
120-
"Adjoint(SX)",
121-
"CNOT",
122-
"SWAP",
123-
"ISWAP",
124-
"PSWAP",
125-
"Adjoint(ISWAP)",
126-
"SISWAP",
127-
"Adjoint(SISWAP)",
128-
"SQISW",
129-
"CSWAP",
130-
"Toffoli",
131-
"CY",
132-
"CZ",
133-
"PhaseShift",
134-
"ControlledPhaseShift",
135-
"RX",
136-
"RY",
137-
"RZ",
138-
"Rot",
139-
"CRX",
140-
"CRY",
141-
"CRZ",
142-
"CRot",
143-
"IsingXX",
144-
"IsingYY",
145-
"IsingZZ",
146-
"IsingXY",
147-
"SingleExcitation",
148-
"SingleExcitationPlus",
149-
"SingleExcitationMinus",
150-
"DoubleExcitation",
151-
"DoubleExcitationPlus",
152-
"DoubleExcitationMinus",
153-
"Adjoint(MultiRZ)",
154-
"Adjoint(GlobalPhase)",
155-
"Adjoint(PhaseShift)",
156-
"Adjoint(ControlledPhaseShift)",
157-
"Adjoint(RX)",
158-
"Adjoint(RY)",
159-
"Adjoint(RZ)",
160-
"Adjoint(CRX)",
161-
"Adjoint(CRY)",
162-
"Adjoint(CRZ)",
163-
"Adjoint(IsingXX)",
164-
"Adjoint(IsingYY)",
165-
"Adjoint(IsingZZ)",
166-
"Adjoint(IsingXY)",
167-
"Adjoint(SingleExcitation)",
168-
"Adjoint(SingleExcitationPlus)",
169-
"Adjoint(SingleExcitationMinus)",
170-
"Adjoint(DoubleExcitation)",
171-
"Adjoint(DoubleExcitationPlus)",
172-
"Adjoint(DoubleExcitationMinus)",
173-
"QubitCarry",
174-
"QubitSum",
175-
"OrbitalRotation",
176-
"ECR",
177-
"BlockEncode",
178-
"C(BlockEncode)",
179-
}
180-
)
181-
# End the set of supported operations.
182-
183-
# The set of supported observables.
184-
_observables = frozenset(
185-
{
186-
"PauliX",
187-
"PauliY",
188-
"PauliZ",
189-
"Hadamard",
190-
"SparseHamiltonian",
191-
"LinearCombination",
192-
"Hermitian",
193-
"Identity",
194-
"Projector",
195-
"Sum",
196-
"Prod",
197-
"SProd",
198-
"Exp",
199-
}
200-
)
77+
_to_matrix_ops = {
78+
"BlockEncode": OperatorProperties(controllable=True),
79+
"ControlledQubitUnitary": OperatorProperties(),
80+
"ECR": OperatorProperties(),
81+
"SX": OperatorProperties(),
82+
"ISWAP": OperatorProperties(),
83+
"PSWAP": OperatorProperties(),
84+
"SISWAP": OperatorProperties(),
85+
"SQISW": OperatorProperties(),
86+
"OrbitalRotation": OperatorProperties(),
87+
"QubitCarry": OperatorProperties(),
88+
"QubitSum": OperatorProperties(),
89+
"DiagonalQubitUnitary": OperatorProperties(),
90+
}
20191

20292

20393
def stopping_condition(op: Operator) -> bool:
20494
"""A function that determines whether or not an operation is supported by ``lightning.gpu``."""
205-
return op.name in _operations
95+
return _supports_operation(op.name)
20696

20797

20898
def stopping_condition_shots(op: Operator) -> bool:
@@ -213,7 +103,7 @@ def stopping_condition_shots(op: Operator) -> bool:
213103

214104
def accepted_observables(obs: Operator) -> bool:
215105
"""A function that determines whether or not an observable is supported by ``lightning.gpu``."""
216-
return obs.name in _observables
106+
return _supports_observable(obs.name)
217107

218108

219109
def adjoint_observables(obs: Operator) -> bool:
@@ -228,7 +118,7 @@ def adjoint_observables(obs: Operator) -> bool:
228118
if isinstance(obs, (Sum, Prod)):
229119
return all(adjoint_observables(o) for o in obs)
230120

231-
return obs.name in _observables
121+
return _supports_observable(obs.name)
232122

233123

234124
def adjoint_measurements(mp: qml.measurements.MeasurementProcess) -> bool:
@@ -252,7 +142,10 @@ def _supports_adjoint(circuit):
252142

253143
def _adjoint_ops(op: qml.operation.Operator) -> bool:
254144
"""Specify whether or not an Operator is supported by adjoint differentiation."""
255-
return adjoint_ops(op) and not isinstance(op, qml.PauliRot)
145+
146+
return not isinstance(op, (Conditional, MidMeasureMP, PauliRot)) and (
147+
not qml.operation.is_trainable(op) or (op.num_params == 1 and op.has_generator)
148+
)
256149

257150

258151
def _add_adjoint_transforms(program: TransformProgram) -> None:
@@ -333,15 +226,13 @@ class LightningGPU(LightningBase):
333226
_CPP_BINARY_AVAILABLE = LGPU_CPP_BINARY_AVAILABLE
334227
_backend_info = backend_info if LGPU_CPP_BINARY_AVAILABLE else None
335228

336-
# This `config` is used in Catalyst-Frontend
337-
config = Path(__file__).parent / "lightning_gpu.toml"
229+
# TODO: This is to communicate to Catalyst in qjit-compiled workflows that these operations
230+
# should be converted to QubitUnitary instead of their original decompositions. Remove
231+
# this when customizable multiple decomposition pathways are implemented
232+
_to_matrix_ops = _to_matrix_ops
338233

339-
# TODO: Move supported ops/obs to TOML file
340-
operations = _operations
341-
# The names of the supported operations.
342-
343-
observables = _observables
344-
# The names of the supported observables.
234+
# This configuration file declares capabilities of the device
235+
config_filepath = Path(__file__).parent / "lightning_gpu.toml"
345236

346237
def __init__( # pylint: disable=too-many-arguments
347238
self,
@@ -607,3 +498,7 @@ def get_c_interface():
607498
return "LightningGPUSimulator", lib_location
608499

609500
raise RuntimeError("'LightningGPUSimulator' shared library not found") # pragma: no cover
501+
502+
503+
_supports_operation = LightningGPU.capabilities.supports_operation
504+
_supports_observable = LightningGPU.capabilities.supports_observable
Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1-
schema = 2
1+
schema = 3
22

3-
# The union of all gate types listed in this section must match what
4-
# the device considers "supported" through PennyLane's device API.
5-
[operators.gates.native]
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]
623

724
Identity = { properties = [ "invertible", "differentiable" ] }
825
PauliX = { properties = [ "invertible", "controllable", "differentiable" ] }
@@ -15,7 +32,7 @@ PhaseShift = { properties = [ "invertible", "controllable", "differe
1532
RX = { properties = [ "invertible", "controllable", "differentiable" ] }
1633
RY = { properties = [ "invertible", "controllable", "differentiable" ] }
1734
RZ = { properties = [ "invertible", "controllable", "differentiable" ] }
18-
Rot = { properties = [ "invertible", "controllable", "differentiable" ] }
35+
Rot = { properties = [ "controllable", "differentiable" ] }
1936
CNOT = { properties = [ "invertible", "differentiable" ] }
2037
CY = { properties = [ "invertible", "differentiable" ] }
2138
CZ = { properties = [ "invertible", "differentiable" ] }
@@ -30,7 +47,7 @@ ControlledPhaseShift = { properties = [ "invertible", "differe
3047
CRX = { properties = [ "invertible", "differentiable" ] }
3148
CRY = { properties = [ "invertible", "differentiable" ] }
3249
CRZ = { properties = [ "invertible", "differentiable" ] }
33-
CRot = { properties = [ "invertible" ] }
50+
CRot = { }
3451
SingleExcitation = { properties = [ "invertible", "controllable", "differentiable" ] }
3552
SingleExcitationPlus = { properties = [ "invertible", "controllable", "differentiable" ] }
3653
SingleExcitationMinus = { properties = [ "invertible", "controllable", "differentiable" ] }
@@ -41,21 +58,10 @@ MultiRZ = { properties = [ "invertible", "controllable", "differe
4158
QubitUnitary = { properties = [ "invertible", "controllable" ] }
4259
GlobalPhase = { properties = [ "invertible", "controllable", "differentiable" ] }
4360

44-
# Operators that should be decomposed according to the algorithm used
45-
# by PennyLane's device API.
46-
# Optional, since gates not listed in this list will typically be decomposed by
47-
# default, but can be useful to express a deviation from this device's regular
48-
# strategy in PennyLane.
49-
[operators.gates.decomp]
61+
# Operations supported by the execution in Python but not directly supported by the backend
62+
[pennylane.operators.gates]
5063

51-
BasisState = {}
52-
StatePrep = {}
53-
MultiControlledX = {}
54-
55-
# Gates which should be translated to QubitUnitary
56-
[operators.gates.matrix]
57-
58-
BlockEncode = {properties = [ "controllable" ]}
64+
BlockEncode = { properties = [ "controllable" ] }
5965
ControlledQubitUnitary = {}
6066
ECR = {}
6167
SX = {}
@@ -67,6 +73,7 @@ OrbitalRotation = {}
6773
QubitCarry = {}
6874
QubitSum = {}
6975
DiagonalQubitUnitary = {}
76+
MultiControlledX = {}
7077

7178
# Observables supported by the device
7279
[operators.observables]
@@ -84,30 +91,35 @@ Prod = { properties = [ "differentiable" ] }
8491
Exp = { properties = [ "differentiable" ] }
8592
LinearCombination = { properties = [ "differentiable" ] }
8693

94+
[pennylane.operators.observables]
95+
96+
Projector = {}
97+
8798
[measurement_processes]
8899

89-
Expval = {}
90-
Var = {}
91-
Probs = {}
92-
State = { condition = [ "analytic" ] }
93-
Sample = { condition = [ "finiteshots" ] }
94-
Counts = { condition = [ "finiteshots" ] }
100+
ExpectationMP = {}
101+
VarianceMP = {}
102+
ProbabilityMP = {}
103+
StateMP = { conditions = [ "analytic" ] }
104+
SampleMP = { conditions = [ "finiteshots" ] }
105+
CountsMP = { conditions = [ "finiteshots" ] }
95106

107+
# Additional support that the device may provide. All accepted fields and their
108+
# default values are listed below. Any fields missing from the TOML file will be
109+
# set to their default values.
96110
[compilation]
97-
# If the device is compatible with qjit
111+
112+
# Whether the device is compatible with qjit.
98113
qjit_compatible = true
99-
# If the device requires run time generation of the quantum circuit.
114+
# Whether the device requires run time generation of the quantum circuit.
100115
runtime_code_generation = false
101-
# If the device supports mid circuit measurements natively
102-
mid_circuit_measurement = true
103-
104-
# This field is currently unchecked but it is reserved for the purpose of
105-
# determining if the device supports dynamic qubit allocation/deallocation.
116+
# The methods of handling mid-circuit measurements that the device supports, e.g.,
117+
# "one-shot", "device", "tree-traversal", etc. An empty list indicates that the device
118+
# does not support mid-circuit measurements.
119+
supported_mcm_methods = [ "one-shot" ]
120+
# Whether the device supports dynamic qubit allocation/deallocation.
106121
dynamic_qubit_management = false
107-
108-
# whether the device can support non-commuting measurements together
109-
# in a single execution
122+
# Whether simultaneous measurements of non-commuting observables is supported.
110123
non_commuting_observables = true
111-
112-
# Whether the device supports (arbitrary) initial state preparation.
124+
# Whether the device supports initial state preparation.
113125
initial_state_prep = true

0 commit comments

Comments
 (0)