-
Notifications
You must be signed in to change notification settings - Fork 1.1k
(De-)serialization of CircuitOperations #3923
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
Conversation
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 |
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. |
Pinging @dstrain115 and @maffoo for review. |
assert ( | ||
str(circuitop_proto) | ||
== """\ | ||
valid_gate_sets { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
def serialized_id(self) -> str: | ||
"""Returns the string identifier for the resulting serialized object. | ||
|
||
This value should reflect the internal_type of the serializer. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
|
||
msg = msg or v2.program_pb2.CircuitOperation() | ||
try: | ||
msg.circuit_constant_index = raw_constants.index(op.circuit) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
cirq/google/op_serializer_test.py
Outdated
raw_constants = [default_circuit()] | ||
|
||
repetition_spec = v2.program_pb2.RepetitionSpecification() | ||
repetition_spec.repetition_count = 1 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
ba6b592
to
a37dccb
Compare
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. |
Pinging @dstrain115 for re-review. |
There was a problem hiding this 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.""" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.') |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.""" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.""" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge conflict
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another merge conflict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved.
There was a problem hiding this 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.""" |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.') |
There was a problem hiding this comment.
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.""" |
There was a problem hiding this comment.
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.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
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
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
Follow up for #3891. Part of #3634.
This PR adds the
CircuitOp(De)serializer
classes and updates existing behavior to handle them appropriately, including:Op(De)serializer
superclasses for operation (de-)serializersGateOp(De)serializer
fields to non-public, with public propertiesgate_type
->internal_type
)Changes not included in this PR:
CircuitOperation
(de-)serializers to the default QCS gateset