Skip to content

Commit c1d096b

Browse files
authored
Default Operator.num_wires = None to indicate that the operator can be on any number of wires (#7312)
**Context:** This PR is separated from #7311 to allow us to update catalyst easily. `AllWires` and `AnyWires` are overkill that don't really need to exist. Setting `Operator.num_wires = None` can sufficiently communicate "I can accept any number of wires". We haven't validated `AllWires` or done anything special about it for many releases. All these serve to do it tell the default `Operator.__init__` to not validate how many wires the user passes in. We can do that with `None`. All they really do is make the interface more complicated and cluttered. **Description of the Change:** Default to using `Operator.num_wires = None` to indicate that the operator can be on any number of wires. **Benefits:** Cleaner Operator interface. Sets us up for deprecating `WiresEnum`. **Possible Drawbacks:** Deprecations and removals always run the risk of breaking something for someone, but I think this a harmless enough change. [sc-89159]
1 parent cf180c0 commit c1d096b

File tree

88 files changed

+118
-269
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+118
-269
lines changed

doc/development/adding_operators.rst

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,6 @@ knows a native implementation for ``FlipAndRotate``). It also defines an adjoint
139139
140140
class FlipAndRotate(qml.operation.Operation):
141141
142-
# Define how many wires the operator acts on in total.
143-
# In our case this may be one or two, which is why we
144-
# use the AnyWires Enumeration to indicate a variable number.
145-
num_wires = qml.operation.AnyWires
146-
147142
# This attribute tells PennyLane what differentiation method to use. Here
148143
# we request parameter-shift (or "analytic") differentiation.
149144
grad_method = "A"
@@ -242,8 +237,7 @@ If the above operator omitted the ``_unflatten`` custom definition, it would rai
242237
For local testing, try type(op)._unflatten(*op._flatten())
243238
244239
245-
The new gate can be used with PennyLane devices. Device support for an operation can be checked via
246-
``dev.stopping_condition(op)``. If ``True``, then the device supports the operation.
240+
The new gate can be used with PennyLane devices.
247241

248242
``DefaultQubit`` first checks if the operator has a matrix using the :attr:`~.Operator.has_matrix` property.
249243

doc/releases/changelog-dev.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@
127127
* Alias for Identity (`I`) is now accessible from `qml.ops`.
128128
[(#7200)](https://github.com/PennyLaneAI/pennylane/pull/7200)
129129

130+
* `Operator.num_wires` now defaults to `None` to indicate that the operator can be on
131+
any number of wires.
132+
[(#7312)](https://github.com/PennyLaneAI/pennylane/pull/7312)
133+
130134
* Shots can now be overridden for specific `qml.Snapshot` instances via a `shots` keyword argument.
131135
[(#7326)](https://github.com/PennyLaneAI/pennylane/pull/7326)
132136

pennylane/noise/conditionals.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import pennylane as qml
2222
from pennylane.boolean_fn import BooleanFn
2323
from pennylane.measurements import MeasurementProcess, MeasurementValue, MidMeasureMP
24-
from pennylane.operation import AnyWires
2524
from pennylane.ops import Adjoint, Controlled
2625
from pennylane.templates import ControlledSequence
2726
from pennylane.wires import WireError, Wires
@@ -747,7 +746,7 @@ def _partial(wires=None, **partial_kwargs):
747746
op_args[key] = val
748747

749748
if issubclass(op_class, qml.operation.Operation):
750-
num_wires = getattr(op_class, "num_wires", AnyWires)
749+
num_wires = getattr(op_class, "num_wires", None)
751750
if "wires" in op_args and isinstance(num_wires, int):
752751
if num_wires < len(op_args["wires"]) and num_wires == 1:
753752
op_wires = op_args.pop("wires")

pennylane/operation.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -302,20 +302,24 @@ class ParameterFrequenciesUndefinedError(OperatorPropertyUndefined):
302302
class WiresEnum(IntEnum):
303303
"""Integer enumeration class
304304
to represent the number of wires
305-
an operation acts on"""
305+
an operation acts on.
306+
307+
"""
306308

307309
AnyWires = -1
310+
"""A enumeration that represents that an operator can act on any number of wires.
311+
312+
"""
313+
308314
AllWires = -2
315+
"""A enumeration that represents that an operator acts on all wires in the system.
309316
310317
311-
AllWires = WiresEnum.AllWires
312-
"""IntEnum: An enumeration which represents all wires in the
313-
subsystem. It is equivalent to an integer with value 0."""
318+
"""
314319

315-
AnyWires = WiresEnum.AnyWires
316-
"""IntEnum: An enumeration which represents any wires in the
317-
subsystem. It is equivalent to an integer with value -1."""
318320

321+
AnyWires = WiresEnum.AnyWires
322+
AllWires = WiresEnum.AllWires
319323

320324
# =============================================================================
321325
# Class property
@@ -434,11 +438,6 @@ class Operator(abc.ABC, metaclass=ABCCaptureMeta):
434438
435439
class FlipAndRotate(qml.operation.Operation):
436440
437-
# Define how many wires the operator acts on in total.
438-
# In our case this may be one or two, which is why we
439-
# use the AnyWires Enumeration to indicate a variable number.
440-
num_wires = qml.operation.AnyWires
441-
442441
# This attribute tells PennyLane what differentiation method to use. Here
443442
# we request parameter-shift (or "analytic") differentiation.
444443
grad_method = "A"
@@ -972,7 +971,7 @@ def terms(self) -> tuple[list[TensorLike], list["Operation"]]: # pylint: disabl
972971
"""
973972
raise TermsUndefinedError
974973

975-
num_wires: Union[int, WiresEnum] = AnyWires
974+
num_wires: Optional[Union[int, WiresEnum]] = None
976975
"""Number of wires the operator acts on."""
977976

978977
@property
@@ -1136,7 +1135,9 @@ def __init__(
11361135
self._wires: Wires = Wires(wires)
11371136

11381137
# check that the number of wires given corresponds to required number
1139-
if self.num_wires not in {AllWires, AnyWires} and len(self._wires) != self.num_wires:
1138+
if (self.num_wires is not None and not isinstance(self.num_wires, WiresEnum)) and len(
1139+
self._wires
1140+
) != self.num_wires:
11401141
raise ValueError(
11411142
f"{self.name}: wrong number of wires. "
11421143
f"{len(self._wires)} wires given, {self.num_wires} expected."
@@ -1886,7 +1887,7 @@ def parameter_frequencies(self) -> list[tuple[Union[float, int]]]:
18861887
warnings.filterwarnings(
18871888
action="ignore", message=r".+ eigenvalues will be computed numerically\."
18881889
)
1889-
eigvals = qml.eigvals(gen, k=2**self.num_wires)
1890+
eigvals = qml.eigvals(gen, k=2 ** len(self.wires))
18901891

18911892
eigvals = tuple(np.round(eigvals, 8))
18921893
return [qml.gradients.eigvals_to_frequencies(eigvals)]

pennylane/ops/channel.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import warnings
2020

2121
from pennylane import math as np
22-
from pennylane.operation import AnyWires, Channel
22+
from pennylane.operation import Channel
2323
from pennylane.wires import Wires, WiresLike
2424

2525

@@ -559,9 +559,6 @@ class PauliError(Channel):
559559
[0.70710678, 0. ]])
560560
"""
561561

562-
num_wires = AnyWires
563-
"""int: Number of wires that the operator acts on."""
564-
565562
num_params = 2
566563
"""int: Number of trainable parameters that the operator depends on."""
567564

@@ -713,7 +710,6 @@ class QubitChannel(Channel):
713710
id (str or None): String representing the operation (optional)
714711
"""
715712

716-
num_wires = AnyWires
717713
grad_method = None
718714

719715
def __init__(self, K_list, wires: WiresLike, id=None):

pennylane/ops/cv.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from scipy.linalg import block_diag
4343

4444
from pennylane import math as qml_math
45-
from pennylane.operation import AnyWires, CVObservable, CVOperation
45+
from pennylane.operation import CVObservable, CVOperation
4646

4747
from .identity import I, Identity # pylint: disable=unused-import
4848
from .meta import Snapshot # pylint: disable=unused-import
@@ -667,7 +667,6 @@ class InterferometerUnitary(CVOperation):
667667
"""
668668

669669
num_params = 1
670-
num_wires = AnyWires
671670
grad_method = None
672671
grad_recipe = None
673672

@@ -833,7 +832,6 @@ class GaussianState(CVOperation):
833832
"""
834833

835834
num_params = 2
836-
num_wires = AnyWires
837835
grad_method = "F"
838836

839837
def __init__(self, V, r, wires, id=None):
@@ -952,7 +950,6 @@ def circuit():
952950
"""
953951

954952
num_params = 1
955-
num_wires = AnyWires
956953
grad_method = "F"
957954

958955
def __init__(self, state, wires, id=None):
@@ -1001,7 +998,6 @@ class FockDensityMatrix(CVOperation):
1001998
"""
1002999

10031000
num_params = 1
1004-
num_wires = AnyWires
10051001
grad_method = "F"
10061002

10071003
def __init__(self, state, wires, id=None):
@@ -1133,7 +1129,6 @@ class TensorN(CVObservable):
11331129
"""
11341130

11351131
num_params = 0
1136-
num_wires = AnyWires
11371132
ev_order = None
11381133

11391134
def __init__(self, wires):
@@ -1326,7 +1321,6 @@ class PolyXP(CVObservable):
13261321
"""
13271322

13281323
num_params = 1
1329-
num_wires = AnyWires
13301324

13311325
grad_method = "F"
13321326
ev_order = 2
@@ -1385,7 +1379,6 @@ class FockStateProjector(CVObservable):
13851379
"""
13861380

13871381
num_params = 1
1388-
num_wires = AnyWires
13891382

13901383
grad_method = None
13911384
ev_order = None

pennylane/ops/identity.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,7 @@
2121
from scipy import sparse
2222

2323
import pennylane as qml
24-
from pennylane.operation import (
25-
AllWires,
26-
AnyWires,
27-
CVObservable,
28-
Operation,
29-
SparseMatrixUndefinedError,
30-
)
24+
from pennylane.operation import CVObservable, Operation, SparseMatrixUndefinedError
3125
from pennylane.wires import WiresLike
3226

3327

@@ -52,8 +46,6 @@ class Identity(CVObservable, Operation):
5246
"""
5347

5448
num_params = 0
55-
num_wires = AnyWires
56-
"""int: Number of wires that the operator acts on."""
5749

5850
grad_method = None
5951
"""Gradient computation method."""
@@ -299,9 +291,6 @@ def circuit():
299291
300292
"""
301293

302-
num_wires = AllWires
303-
"""int: Number of wires that the operator acts on."""
304-
305294
num_params = 1
306295
"""int: Number of trainable parameters that the operator depends on."""
307296

pennylane/ops/meta.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from typing import Literal, Optional, Sequence, Union
2323

2424
import pennylane as qml
25-
from pennylane.operation import AnyWires, Operation
25+
from pennylane.operation import Operation
2626
from pennylane.wires import Wires, WiresLike
2727

2828

@@ -43,9 +43,6 @@ class Barrier(Operation):
4343
num_params = 0
4444
"""int: Number of trainable parameters that the operator depends on."""
4545

46-
num_wires = AnyWires
47-
par_domain = None
48-
4946
def __init__(self, wires: WiresLike = (), only_visual=False, id=None):
5047
wires = Wires(wires)
5148
self.only_visual = only_visual
@@ -117,7 +114,6 @@ class WireCut(Operation):
117114
"""
118115

119116
num_params = 0
120-
num_wires = AnyWires
121117
grad_method = None
122118

123119
def __init__(self, wires: WiresLike = (), id=None):
@@ -211,7 +207,6 @@ def circuit():
211207
.. seealso:: :func:`~.snapshots`
212208
"""
213209

214-
num_wires = AnyWires
215210
num_params = 0
216211
grad_method = None
217212

pennylane/ops/op_math/condition.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from pennylane.capture import FlatFn
2424
from pennylane.compiler import compiler
2525
from pennylane.measurements import MeasurementValue, MidMeasureMP, get_mcm_predicates
26-
from pennylane.operation import AnyWires, Operation, Operator
26+
from pennylane.operation import Operation, Operator
2727
from pennylane.ops.op_math.symbolicop import SymbolicOp
2828

2929

@@ -88,8 +88,6 @@ class Conditional(SymbolicOp, Operation):
8888
can be useful for some applications where the instance has to be identified
8989
"""
9090

91-
num_wires = AnyWires
92-
9391
def __init__(self, expr, then_op: Type[Operation], id=None):
9492
self.hyperparameters["meas_val"] = expr
9593
self._name = f"Conditional({then_op.name})"

pennylane/ops/op_math/controlled_ops.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@
2424

2525
import pennylane as qml
2626
from pennylane.decomposition import add_decomps, register_resources
27-
from pennylane.operation import AnyWires, Wires
2827
from pennylane.ops.qubit.parametric_ops_single_qubit import stack_last
2928
from pennylane.typing import TensorLike
30-
from pennylane.wires import WiresLike
29+
from pennylane.wires import Wires, WiresLike
3130

3231
from .controlled import ControlledOp
3332
from .controlled_decompositions import decompose_mcx
@@ -94,9 +93,6 @@ class ControlledQubitUnitary(ControlledOp):
9493
>>> qml.ControlledQubitUnitary(U, wires=[0, 1, 2, 3], control_values=[False, True, True])
9594
"""
9695

97-
num_wires = AnyWires
98-
"""int: Number of wires that the operator acts on."""
99-
10096
num_params = 1
10197
"""int: Number of trainable parameters that the operator depends on."""
10298

@@ -1319,9 +1315,6 @@ class MultiControlledX(ControlledOp):
13191315
is_self_inverse = True
13201316
"""bool: Whether or not the operator is self-inverse."""
13211317

1322-
num_wires = AnyWires
1323-
"""int: Number of wires the operation acts on."""
1324-
13251318
num_params = 0
13261319
"""int: Number of trainable parameters that the operator depends on."""
13271320

pennylane/ops/op_math/exp.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from pennylane import math
2424
from pennylane.math import expand_matrix
2525
from pennylane.operation import (
26-
AnyWires,
2726
DecompositionUndefinedError,
2827
GeneratorUndefinedError,
2928
Operation,
@@ -297,11 +296,11 @@ def _smart_decomposition(self, coeff, base):
297296
for op_name in qml.ops.qubit.__all__: # pylint:disable=no-member
298297
op_class = getattr(qml.ops.qubit, op_name) # pylint:disable=no-member
299298
if op_class.has_generator:
300-
if op_class.num_wires == AnyWires:
299+
if op_class.num_wires is None:
301300
has_generator_types_anywires.append(op_class)
302301
elif op_class.num_wires == len(base.wires):
303302
has_generator_types.append(op_class)
304-
# Ensure op_class.num_wires == base.num_wires before op_class.num_wires == AnyWires
303+
# Ensure op_class.num_wires == base.num_wires before op_class.num_wires is None
305304
has_generator_types.extend(has_generator_types_anywires)
306305

307306
for op_class in has_generator_types:

pennylane/ops/op_math/linear_combination.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ class LinearCombination(Sum):
103103
using the :func:`compute_grouping <pennylane.ops.LinearCombination.compute_grouping>` method.
104104
"""
105105

106-
num_wires = qml.operation.AnyWires
107106
grad_method = "A" # supports analytic gradients
108107
batch_size = None
109108
ndim_params = None # could be (0,) * len(coeffs), but it is not needed. Define at class-level

pennylane/ops/qubit/arithmetic_ops.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
import pennylane as qml
2525
from pennylane.decomposition import add_decomps, register_resources
26-
from pennylane.operation import AnyWires, FlatPytree, Operation
26+
from pennylane.operation import FlatPytree, Operation
2727
from pennylane.ops import Identity
2828
from pennylane.typing import TensorLike
2929
from pennylane.wires import Wires, WiresLike
@@ -401,7 +401,6 @@ class IntegerComparator(Operation):
401401
"""
402402

403403
is_self_inverse: bool = True
404-
num_wires = AnyWires
405404
num_params: int = 0
406405
"""int: Number of trainable parameters that the operator depends on."""
407406

0 commit comments

Comments
 (0)