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

(De-)serialization of CircuitOperations #3923

Merged
merged 23 commits into from
May 24, 2021

Conversation

95-martin-orion
Copy link
Collaborator

Follow up for #3891. Part of #3634.

This PR adds the CircuitOp(De)serializer classes and updates existing behavior to handle them appropriately, including:

  • Addition of Op(De)serializer superclasses for operation (de-)serializers
  • Backwards-compatible conversion of GateOp(De)serializer fields to non-public, with public properties
  • Updates and deprecations for names made awkward by this change (e.g. gate_type -> internal_type)

Changes not included in this PR:

  • Add CircuitOperation (de-)serializers to the default QCS gateset

@95-martin-orion
Copy link
Collaborator Author

95-martin-orion commented Mar 17, 2021

TODO in this PR: replace newly-deprecated fields in tests and add deprecation tests for these fields.

@95-martin-orion
Copy link
Collaborator Author

TODO in this PR: replace newly-deprecated fields in tests and add deprecation tests for these fields.

This is now done for tests caught by check/pytest-changed-files. May still hit some bumps if other uses of these fields are floating around the repo somewhere.

@95-martin-orion
Copy link
Collaborator Author

I realized while looking at the internal tools that the current proto format for moments (ops + circuit ops) will cause downstream tools to silently ignore circuit operations in circuits. One possible workaround is to append an invalid 'flag' operation to moments with circuit operations to cause a failure; tools with circuit operation support would then need to identify and ignore these 'flag' operations.

@95-martin-orion
Copy link
Collaborator Author

Pinging @dstrain115 and @maffoo for review.

assert (
str(circuitop_proto)
== """\
valid_gate_sets {
Copy link
Collaborator

Choose a reason for hiding this comment

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

One thing that we should think about is whether a device specification should specify that the device supports circuit operations or not. (Or should we assume they all support circuit operations?)

This may have to be in a later PR, since it involves further proto changes, but we should give it some thought and maybe add an issue about it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Apart from the transitional phase where we're still bringing support online, I think assuming all devices support circuit operations is valid, since in the worst case you can simply decompose the circuit operation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

TODO(95-martin-orion): test creating a device spec with CircuitOperation to identify necessary changes / ensure that this is well-behaved.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@dstrain115: added test_sycamore_circuitop_device to provide this coverage, and it failed. Updated serializable_device to resolve the issue.

cirq/google/op_deserializer.py Outdated Show resolved Hide resolved
cirq/google/op_deserializer.py Outdated Show resolved Hide resolved
cirq/google/op_deserializer.py Outdated Show resolved Hide resolved
cirq/google/op_deserializer.py Outdated Show resolved Hide resolved
def serialized_id(self) -> str:
"""Returns the string identifier for the resulting serialized object.

This value should reflect the internal_type of the serializer.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am not sure I understand what this sentence means. What does "should reflect the internal_type" imply?
Same comment for deserializer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I must have misunderstood the IDs when typing this up (plus a copy-paste error in the deserializer comment). Updated to (hopefully) more accurately represent the behavior.

cirq/google/op_serializer.py Outdated Show resolved Hide resolved

msg = msg or v2.program_pb2.CircuitOperation()
try:
msg.circuit_constant_index = raw_constants.index(op.circuit)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any idea if this will be a performance concern? It seems we are doing a O(n) search of comparisons of potentially big circuits here. I am not sure how fast comparing two circuits would be. Maybe this is not a huge concern since a circuit would likely not have too many circuitsops, but this does seem to be a potential performance issue.

Do you think it is worth making raw_constants a dictionary instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's a legitimate concern, although I would hope proper use of CircuitOperations would limit the size of these circuits somewhat. Since op.circuit is guaranteed to be a hashable FrozenCircuit, I'll change this to a constant-to-index map.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Switched to a map. Since this broke the symmetry between raw_constants in the serializer and deserializer, I went ahead with the rename to deserialized_constants in the deserializer as well.

raw_constants = [default_circuit()]

repetition_spec = v2.program_pb2.RepetitionSpecification()
repetition_spec.repetition_count = 1
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would also test different repetition specs.

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. Also changed the serializer code, since the old behavior failed this new test.

cirq/google/op_serializer_test.py Outdated Show resolved Hide resolved
@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@95-martin-orion
Copy link
Collaborator Author

Apologies for the review spam, everyone - had some troubles merging master into this PR. It should be resolved now - feel free to unsubscribe from this if it's still spamming you.

@95-martin-orion
Copy link
Collaborator Author

Pinging @dstrain115 for re-review.

Copy link
Collaborator

@dstrain115 dstrain115 left a comment

Choose a reason for hiding this comment

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

Mostly doc comments and then LGTM.

@@ -31,6 +36,46 @@
import cirq


class OpDeserializer(abc.ABC):
"""Generic supertype for op deserializers."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe put "operation deserializers" to avoid using an abbreviation in the docstring.

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.

"""

@property # type: ignore
@deprecated(deadline='v0.12', fix='Use serialized_id instead.')
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why does this need to be deprecated if it is a new class? Is this because OpDeserializer is itself deprecating a class?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You have a point - I needed it here to get the tests working initially, but now it can be safely relocated to the GateOpDeserializer.

Applied this change and updated all deprecation deadlines to v0.13, since we are now in v0.11.

def serialized_id(self) -> str:
"""Returns the string identifier for the accepted serialized objects.

This ID denotes the serialization format this deserializer consumes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I can't understand what this docstring means. Maybe an example or concrete statement would help?

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.

constants: List[v2.program_pb2.Constant] = None,
deserialized_constants: List[Any] = None,
) -> 'cirq.CircuitOperation':
"""Turns a cirq.google.api.v2.CircuitOperation proto into a CircuitOperation."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add an Args section or at least point out that constants should have been previously parsed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copied the docstring down from the superclass method and added changes as necessary. Same for the from_proto method of the GateOpDeserializer.

@@ -362,3 +329,167 @@ def test_token_with_references():

with pytest.raises(ValueError, match='Proto has references to constants table'):
deserializer.from_proto(serialized)


DEFAULT_TOKEN = 'test_tag'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this go at the top of the file?

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.

@@ -30,6 +32,78 @@
Gate = TypeVar('Gate', bound=ops.Gate)


class OpSerializer(abc.ABC):
"""Generic supertype for op serializers."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, recommend using operation. It might be good to explain each of these abstract classes further, if possible 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.

@@ -392,3 +406,139 @@ def test_token_serialization_with_constant_reference(constants, expected_index,
GateWithAttribute(0.125)(q).with_tags(tag), constants=constants
)
assert constants == expected_constants


DEFAULT_TOKEN = 'test_tag'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Put at top of file?

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.

Returns:
A dictionary corresponds to the cirq_google.api.v2.Operation proto.
Returns:
<<<<<<< HEAD:cirq/google/serializable_gate_set.py
Copy link
Collaborator

Choose a reason for hiding this comment

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

Merge conflict

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Resolved.

cirq_google.api.v2.Operation proto.
Args:
operation_proto: A dictionary representing a
<<<<<<< HEAD:cirq/google/serializable_gate_set.py
Copy link
Collaborator

Choose a reason for hiding this comment

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

Another merge conflict.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Resolved.

Copy link
Collaborator Author

@95-martin-orion 95-martin-orion left a comment

Choose a reason for hiding this comment

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

Review comments addressed, PTAL.

@@ -31,6 +36,46 @@
import cirq


class OpDeserializer(abc.ABC):
"""Generic supertype for op deserializers."""
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.

def serialized_id(self) -> str:
"""Returns the string identifier for the accepted serialized objects.

This ID denotes the serialization format this deserializer consumes.
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.

@@ -362,3 +329,167 @@ def test_token_with_references():

with pytest.raises(ValueError, match='Proto has references to constants table'):
deserializer.from_proto(serialized)


DEFAULT_TOKEN = 'test_tag'
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.

@@ -392,3 +406,139 @@ def test_token_serialization_with_constant_reference(constants, expected_index,
GateWithAttribute(0.125)(q).with_tags(tag), constants=constants
)
assert constants == expected_constants


DEFAULT_TOKEN = 'test_tag'
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.

Returns:
A dictionary corresponds to the cirq_google.api.v2.Operation proto.
Returns:
<<<<<<< HEAD:cirq/google/serializable_gate_set.py
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Resolved.

cirq_google.api.v2.Operation proto.
Args:
operation_proto: A dictionary representing a
<<<<<<< HEAD:cirq/google/serializable_gate_set.py
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Resolved.

"""

@property # type: ignore
@deprecated(deadline='v0.12', fix='Use serialized_id instead.')
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You have a point - I needed it here to get the tests working initially, but now it can be safely relocated to the GateOpDeserializer.

Applied this change and updated all deprecation deadlines to v0.13, since we are now in v0.11.

constants: List[v2.program_pb2.Constant] = None,
deserialized_constants: List[Any] = None,
) -> 'cirq.CircuitOperation':
"""Turns a cirq.google.api.v2.CircuitOperation proto into a CircuitOperation."""
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copied the docstring down from the superclass method and added changes as necessary. Same for the from_proto method of the GateOpDeserializer.

@@ -30,6 +32,78 @@
Gate = TypeVar('Gate', bound=ops.Gate)


class OpSerializer(abc.ABC):
"""Generic supertype for op serializers."""
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.

@95-martin-orion 95-martin-orion added the automerge Tells CirqBot to sync and merge this PR. (If it's running.) label May 24, 2021
@CirqBot CirqBot added the front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. label May 24, 2021
@CirqBot CirqBot merged commit 71285d2 into quantumlib:master May 24, 2021
@CirqBot CirqBot removed automerge Tells CirqBot to sync and merge this PR. (If it's running.) front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. labels May 24, 2021
NoureldinYosri pushed a commit to NoureldinYosri/Cirq that referenced this pull request May 25, 2021
Follow up for quantumlib#3891. Part of quantumlib#3634.

This PR adds the `CircuitOp(De)serializer` classes and updates existing behavior to handle them appropriately, including:
- Addition of `Op(De)serializer` superclasses for operation (de-)serializers
- Backwards-compatible conversion of `GateOp(De)serializer` fields to non-public, with public properties
- Updates and deprecations for names made awkward by this change (e.g. `gate_type` -> `internal_type`)

Changes **not** included in this PR:
- Add `CircuitOperation` (de-)serializers to the default QCS gateset
rht pushed a commit to rht/Cirq that referenced this pull request May 1, 2023
Follow up for quantumlib#3891. Part of quantumlib#3634.

This PR adds the `CircuitOp(De)serializer` classes and updates existing behavior to handle them appropriately, including:
- Addition of `Op(De)serializer` superclasses for operation (de-)serializers
- Backwards-compatible conversion of `GateOp(De)serializer` fields to non-public, with public properties
- Updates and deprecations for names made awkward by this change (e.g. `gate_type` -> `internal_type`)

Changes **not** included in this PR:
- Add `CircuitOperation` (de-)serializers to the default QCS gateset
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.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants