39
39
from cirq_google .experimental import ops as experimental_ops
40
40
41
41
42
- SYC_GATE_FAMILY = cirq .GateFamily (ops .SYC )
43
- SQRT_ISWAP_GATE_FAMILY = cirq .GateFamily (cirq .SQRT_ISWAP )
44
- SQRT_ISWAP_INV_GATE_FAMILY = cirq .GateFamily (cirq .SQRT_ISWAP_INV )
45
- CZ_GATE_FAMILY = cirq .GateFamily (cirq .CZ )
46
- PHASED_XZ_GATE_FAMILY = cirq .GateFamily (cirq .PhasedXZGate )
47
- VIRTUAL_ZPOW_GATE_FAMILY = cirq .GateFamily (cirq .ZPowGate , tags_to_ignore = [ops .PhysicalZTag ()])
48
- PHYSICAL_ZPOW_GATE_FAMILY = cirq .GateFamily (cirq .ZPowGate , tags_to_accept = [ops .PhysicalZTag ()])
49
- COUPLER_PULSE_GATE_FAMILY = cirq .GateFamily (experimental_ops .CouplerPulse )
50
- MEASUREMENT_GATE_FAMILY = cirq .GateFamily (cirq .MeasurementGate )
51
- WAIT_GATE_FAMILY = cirq .GateFamily (cirq .WaitGate )
42
+ # Gate family constants used in various parts of GridDevice logic.
43
+ _SYC_GATE_FAMILY = cirq .GateFamily (ops .SYC )
44
+ _SQRT_ISWAP_GATE_FAMILY = cirq .GateFamily (cirq .SQRT_ISWAP )
45
+ _SQRT_ISWAP_INV_GATE_FAMILY = cirq .GateFamily (cirq .SQRT_ISWAP_INV )
46
+ _CZ_GATE_FAMILY = cirq .GateFamily (cirq .CZ )
47
+ _PHASED_XZ_GATE_FAMILY = cirq .GateFamily (cirq .PhasedXZGate )
48
+ _VIRTUAL_ZPOW_GATE_FAMILY = cirq .GateFamily (cirq .ZPowGate , tags_to_ignore = [ops .PhysicalZTag ()])
49
+ _PHYSICAL_ZPOW_GATE_FAMILY = cirq .GateFamily (cirq .ZPowGate , tags_to_accept = [ops .PhysicalZTag ()])
50
+ _COUPLER_PULSE_GATE_FAMILY = cirq .GateFamily (experimental_ops .CouplerPulse )
51
+ _MEASUREMENT_GATE_FAMILY = cirq .GateFamily (cirq .MeasurementGate )
52
+ _WAIT_GATE_FAMILY = cirq .GateFamily (cirq .WaitGate )
53
+
54
+ _SYC_FSIM_GATE_FAMILY = ops .FSimGateFamily (gates_to_accept = [ops .SYC ])
55
+ _SQRT_ISWAP_FSIM_GATE_FAMILY = ops .FSimGateFamily (gates_to_accept = [cirq .SQRT_ISWAP ])
56
+ _SQRT_ISWAP_INV_FSIM_GATE_FAMILY = ops .FSimGateFamily (gates_to_accept = [cirq .SQRT_ISWAP_INV ])
57
+ _CZ_FSIM_GATE_FAMILY = ops .FSimGateFamily (gates_to_accept = [cirq .CZ ])
58
+
59
+
60
+ # TODO(#5050) Add GlobalPhaseGate
61
+ # Target gates of `cirq_google.GoogleCZTargetGateset`.
62
+ _CZ_TARGET_GATES = [_CZ_FSIM_GATE_FAMILY , _PHASED_XZ_GATE_FAMILY , _MEASUREMENT_GATE_FAMILY ]
63
+ # Target gates of `cirq_google.SycamoreTargetGateset`.
64
+ _SYC_TARGET_GATES = [_SYC_FSIM_GATE_FAMILY , _PHASED_XZ_GATE_FAMILY , _MEASUREMENT_GATE_FAMILY ]
65
+ # Target gates of `cirq.SqrtIswapTargetGateset`
66
+ _SQRT_ISWAP_TARGET_GATES = [
67
+ _SQRT_ISWAP_FSIM_GATE_FAMILY ,
68
+ _PHASED_XZ_GATE_FAMILY ,
69
+ _MEASUREMENT_GATE_FAMILY ,
70
+ ]
71
+
52
72
53
73
# Families of gates which can be applied to any subset of valid qubits.
54
- _VARIADIC_GATE_FAMILIES = [MEASUREMENT_GATE_FAMILY , WAIT_GATE_FAMILY ]
74
+ _VARIADIC_GATE_FAMILIES = [_MEASUREMENT_GATE_FAMILY , _WAIT_GATE_FAMILY ]
55
75
56
76
57
77
def _validate_device_specification (proto : v2 .device_pb2 .DeviceSpecification ) -> None :
@@ -115,19 +135,19 @@ def _build_gateset_and_gate_durations(
115
135
cirq_gates : List [Union [Type [cirq .Gate ], cirq .Gate , cirq .GateFamily ]] = []
116
136
117
137
if gate_name == 'syc' :
118
- cirq_gates = [ops . FSimGateFamily ( gates_to_accept = [ ops . SYC ]) ]
138
+ cirq_gates = [_SYC_FSIM_GATE_FAMILY ]
119
139
elif gate_name == 'sqrt_iswap' :
120
- cirq_gates = [ops . FSimGateFamily ( gates_to_accept = [ cirq . SQRT_ISWAP ]) ]
140
+ cirq_gates = [_SQRT_ISWAP_FSIM_GATE_FAMILY ]
121
141
elif gate_name == 'sqrt_iswap_inv' :
122
- cirq_gates = [ops . FSimGateFamily ( gates_to_accept = [ cirq . SQRT_ISWAP_INV ]) ]
142
+ cirq_gates = [_SQRT_ISWAP_INV_FSIM_GATE_FAMILY ]
123
143
elif gate_name == 'cz' :
124
- cirq_gates = [ops . FSimGateFamily ( gates_to_accept = [ cirq . CZ ]) ]
144
+ cirq_gates = [_CZ_FSIM_GATE_FAMILY ]
125
145
elif gate_name == 'phased_xz' :
126
146
cirq_gates = [cirq .PhasedXZGate , cirq .XPowGate , cirq .YPowGate , cirq .PhasedXPowGate ]
127
147
elif gate_name == 'virtual_zpow' :
128
- cirq_gates = [cirq . GateFamily ( cirq . ZPowGate , tags_to_ignore = [ ops . PhysicalZTag ()]) ]
148
+ cirq_gates = [_VIRTUAL_ZPOW_GATE_FAMILY ]
129
149
elif gate_name == 'physical_zpow' :
130
- cirq_gates = [cirq . GateFamily ( cirq . ZPowGate , tags_to_accept = [ ops . PhysicalZTag ()]) ]
150
+ cirq_gates = [_PHYSICAL_ZPOW_GATE_FAMILY ]
131
151
elif gate_name == 'coupler_pulse' :
132
152
cirq_gates = [experimental_ops .CouplerPulse ]
133
153
elif gate_name == 'meas' :
@@ -161,28 +181,27 @@ def _build_gateset_and_gate_durations(
161
181
def _build_compilation_target_gatesets (
162
182
gateset : cirq .Gateset ,
163
183
) -> Sequence [cirq .CompilationTargetGateset ]:
164
- """Detects compilation target gatesets based on what gates are inside the gateset.
165
-
166
- If a device contains gates which yield multiple compilation target gatesets, the user can only
167
- choose one target gateset to compile to. For example, a device may contain both SYC and
168
- SQRT_ISWAP gates which yield two separate target gatesets, but a circuit can only be compiled to
169
- either SYC or SQRT_ISWAP for its two-qubit gates, not both.
170
-
171
- TODO(#5050) when cirq-google CompilationTargetGateset subclasses are implemented, mention that
172
- gates which are part of the gateset but not the compilation target gateset are untouched when
173
- compiled.
174
- """
175
-
176
- # TODO(#5050) Subclass core CompilationTargetGatesets in cirq-google.
184
+ """Detects compilation target gatesets based on what gates are inside the gateset."""
177
185
186
+ # Include a particular target gateset if the device's gateset contains all required gates of
187
+ # the target gateset.
188
+ # Set all remaining gates in the device's gateset as `additional_gates` so that they are not
189
+ # decomposed in the transformation process.
178
190
target_gatesets : List [cirq .CompilationTargetGateset ] = []
179
- if cirq .CZ in gateset :
180
- target_gatesets .append (cirq .CZTargetGateset ())
181
- if ops .SYC in gateset :
191
+ if all (gate_family in gateset .gates for gate_family in _CZ_TARGET_GATES ):
192
+ target_gatesets .append (
193
+ transformers .GoogleCZTargetGateset (
194
+ additional_gates = list (gateset .gates - set (_CZ_TARGET_GATES ))
195
+ )
196
+ )
197
+ if all (gate_family in gateset .gates for gate_family in _SYC_TARGET_GATES ):
198
+ # TODO(#5050) SycamoreTargetGateset additional gates
182
199
target_gatesets .append (transformers .SycamoreTargetGateset ())
183
- if cirq . SQRT_ISWAP in gateset :
200
+ if all ( gate_family in gateset . gates for gate_family in _SQRT_ISWAP_TARGET_GATES ) :
184
201
target_gatesets .append (
185
- cirq .SqrtIswapTargetGateset (use_sqrt_iswap_inv = cirq .SQRT_ISWAP_INV in gateset )
202
+ cirq .SqrtIswapTargetGateset (
203
+ additional_gates = list (gateset .gates - set (_SQRT_ISWAP_TARGET_GATES ))
204
+ )
186
205
)
187
206
188
207
return tuple (target_gatesets )
@@ -265,7 +284,7 @@ class GridDevice(cirq.Device):
265
284
transform a circuit to one which only contains gates from a native target gateset
266
285
supported by the device.
267
286
>>> device.metadata.compilation_target_gatesets
268
- (...cirq.CZTargetGateset ...)
287
+ (...cirq_google.GoogleCZTargetGateset ...)
269
288
270
289
* Assuming valid CompilationTargetGatesets exist for the device, select the first one and
271
290
use it to transform a circuit to one which only contains gates from a native target
@@ -277,11 +296,18 @@ class GridDevice(cirq.Device):
277
296
>>> print(circuit)
278
297
(5, 1): ───PhXZ(a=0,x=1,z=0)───
279
298
280
- A note about CompilationTargetGatesets:
299
+ Notes about CompilationTargetGatesets:
281
300
282
- A circuit which contains `cirq.WaitGate`s will be dropped if it is transformed using
283
- CompilationTargetGatesets generated by GridDevice. To better control circuit timing, insert
284
- WaitGates after the circuit has been transformed.
301
+ * If a device contains gates which yield multiple compilation target gatesets, the user can only
302
+ choose one target gateset to compile to. For example, a device may contain both SYC and
303
+ SQRT_ISWAP gates which yield two separate target gatesets, but a circuit can only be compiled
304
+ to either SYC or SQRT_ISWAP for its two-qubit gates, not both.
305
+ * For a given compilation target gateset, gates which are part of the device's gateset but not
306
+ the target gateset are not decomposed. However, they may still be merged with other gates in
307
+ the circuit.
308
+ * A circuit which contains `cirq.WaitGate`s will be dropped if it is transformed using
309
+ CompilationTargetGatesets generated by GridDevice. To better control circuit timing, insert
310
+ WaitGates after the circuit has been transformed.
285
311
286
312
Notes for cirq_google internal implementation:
287
313
@@ -435,31 +461,34 @@ def _value_equality_values_(self):
435
461
def _set_gate_in_gate_spec (
436
462
gate_spec : v2 .device_pb2 .GateSpecification , gate_family : cirq .GateFamily
437
463
) -> None :
438
- if gate_family == SYC_GATE_FAMILY :
464
+ if gate_family == _SYC_GATE_FAMILY or gate_family == _SYC_FSIM_GATE_FAMILY :
439
465
gate_spec .syc .SetInParent ()
440
- elif gate_family == SQRT_ISWAP_GATE_FAMILY :
466
+ elif gate_family == _SQRT_ISWAP_GATE_FAMILY or gate_family == _SQRT_ISWAP_FSIM_GATE_FAMILY :
441
467
gate_spec .sqrt_iswap .SetInParent ()
442
- elif gate_family == SQRT_ISWAP_INV_GATE_FAMILY :
468
+ elif (
469
+ gate_family == _SQRT_ISWAP_INV_GATE_FAMILY
470
+ or gate_family == _SQRT_ISWAP_INV_FSIM_GATE_FAMILY
471
+ ):
443
472
gate_spec .sqrt_iswap_inv .SetInParent ()
444
- elif gate_family == CZ_GATE_FAMILY :
473
+ elif gate_family == _CZ_GATE_FAMILY or gate_family == _CZ_FSIM_GATE_FAMILY :
445
474
gate_spec .cz .SetInParent ()
446
- elif gate_family == PHASED_XZ_GATE_FAMILY :
475
+ elif gate_family == _PHASED_XZ_GATE_FAMILY :
447
476
gate_spec .phased_xz .SetInParent ()
448
- elif gate_family == VIRTUAL_ZPOW_GATE_FAMILY :
477
+ elif gate_family == _VIRTUAL_ZPOW_GATE_FAMILY :
449
478
gate_spec .virtual_zpow .SetInParent ()
450
- elif gate_family == PHYSICAL_ZPOW_GATE_FAMILY :
479
+ elif gate_family == _PHYSICAL_ZPOW_GATE_FAMILY :
451
480
gate_spec .physical_zpow .SetInParent ()
452
- elif gate_family == COUPLER_PULSE_GATE_FAMILY :
481
+ elif gate_family == _COUPLER_PULSE_GATE_FAMILY :
453
482
gate_spec .coupler_pulse .SetInParent ()
454
- elif gate_family == MEASUREMENT_GATE_FAMILY :
483
+ elif gate_family == _MEASUREMENT_GATE_FAMILY :
455
484
gate_spec .meas .SetInParent ()
456
- elif gate_family == WAIT_GATE_FAMILY :
485
+ elif gate_family == _WAIT_GATE_FAMILY :
457
486
gate_spec .wait .SetInParent ()
458
487
else :
459
488
raise ValueError (f'Unrecognized gate { gate_family } .' )
460
489
461
490
462
- def create_device_specification_proto (
491
+ def _create_device_specification_proto (
463
492
* ,
464
493
qubits : Collection [cirq .GridQubit ],
465
494
pairs : Collection [Tuple [cirq .GridQubit , cirq .GridQubit ]],
@@ -469,6 +498,13 @@ def create_device_specification_proto(
469
498
) -> v2 .device_pb2 .DeviceSpecification :
470
499
"""Serializes the given device information into a DeviceSpecification proto.
471
500
501
+ EXPERIMENTAL: DeviceSpecification serialization API may change.
502
+
503
+ This function does not serialize a `GridDevice`. Instead, it only takes a subset of device
504
+ information sufficient to populate the `DeviceSpecification` proto. This reduces the complexity
505
+ of constructing `DeviceSpecification` and `GridDevice` on server side by requiring only the bare
506
+ essential device information.
507
+
472
508
Args:
473
509
qubits: Collection of qubits available on the device.
474
510
pairs: Collection of bidirectional qubit couplings available on the device.
0 commit comments