Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Tags and TaggedOperation class #2670

Merged
merged 15 commits into from
Feb 8, 2020

Conversation

dstrain115
Copy link
Collaborator

Draft of basic Operator Tag functionality.

  • Tags are a wrapper around strings that allow you to
    mark a specific instance of an operator for special processing.
  • This can be used, for example, to exclude certain operations
    from optimizer routines or give operations information specific
    to the underlying hardware.

This PR adds a Tag class which is a wrapper around a string and
can also be sub-classed.

It also adds a TaggedOperation class which wraps an Operation and
includes Tags on that Operation.

Draft of basic Operator Tag functionality.

- Tags are a wrapper around strings that allow you to
mark a specific instance of an operator for special processing.
- This can be used, for example, to exclude certain operations
from optimizer routines or give operations information specific
to the underlying hardware.

This PR adds a Tag class which is a wrapper around a string and
can also be sub-classed.

It also adds a TaggedOperation class which wraps an Operation and
includes Tags on that Operation.
@googlebot googlebot added the cla: yes Makes googlebot stop complaining. label Jan 5, 2020
@dstrain115
Copy link
Collaborator Author

Adding an additional reviewer. I'd love to get this reviewed this week. Thanks!

cirq/ops/raw_types.py Outdated Show resolved Hide resolved
cirq/ops/raw_types.py Outdated Show resolved Hide resolved
cirq/ops/raw_types.py Show resolved Hide resolved
return protocols.trace_distance_bound(self.sub_operation)

def _phase_by_(self, phase_turns: float,
qubit_index: int) -> 'TaggedOperation':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type here is TaggedOperation, but the method doesn't appear to preserve the tags.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. The intended behavior is that tagging only applies to that specific operation. Any modifications should drop the tags. This is probably the only way to have a consistent behavior.

For that reason, I have changed the return type to Operation. I also modified controlled_by, which was not following this convention.

@@ -392,6 +393,24 @@ def with_qubits(self, *new_qubits: 'cirq.Qid') -> 'cirq.Operation':
`qubits` property.
"""

def with_tags(self, *new_tags: Any) -> 'cirq.TaggedOperation':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should TaggedOperation override this to add new_tags to itself (or replace its tags with new_tags), instead of nesting it in another TaggedOperation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I added a with_tags() on TaggedOperation that avoids nesting.

@dstrain115 dstrain115 added the Ready for Re-Review For when reviewers take their time. label Feb 4, 2020
Copy link
Contributor

@Strilanc Strilanc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

We could consider switching the convention to "basic operations preserve tags" but I don't consider it blocking.


def __init__(self, sub_operation: 'cirq.Operation', *tags: Any):
self.sub_operation = sub_operation
self._tags = list(tags)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why convert it into a list when it's already a tuple? Tuple guarantees no shenanigans.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

@cduck cduck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments.

See Operation.with_tags() for more information on intended usage.
"""

def __init__(self, sub_operation: 'cirq.Operation', *tags: Any):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should tags be required to be Hashable or even JSON serializable?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to Hashable and put a warning in the pydoc to make tags JSON serialiable if you want to serialize the circuit. I don't think JSON serializability should be a strict requirement, but it's nice to remember.

return str(self)

def _value_equality_values_(self):
return (self.sub_operation, *self._tags)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems inefficient for a type that may be hashed often.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would it be less efficient than just the sub_operation plus tags?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking to avoid creating a new tuple of length 1+len(tags) by nesting tuples instead of flattening. Now that I think about it, there won't usually be a large number of tags so it really doesn't matter.

# in __init__
self._tags = tuple(...)

def _value_equality_values_(self):
    return (self.sub_operation, self._tags)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I was also confused about what you were concerned about. I have changed it to a tuple, though I doubt the performance will matter too much.

@dstrain115
Copy link
Collaborator Author

We could consider switching the convention to "basic operations preserve tags" but I don't consider it blocking.

I felt that was tricky because it raises the question of what a basic operation is, and when does or doesn't this apply. Making it so that any new creation deletes tags is sometimes annoying, but never ambiguous.

control_values=control_values)

@property
def tags(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

"""Returns a tuple of the operation's tags."""
return self._tags

def with_tags(self, *new_tags: Any) -> 'cirq.TaggedOperation':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to Hashable here as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@dstrain115 dstrain115 merged commit 2715417 into quantumlib:master Feb 8, 2020
@dstrain115 dstrain115 deleted the tagged_operation branch February 8, 2020 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Makes googlebot stop complaining. Ready for Re-Review For when reviewers take their time.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants