Skip to content

(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

Merged
merged 23 commits into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
185e95e
First pass, still needs tests.
95-martin-orion Mar 8, 2021
c80d982
Clean up TODOs
95-martin-orion Mar 9, 2021
1ee4b30
Basic (de-)serialization tests.
95-martin-orion Mar 9, 2021
fdaa216
Update gate_sets_test.
95-martin-orion Mar 9, 2021
4aa8ccf
Deserializer test coverage
95-martin-orion Mar 11, 2021
14ca867
CircuitOpSerializer test coverage
95-martin-orion Mar 11, 2021
de2b042
SerializableGateSet test coverage
95-martin-orion Mar 11, 2021
fded376
Known devices test coverage
95-martin-orion Mar 11, 2021
7f3a269
Formatting
95-martin-orion Mar 11, 2021
1877a71
Pick up changes in proto.
95-martin-orion Mar 17, 2021
8b2ed14
Rewind gate_sets_test format.
95-martin-orion Mar 17, 2021
b98219d
Avoid deprecated fields
95-martin-orion Mar 17, 2021
c3f5215
Merge remote-tracking branch 'upstream/master' into cirq-proto-serial-2
95-martin-orion Mar 22, 2021
69b7168
Update cirq.google refs
95-martin-orion Mar 22, 2021
138441b
Round out tests and docs
95-martin-orion Apr 12, 2021
f6020d4
Merge branch 'master' into cirq-proto-serial-2
95-martin-orion Apr 12, 2021
4759ff2
Use map for raw_constants in serializer
95-martin-orion Apr 12, 2021
c717ef9
Fix test typo
95-martin-orion Apr 12, 2021
0a90658
Support and test for subcircuits in device spec.
95-martin-orion Apr 20, 2021
a37dccb
Merge branch 'master' into cirq-proto-serial-2
95-martin-orion Apr 20, 2021
b7ab8d6
Docstring and deprecation fixes
95-martin-orion May 19, 2021
c40d061
Merge branch 'master' into cirq-proto-serial-2
95-martin-orion May 19, 2021
233fe88
Merge branch 'master' into cirq-proto-serial-2
CirqBot May 24, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cirq-google/cirq_google/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,13 @@
)

from cirq_google.op_deserializer import (
CircuitOpDeserializer,
DeserializingArg,
GateOpDeserializer,
)

from cirq_google.op_serializer import (
CircuitOpSerializer,
GateOpSerializer,
SerializingArg,
)
Expand Down
11 changes: 11 additions & 0 deletions cirq-google/cirq_google/common_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,11 @@ def _can_serialize_limited_iswap(exponent: float):
op_wrapper=lambda op, proto: _add_phase_match(op, proto),
)

#############################################
#
# Miscellaneous serializers and deserializers
#
#############################################

#
# WaitGate serializer and deserializer
Expand Down Expand Up @@ -675,3 +680,9 @@ def _can_serialize_limited_iswap(exponent: float):
],
num_qubits_param='num_qubits',
)

#
# CircuitOperation serializer and deserializer
#
CIRCUIT_OP_SERIALIZER = op_serializer.CircuitOpSerializer()
CIRCUIT_OP_DESERIALIZER = op_deserializer.CircuitOpDeserializer()
14 changes: 10 additions & 4 deletions cirq-google/cirq_google/devices/known_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from cirq._doc import document
from cirq.devices import GridQubit
from cirq_google import gate_sets, serializable_gate_set
from cirq_google import gate_sets, op_serializer, serializable_gate_set
from cirq_google.api import v2
from cirq_google.api.v2 import device_pb2
from cirq_google.devices.serializable_device import SerializableDevice
Expand Down Expand Up @@ -132,9 +132,9 @@ def create_device_proto_for_qubits(
gs_proto = out.valid_gate_sets.add()
gs_proto.name = gate_set.gate_set_name
gate_ids: Set[str] = set()
for gate_type in gate_set.serializers:
for serializer in gate_set.serializers[gate_type]:
gate_id = serializer.serialized_gate_id
for internal_type in gate_set.serializers:
for serializer in gate_set.serializers[internal_type]:
gate_id = serializer.serialized_id
if gate_id in gate_ids:
# Only add each type once
continue
Expand All @@ -143,7 +143,13 @@ def create_device_proto_for_qubits(
gate = gs_proto.valid_gates.add()
gate.id = gate_id

if not isinstance(serializer, op_serializer.GateOpSerializer):
# This implies that 'serializer' handles non-gate ops,
# such as CircuitOperations. No other properties apply.
continue

# Choose target set and number of qubits based on gate type.
gate_type = internal_type

# Note: if it is not a measurement gate and doesn't inherit
# from SingleQubitGate, it's assumed to be a two qubit gate.
Expand Down
86 changes: 86 additions & 0 deletions cirq-google/cirq_google/devices/known_devices_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,40 @@ def test_sycamore_devices(device):
assert device.duration_of(sqrt_iswap) == cirq.Duration(nanos=32)


def test_sycamore_circuitop_device():
circuitop_gateset = cirq.google.serializable_gate_set.SerializableGateSet(
gate_set_name='circuitop_gateset',
serializers=[cgc.CIRCUIT_OP_SERIALIZER],
deserializers=[cgc.CIRCUIT_OP_DESERIALIZER],
)
gateset_list = [
cirq.google.gate_sets.SQRT_ISWAP_GATESET,
cirq.google.gate_sets.SYC_GATESET,
circuitop_gateset,
]
circuitop_proto = cirq.google.devices.known_devices.create_device_proto_from_diagram(
known_devices._SYCAMORE23_GRID,
gateset_list,
known_devices._SYCAMORE_DURATIONS_PICOS,
)
device = cirq.google.SerializableDevice.from_proto(
proto=circuitop_proto,
gate_sets=gateset_list,
)
q0 = cirq.GridQubit(5, 3)
q1 = cirq.GridQubit(5, 4)
syc = cirq.FSimGate(theta=np.pi / 2, phi=np.pi / 6)(q0, q1)
sqrt_iswap = cirq.FSimGate(theta=np.pi / 4, phi=0)(q0, q1)
circuit_op = cirq.CircuitOperation(cirq.FrozenCircuit(syc, sqrt_iswap))
device.validate_operation(syc)
device.validate_operation(sqrt_iswap)
device.validate_operation(circuit_op)
assert device.duration_of(syc) == cirq.Duration(nanos=12)
assert device.duration_of(sqrt_iswap) == cirq.Duration(nanos=32)
# CircuitOperations don't have a set duration.
assert device.duration_of(circuit_op) == cirq.Duration(nanos=0)


def test_sycamore_grid_layout():
# Qubits on Sycamore but not on Sycamore23
q0 = cirq.GridQubit(5, 5)
Expand All @@ -498,6 +532,58 @@ def test_sycamore_grid_layout():
cirq_google.Sycamore23.validate_operation(sqrt_iswap)


def test_proto_with_circuitop():
circuitop_gateset = cirq.google.serializable_gate_set.SerializableGateSet(
gate_set_name='circuitop_gateset',
serializers=[cgc.CIRCUIT_OP_SERIALIZER],
deserializers=[cgc.CIRCUIT_OP_DESERIALIZER],
)
circuitop_proto = cirq.google.devices.known_devices.create_device_proto_from_diagram(
"aa\naa",
[circuitop_gateset],
)

assert (
str(circuitop_proto)
== """\
valid_gate_sets {
name: "circuitop_gateset"
valid_gates {
id: "circuit"
}
}
valid_qubits: "0_0"
valid_qubits: "0_1"
valid_qubits: "1_0"
valid_qubits: "1_1"
valid_targets {
name: "meas_targets"
target_ordering: SUBSET_PERMUTATION
}
valid_targets {
name: "2_qubit_targets"
target_ordering: SYMMETRIC
targets {
ids: "0_0"
ids: "0_1"
}
targets {
ids: "0_0"
ids: "1_0"
}
targets {
ids: "0_1"
ids: "1_1"
}
targets {
ids: "1_0"
ids: "1_1"
}
}
"""
)


def test_proto_with_waitgate():
wait_gateset = cirq_google.serializable_gate_set.SerializableGateSet(
gate_set_name='wait_gateset',
Expand Down
24 changes: 15 additions & 9 deletions cirq-google/cirq_google/devices/serializable_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,20 @@ def from_proto(
# Loop through serializers and map gate_definitions to type
gates_by_type: Dict[Type['cirq.Gate'], List[_GateDefinition]] = {}
for gate_set in gate_sets:
for gate_type in gate_set.supported_gate_types():
for serializer in gate_set.serializers[gate_type]:
gate_id = serializer.serialized_gate_id
if gate_id not in gate_definitions:
for internal_type in gate_set.supported_internal_types():
for serializer in gate_set.serializers[internal_type]:
serialized_id = serializer.serialized_id
if serialized_id not in gate_definitions:
raise ValueError(
f'Serializer has {gate_id} which is not supported '
f'Serializer has {serialized_id} which is not supported '
'by the device specification'
)
if gate_type not in gates_by_type:
gates_by_type[gate_type] = []
gate_def = gate_definitions[gate_id].with_can_serialize_predicate(
if internal_type not in gates_by_type:
gates_by_type[internal_type] = []
gate_def = gate_definitions[serialized_id].with_can_serialize_predicate(
serializer.can_serialize_predicate
)
gates_by_type[gate_type].append(gate_def)
gates_by_type[internal_type].append(gate_def)

return SerializableDevice(
qubits=[cls._qid_from_str(q) for q in proto.valid_qubits],
Expand Down Expand Up @@ -264,6 +264,12 @@ def _find_operation_type(self, op: 'cirq.Operation') -> Optional[_GateDefinition
the value corresponding to that key or None if no type matches
"""
for type_key, gate_defs in self.gate_definitions.items():
if type_key == circuits.FrozenCircuit and isinstance(
op.untagged, circuits.CircuitOperation
):
for gate_def in gate_defs:
if gate_def.can_serialize_predicate(op):
return gate_def
if isinstance(op.gate, type_key):
for gate_def in gate_defs:
if gate_def.can_serialize_predicate(op):
Expand Down
2 changes: 2 additions & 0 deletions cirq-google/cirq_google/json_test_data/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
],
should_not_be_serialized=[
'AnnealSequenceSearchStrategy',
'CircuitOpDeserializer',
'CircuitOpSerializer',
'CircuitWithCalibration',
'ConvertToSqrtIswapGates',
'ConvertToSycamoreGates',
Expand Down
Loading