Skip to content

Commit

Permalink
Disallow passing types as tags (#6947)
Browse files Browse the repository at this point in the history
* Disallow passing types as tags

- This has caused confusion when passing a tag type
with PhysicalZTag as a tag when you mean the instance
PhysicalZTag().
- Adds comments to TaggedOperation and Operation to explain the limitation.
  • Loading branch information
dstrain115 authored Jan 14, 2025
1 parent 326a287 commit 63e4c7d
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 3 deletions.
11 changes: 10 additions & 1 deletion cirq-core/cirq/ops/raw_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,9 @@ def with_tags(self, *new_tags: Hashable) -> 'cirq.Operation':
resulting operation to be eventually serialized into JSON, you should
also restrict the operation to be JSON serializable.
Please note that tags should be instantiated if classes are
used. Raw types are not allowed.
Args:
*new_tags: The tags to wrap this operation in.
"""
Expand Down Expand Up @@ -779,14 +782,17 @@ class TaggedOperation(Operation):
Tags added can be of any type, but they should be Hashable in order
to allow equality checking. If you wish to serialize operations into
JSON, you should restrict yourself to only use objects that have a JSON
serialization.
serialization. Tags cannot be raw types and should be instantiated
if classes are used.
See `Operation.with_tags()` for more information on intended usage.
"""

def __init__(self, sub_operation: 'cirq.Operation', *tags: Hashable):
self._sub_operation = sub_operation
self._tags = tuple(tags)
if any(isinstance(tag, type) for tag in tags):
raise ValueError('Tags cannot be types. Did you forget to instantiate the tag type?')

@property
def sub_operation(self) -> 'cirq.Operation':
Expand Down Expand Up @@ -836,6 +842,9 @@ def with_tags(self, *new_tags: Hashable) -> 'cirq.TaggedOperation':
Overloads Operation.with_tags to create a new TaggedOperation
that has the tags of this operation combined with the new_tags
specified as the parameter.
Please note that tags should be instantiated if classes are
used. Raw types are not allowed.
"""
if not new_tags:
return self
Expand Down
6 changes: 6 additions & 0 deletions cirq-core/cirq/ops/raw_types_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,12 @@ def test_tagged_operation():
assert op.with_qubits(q2).qubits == (q2,)
assert not cirq.is_measurement(op)

# Tags can't be types
# This is to prevent typos of cirq.X(q1).with_tags(TagType)
# when you meant cirq.X(q1).with_tags(TagType())
with pytest.raises(ValueError, match="cannot be types"):
_ = cirq.X(q1).with_tags(cirq.Circuit)


def test_with_tags_returns_same_instance_if_possible():
untagged = cirq.X(cirq.GridQubit(1, 1))
Expand Down
2 changes: 1 addition & 1 deletion cirq-google/cirq_google/devices/google_noise_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,6 @@ class NoiseModelFromGoogleNoiseProperties(devices.NoiseModelFromNoiseProperties)
"""A noise model defined from noise properties of a Google device."""

def is_virtual(self, op: cirq.Operation) -> bool:
return isinstance(op.gate, cirq.ZPowGate) and cirq_google.PhysicalZTag not in op.tags
return isinstance(op.gate, cirq.ZPowGate) and cirq_google.PhysicalZTag() not in op.tags

# noisy_moments is implemented by the superclass.
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def test_with_params_opid_with_gate():
@pytest.mark.parametrize(
'op',
[
(cirq.Z(cirq.LineQubit(0)) ** 0.3).with_tags(cirq_google.PhysicalZTag),
(cirq.Z(cirq.LineQubit(0)) ** 0.3).with_tags(cirq_google.PhysicalZTag()),
cirq.PhasedXZGate(x_exponent=0.8, z_exponent=0.2, axis_phase_exponent=0.1).on(
cirq.LineQubit(0)
),
Expand Down

0 comments on commit 63e4c7d

Please sign in to comment.