1# Copyright 2019 The Cirq Developers
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Common Serializers that can be used by APIs.
15
16This file contains the following serializers (and corresponding deserializers)
17
18    - SINGLE_QUBIT_SERIALIZERS: A list of GateOpSerializer for single qubit
19        rotations using cirq Gates.
20    - MEASUREMENT_SERIALIZER:  Single GateOpSerializer for the measurement gate
21    - SINGLE_QUBIT_SERIALIZERS: A list of GateOpSerializer for single qubit
22        rotations confined to half-pi increments using cirq Gates.
23
24"""
25from typing import cast, List, Union
26
27import numpy as np
28import sympy
29
30import cirq
31from cirq_google.api import v2
32from cirq_google.experimental.ops import CouplerPulse
33from cirq_google.ops import PhysicalZTag
34from cirq_google.serialization import op_deserializer, op_serializer
35
36# Type strings used in serialization for the two types of Z operations
37PHYSICAL_Z = 'physical'
38VIRTUAL_Z = 'virtual_propagates_forward'
39
40# Strings used for phase matching args
41PHASE_MATCH_PHYS_Z = 'phys_z'
42
43
44# Default tolerance for differences in floating point
45# Note that Google protocol buffers use floats
46# which trigger a conversion from double precision to single precision
47# This results in errors possibly up to 1e-6
48# (23 bits for mantissa in single precision)
49_DEFAULT_ATOL = 1e-6
50
51
52def _near_mod_n(e, t, n, atol=_DEFAULT_ATOL):
53    """Returns whether a value, e, translated by t, is equal to 0 mod n."""
54    if isinstance(e, sympy.Symbol):
55        return False
56    return abs((e - t + 1) % n - 1) <= atol
57
58
59def _near_mod_2pi(e, t, atol=_DEFAULT_ATOL):
60    """Returns whether a value, e, translated by t, is equal to 0 mod 2 * pi."""
61    return _near_mod_n(e, t, n=2 * np.pi, atol=atol)
62
63
64def _near_mod_2(e, t, atol=_DEFAULT_ATOL):
65    """Returns whether a value, e, translated by t, is equal to 0 mod 2."""
66    return _near_mod_n(e, t, n=2, atol=atol)
67
68
69def _convert_physical_z(op: cirq.Operation, proto: v2.program_pb2.Operation):
70    if 'type' in proto.args:
71        if proto.args['type'].arg_value.string_value == PHYSICAL_Z:
72            return op.with_tags(PhysicalZTag())
73    return op
74
75
76#############################################
77#
78# Single qubit serializers and deserializers
79#
80#############################################
81
82#
83# Single qubit serializers for arbitrary rotations
84#
85SINGLE_QUBIT_SERIALIZERS = [
86    op_serializer.GateOpSerializer(
87        gate_type=cirq.PhasedXPowGate,
88        serialized_gate_id='xy',
89        args=[
90            op_serializer.SerializingArg(
91                serialized_name='axis_half_turns',
92                serialized_type=float,
93                op_getter='phase_exponent',
94            ),
95            op_serializer.SerializingArg(
96                serialized_name='half_turns',
97                serialized_type=float,
98                op_getter='exponent',
99            ),
100        ],
101    ),
102    op_serializer.GateOpSerializer(
103        gate_type=cirq.XPowGate,
104        serialized_gate_id='xy',
105        args=[
106            op_serializer.SerializingArg(
107                serialized_name='axis_half_turns',
108                serialized_type=float,
109                op_getter=lambda op: 0.0,
110            ),
111            op_serializer.SerializingArg(
112                serialized_name='half_turns',
113                serialized_type=float,
114                op_getter='exponent',
115            ),
116        ],
117    ),
118    op_serializer.GateOpSerializer(
119        gate_type=cirq.YPowGate,
120        serialized_gate_id='xy',
121        args=[
122            op_serializer.SerializingArg(
123                serialized_name='axis_half_turns',
124                serialized_type=float,
125                op_getter=lambda op: 0.5,
126            ),
127            op_serializer.SerializingArg(
128                serialized_name='half_turns',
129                serialized_type=float,
130                op_getter='exponent',
131            ),
132        ],
133    ),
134    op_serializer.GateOpSerializer(
135        gate_type=cirq.ZPowGate,
136        serialized_gate_id='z',
137        args=[
138            op_serializer.SerializingArg(
139                serialized_name='half_turns',
140                serialized_type=float,
141                op_getter='exponent',
142            ),
143            op_serializer.SerializingArg(
144                serialized_name='type',
145                serialized_type=str,
146                op_getter=lambda op: PHYSICAL_Z if PhysicalZTag() in op.tags else VIRTUAL_Z,
147            ),
148        ],
149    ),
150    op_serializer.GateOpSerializer(
151        gate_type=cirq.PhasedXZGate,
152        serialized_gate_id='xyz',
153        args=[
154            op_serializer.SerializingArg(
155                serialized_name='x_exponent',
156                serialized_type=float,
157                op_getter='x_exponent',
158            ),
159            op_serializer.SerializingArg(
160                serialized_name='z_exponent',
161                serialized_type=float,
162                op_getter='z_exponent',
163            ),
164            op_serializer.SerializingArg(
165                serialized_name='axis_phase_exponent',
166                serialized_type=float,
167                op_getter='axis_phase_exponent',
168            ),
169        ],
170    ),
171]
172
173#
174# Single qubit deserializers for arbitrary rotations
175#
176SINGLE_QUBIT_DESERIALIZERS = [
177    op_deserializer.GateOpDeserializer(
178        serialized_gate_id='xy',
179        gate_constructor=cirq.PhasedXPowGate,
180        args=[
181            op_deserializer.DeserializingArg(
182                serialized_name='axis_half_turns',
183                constructor_arg_name='phase_exponent',
184                default=0.0,
185            ),
186            op_deserializer.DeserializingArg(
187                serialized_name='half_turns',
188                constructor_arg_name='exponent',
189                default=1.0,
190            ),
191        ],
192    ),
193    op_deserializer.GateOpDeserializer(
194        serialized_gate_id='z',
195        gate_constructor=cirq.ZPowGate,
196        args=[
197            op_deserializer.DeserializingArg(
198                serialized_name='half_turns',
199                constructor_arg_name='exponent',
200                default=1.0,
201            ),
202        ],
203        op_wrapper=lambda op, proto: _convert_physical_z(op, proto),
204    ),
205    op_deserializer.GateOpDeserializer(
206        serialized_gate_id='xyz',
207        gate_constructor=cirq.PhasedXZGate,
208        args=[
209            op_deserializer.DeserializingArg(
210                serialized_name='x_exponent',
211                constructor_arg_name='x_exponent',
212                default=0.0,
213            ),
214            op_deserializer.DeserializingArg(
215                serialized_name='z_exponent',
216                constructor_arg_name='z_exponent',
217                default=0.0,
218            ),
219            op_deserializer.DeserializingArg(
220                serialized_name='axis_phase_exponent',
221                constructor_arg_name='axis_phase_exponent',
222                default=0.0,
223            ),
224        ],
225    ),
226]
227
228
229#
230# Measurement Serializer and Deserializer
231#
232MEASUREMENT_SERIALIZER = op_serializer.GateOpSerializer(
233    gate_type=cirq.MeasurementGate,
234    serialized_gate_id='meas',
235    args=[
236        op_serializer.SerializingArg(
237            serialized_name='key', serialized_type=str, op_getter=cirq.measurement_key_name
238        ),
239        op_serializer.SerializingArg(
240            serialized_name='invert_mask', serialized_type=List[bool], op_getter='invert_mask'
241        ),
242    ],
243)
244MEASUREMENT_DESERIALIZER = op_deserializer.GateOpDeserializer(
245    serialized_gate_id='meas',
246    gate_constructor=cirq.MeasurementGate,
247    args=[
248        op_deserializer.DeserializingArg(serialized_name='key', constructor_arg_name='key'),
249        op_deserializer.DeserializingArg(
250            serialized_name='invert_mask',
251            constructor_arg_name='invert_mask',
252            value_func=lambda x: tuple(cast(list, x)),
253        ),
254    ],
255    num_qubits_param='num_qubits',
256)
257
258
259#
260# Serializers for single qubit rotations confined to half-pi increments
261#
262SINGLE_QUBIT_HALF_PI_SERIALIZERS = [
263    op_serializer.GateOpSerializer(
264        gate_type=cirq.PhasedXPowGate,
265        serialized_gate_id='xy_pi',
266        args=[
267            op_serializer.SerializingArg(
268                serialized_name='axis_half_turns', serialized_type=float, op_getter='phase_exponent'
269            ),
270        ],
271        can_serialize_predicate=lambda op: _near_mod_2(
272            cast(cirq.PhasedXPowGate, op.gate).exponent, 1
273        ),
274    ),
275    op_serializer.GateOpSerializer(
276        gate_type=cirq.XPowGate,
277        serialized_gate_id='xy_pi',
278        args=[
279            op_serializer.SerializingArg(
280                serialized_name='axis_half_turns',
281                serialized_type=float,
282                op_getter=lambda op: (cast(cirq.XPowGate, op.gate).exponent - 1) / 2,
283            )
284        ],
285        can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.XPowGate, op.gate).exponent, 1),
286    ),
287    op_serializer.GateOpSerializer(
288        gate_type=cirq.YPowGate,
289        serialized_gate_id='xy_pi',
290        args=[
291            op_serializer.SerializingArg(
292                serialized_name='axis_half_turns',
293                serialized_type=float,
294                op_getter=lambda op: cast(cirq.YPowGate, op.gate).exponent / 2,
295            )
296        ],
297        can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.YPowGate, op.gate).exponent, 1),
298    ),
299    op_serializer.GateOpSerializer(
300        gate_type=cirq.XPowGate,
301        serialized_gate_id='xy_half_pi',
302        args=[
303            op_serializer.SerializingArg(
304                serialized_name='axis_half_turns',
305                serialized_type=float,
306                op_getter=lambda op: cast(cirq.XPowGate, op.gate).exponent - 0.5,
307            )
308        ],
309        can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.XPowGate, op.gate).exponent, 0.5),
310    ),
311    op_serializer.GateOpSerializer(
312        gate_type=cirq.YPowGate,
313        serialized_gate_id='xy_half_pi',
314        args=[
315            op_serializer.SerializingArg(
316                serialized_name='axis_half_turns',
317                serialized_type=float,
318                op_getter=lambda op: cast(cirq.YPowGate, op.gate).exponent,
319            )
320        ],
321        can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.YPowGate, op.gate).exponent, 0.5),
322    ),
323    op_serializer.GateOpSerializer(
324        gate_type=cirq.PhasedXPowGate,
325        serialized_gate_id='xy_half_pi',
326        args=[
327            op_serializer.SerializingArg(
328                serialized_name='axis_half_turns', serialized_type=float, op_getter='phase_exponent'
329            ),
330        ],
331        can_serialize_predicate=lambda op: _near_mod_2(
332            cast(cirq.PhasedXPowGate, op.gate).exponent, 0.5
333        ),
334    ),
335]
336
337#
338# Deserializers for single qubit rotations confined to half-pi increments
339#
340SINGLE_QUBIT_HALF_PI_DESERIALIZERS = [
341    op_deserializer.GateOpDeserializer(
342        serialized_gate_id='xy_pi',
343        gate_constructor=cirq.PhasedXPowGate,
344        args=[
345            op_deserializer.DeserializingArg(
346                serialized_name='axis_half_turns',
347                constructor_arg_name='phase_exponent',
348            ),
349            op_deserializer.DeserializingArg(
350                serialized_name='axis_half_turns',
351                constructor_arg_name='exponent',
352                value_func=lambda _: 1,
353            ),
354        ],
355    ),
356    op_deserializer.GateOpDeserializer(
357        serialized_gate_id='xy_half_pi',
358        gate_constructor=cirq.PhasedXPowGate,
359        args=[
360            op_deserializer.DeserializingArg(
361                serialized_name='axis_half_turns', constructor_arg_name='phase_exponent'
362            ),
363            op_deserializer.DeserializingArg(
364                serialized_name='axis_half_turns',
365                constructor_arg_name='exponent',
366                value_func=lambda _: 0.5,
367            ),
368        ],
369    ),
370]
371
372#############################################
373#
374# Two qubit serializers and deserializers
375#
376#############################################
377
378_phase_match_arg = op_serializer.SerializingArg(
379    serialized_name='phase_match',
380    serialized_type=str,
381    op_getter=lambda op: PHASE_MATCH_PHYS_Z if PhysicalZTag() in op.tags else None,
382    required=False,
383)
384
385
386def _add_phase_match(op: cirq.Operation, proto: v2.program_pb2.Operation):
387    if 'phase_match' in proto.args:
388        if proto.args['phase_match'].arg_value.string_value == PHASE_MATCH_PHYS_Z:
389            return op.with_tags(PhysicalZTag())
390    return op
391
392
393#
394# CZ Serializer and deserializer
395#
396
397# Only CZ
398CZ_SERIALIZER = op_serializer.GateOpSerializer(
399    gate_type=cirq.CZPowGate,
400    serialized_gate_id='cz',
401    args=[
402        op_serializer.SerializingArg(
403            serialized_name='half_turns', serialized_type=float, op_getter='exponent'
404        ),
405        _phase_match_arg,
406    ],
407    can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.CZPowGate, op.gate).exponent, 1.0),
408)
409
410# CZ to any power
411CZ_POW_SERIALIZER = op_serializer.GateOpSerializer(
412    gate_type=cirq.CZPowGate,
413    serialized_gate_id='cz',
414    args=[
415        op_serializer.SerializingArg(
416            serialized_name='half_turns', serialized_type=float, op_getter='exponent'
417        ),
418        _phase_match_arg,
419    ],
420)
421
422CZ_POW_DESERIALIZER = op_deserializer.GateOpDeserializer(
423    serialized_gate_id='cz',
424    gate_constructor=cirq.CZPowGate,
425    args=[
426        op_deserializer.DeserializingArg(
427            serialized_name='half_turns',
428            constructor_arg_name='exponent',
429            default=1.0,
430        ),
431    ],
432    op_wrapper=lambda op, proto: _add_phase_match(op, proto),
433)
434
435#
436# Sycamore Gate Serializer and deserializer
437#
438SYC_SERIALIZER = op_serializer.GateOpSerializer(
439    gate_type=cirq.FSimGate,
440    serialized_gate_id='syc',
441    args=[_phase_match_arg],
442    can_serialize_predicate=(
443        lambda op: _near_mod_2pi(cast(cirq.FSimGate, op.gate).theta, np.pi / 2)
444        and _near_mod_2pi(cast(cirq.FSimGate, op.gate).phi, np.pi / 6)
445    ),
446)
447
448SYC_DESERIALIZER = op_deserializer.GateOpDeserializer(
449    serialized_gate_id='syc',
450    gate_constructor=lambda: cirq.FSimGate(theta=np.pi / 2, phi=np.pi / 6),
451    args=[],
452    op_wrapper=lambda op, proto: _add_phase_match(op, proto),
453)
454
455#
456# sqrt(ISWAP) serializer and deserializer
457# (e.g. ISWAP ** 0.5)
458#
459SQRT_ISWAP_SERIALIZERS = [
460    op_serializer.GateOpSerializer(
461        gate_type=cirq.FSimGate,
462        serialized_gate_id='fsim_pi_4',
463        args=[_phase_match_arg],
464        can_serialize_predicate=(
465            lambda op: _near_mod_2pi(cast(cirq.FSimGate, op.gate).theta, np.pi / 4)
466            and _near_mod_2pi(cast(cirq.FSimGate, op.gate).phi, 0)
467        ),
468    ),
469    op_serializer.GateOpSerializer(
470        gate_type=cirq.ISwapPowGate,
471        serialized_gate_id='fsim_pi_4',
472        args=[_phase_match_arg],
473        can_serialize_predicate=(
474            lambda op: _near_mod_n(cast(cirq.ISwapPowGate, op.gate).exponent, -0.5, 4)
475        ),
476    ),
477    op_serializer.GateOpSerializer(
478        gate_type=cirq.FSimGate,
479        serialized_gate_id='inv_fsim_pi_4',
480        args=[_phase_match_arg],
481        can_serialize_predicate=(
482            lambda op: _near_mod_2pi(cast(cirq.FSimGate, op.gate).theta, -np.pi / 4)
483            and _near_mod_2pi(cast(cirq.FSimGate, op.gate).phi, 0)
484        ),
485    ),
486    op_serializer.GateOpSerializer(
487        gate_type=cirq.ISwapPowGate,
488        serialized_gate_id='inv_fsim_pi_4',
489        args=[_phase_match_arg],
490        can_serialize_predicate=(
491            lambda op: _near_mod_n(cast(cirq.ISwapPowGate, op.gate).exponent, +0.5, 4)
492        ),
493    ),
494]
495
496SQRT_ISWAP_DESERIALIZERS = [
497    op_deserializer.GateOpDeserializer(
498        serialized_gate_id='fsim_pi_4',
499        gate_constructor=lambda: cirq.FSimGate(theta=np.pi / 4, phi=0),
500        args=[],
501        op_wrapper=lambda op, proto: _add_phase_match(op, proto),
502    ),
503    op_deserializer.GateOpDeserializer(
504        serialized_gate_id='inv_fsim_pi_4',
505        gate_constructor=lambda: cirq.FSimGate(theta=-np.pi / 4, phi=0),
506        args=[],
507        op_wrapper=lambda op, proto: _add_phase_match(op, proto),
508    ),
509]
510
511
512#
513# FSim serializer
514# Only allows iswap, sqrt_iswap and their inverses, iswap, CZ, identity, and sycamore
515# Note that not all combinations may not be available on all processors
516def _can_serialize_limited_fsim(theta: float, phi: float):
517    # Symbols for LIMITED_FSIM are allowed, but may fail server-side
518    # if an incorrect run context is specified
519    if _near_mod_2pi(phi, 0) or isinstance(phi, sympy.Symbol):
520        if isinstance(theta, sympy.Symbol):
521            return True
522        # Identity
523        if _near_mod_2pi(theta, 0):
524            return True
525        # sqrt ISWAP
526        if _near_mod_2pi(theta, -np.pi / 4):
527            return True
528        # inverse sqrt ISWAP
529        if _near_mod_2pi(theta, np.pi / 4):
530            return True
531        # ISWAP
532        if _near_mod_2pi(theta, -np.pi / 2):
533            return True
534        # Inverse ISWAP
535        if _near_mod_2pi(theta, np.pi / 2):
536            return True
537    # Sycamore
538    if (
539        (_near_mod_2pi(theta, np.pi / 2) or isinstance(theta, sympy.Symbol))
540        and (_near_mod_2pi(phi, np.pi / 6))
541        or isinstance(phi, sympy.Symbol)
542    ):
543        return True
544    # CZ
545    if (
546        (_near_mod_2pi(theta, 0) or isinstance(theta, sympy.Symbol))
547        and (_near_mod_2pi(phi, np.pi))
548        or isinstance(phi, sympy.Symbol)
549    ):
550        return True
551    return False
552
553
554def _can_serialize_limited_iswap(exponent: float):
555    # Symbols for LIMITED_FSIM are allowed, but may fail server-side
556    # if an incorrect run context is specified
557    if isinstance(exponent, sympy.Symbol):
558        return True
559    # Sqrt ISWAP
560    if _near_mod_n(exponent, 0.5, 4):
561        return True
562    # Inverse Sqrt ISWAP
563    if _near_mod_n(exponent, -0.5, 4):
564        return True
565    # ISWAP
566    if _near_mod_n(exponent, -1.0, 4):
567        return True
568    # Inverse ISWAP
569    if _near_mod_n(exponent, 1.0, 4):
570        return True
571    # Identity
572    if _near_mod_n(exponent, 0.0, 4):
573        return True
574    return False
575
576
577LIMITED_FSIM_SERIALIZERS = [
578    op_serializer.GateOpSerializer(
579        gate_type=cirq.FSimGate,
580        serialized_gate_id='fsim',
581        args=[
582            op_serializer.SerializingArg(
583                serialized_name='theta', serialized_type=float, op_getter='theta'
584            ),
585            op_serializer.SerializingArg(
586                serialized_name='phi', serialized_type=float, op_getter='phi'
587            ),
588            _phase_match_arg,
589        ],
590        can_serialize_predicate=(
591            lambda op: _can_serialize_limited_fsim(
592                cast(cirq.FSimGate, op.gate).theta, cast(cirq.FSimGate, op.gate).phi
593            )
594        ),
595    ),
596    op_serializer.GateOpSerializer(
597        gate_type=cirq.ISwapPowGate,
598        serialized_gate_id='fsim',
599        args=[
600            op_serializer.SerializingArg(
601                serialized_name='theta',
602                serialized_type=float,
603                # Note that ISWAP ** 0.5 is Fsim(-pi/4,0)
604                op_getter=(lambda op: cast(cirq.ISwapPowGate, op.gate).exponent * -np.pi / 2),
605            ),
606            op_serializer.SerializingArg(
607                serialized_name='phi', serialized_type=float, op_getter=lambda e: 0
608            ),
609            _phase_match_arg,
610        ],
611        can_serialize_predicate=(
612            lambda op: _can_serialize_limited_iswap(cast(cirq.ISwapPowGate, op.gate).exponent)
613        ),
614    ),
615    op_serializer.GateOpSerializer(
616        gate_type=cirq.CZPowGate,
617        serialized_gate_id='fsim',
618        args=[
619            op_serializer.SerializingArg(
620                serialized_name='theta', serialized_type=float, op_getter=lambda e: 0
621            ),
622            op_serializer.SerializingArg(
623                serialized_name='phi', serialized_type=float, op_getter=lambda e: np.pi
624            ),
625            _phase_match_arg,
626        ],
627        can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.CZPowGate, op.gate).exponent, 1.0),
628    ),
629]
630
631
632LIMITED_FSIM_DESERIALIZER = op_deserializer.GateOpDeserializer(
633    serialized_gate_id='fsim',
634    gate_constructor=cirq.FSimGate,
635    args=[
636        op_deserializer.DeserializingArg(
637            serialized_name='theta',
638            constructor_arg_name='theta',
639            default=0.0,
640        ),
641        op_deserializer.DeserializingArg(
642            serialized_name='phi',
643            constructor_arg_name='phi',
644            default=0.0,
645        ),
646    ],
647    op_wrapper=lambda op, proto: _add_phase_match(op, proto),
648)
649
650#############################################
651#
652# Miscellaneous serializers and deserializers
653#
654#############################################
655
656#
657# Coupler Pulse serializer and deserializer
658#
659
660COUPLER_PULSE_SERIALIZER = op_serializer.GateOpSerializer(
661    gate_type=CouplerPulse,
662    serialized_gate_id='coupler_pulse',
663    args=[
664        op_serializer.SerializingArg(
665            serialized_name='coupling_mhz', serialized_type=float, op_getter='coupling_mhz'
666        ),
667        op_serializer.SerializingArg(
668            serialized_name='hold_time_ns',
669            serialized_type=float,
670            op_getter=lambda op: cast(CouplerPulse, op.gate).hold_time.total_nanos(),
671        ),
672        op_serializer.SerializingArg(
673            serialized_name='rise_time_ns',
674            serialized_type=float,
675            op_getter=lambda op: cast(CouplerPulse, op.gate).rise_time.total_nanos(),
676        ),
677        op_serializer.SerializingArg(
678            serialized_name='padding_time_ns',
679            serialized_type=float,
680            op_getter=lambda op: cast(CouplerPulse, op.gate).padding_time.total_nanos(),
681        ),
682    ],
683)
684COUPLER_PULSE_DESERIALIZER = op_deserializer.GateOpDeserializer(
685    serialized_gate_id='coupler_pulse',
686    gate_constructor=CouplerPulse,
687    args=[
688        op_deserializer.DeserializingArg(
689            serialized_name='coupling_mhz',
690            constructor_arg_name='coupling_mhz',
691        ),
692        op_deserializer.DeserializingArg(
693            serialized_name='hold_time_ns',
694            constructor_arg_name='hold_time',
695            value_func=lambda nanos: cirq.Duration(
696                nanos=cast(Union[int, float, sympy.Basic], nanos)
697            ),
698        ),
699        op_deserializer.DeserializingArg(
700            serialized_name='rise_time_ns',
701            constructor_arg_name='rise_time',
702            value_func=lambda nanos: cirq.Duration(
703                nanos=cast(Union[int, float, sympy.Basic], nanos)
704            ),
705        ),
706        op_deserializer.DeserializingArg(
707            serialized_name='padding_time_ns',
708            constructor_arg_name='padding_time',
709            value_func=lambda nanos: cirq.Duration(
710                nanos=cast(Union[int, float, sympy.Basic], nanos)
711            ),
712        ),
713    ],
714)
715
716#
717# WaitGate serializer and deserializer
718#
719WAIT_GATE_SERIALIZER = op_serializer.GateOpSerializer(
720    gate_type=cirq.WaitGate,
721    serialized_gate_id='wait',
722    args=[
723        op_serializer.SerializingArg(
724            serialized_name='nanos',
725            serialized_type=float,
726            op_getter=lambda op: cast(cirq.WaitGate, op.gate).duration.total_nanos(),
727        ),
728    ],
729)
730WAIT_GATE_DESERIALIZER = op_deserializer.GateOpDeserializer(
731    serialized_gate_id='wait',
732    gate_constructor=cirq.WaitGate,
733    args=[
734        op_deserializer.DeserializingArg(
735            serialized_name='nanos',
736            constructor_arg_name='duration',
737            value_func=lambda nanos: cirq.Duration(
738                nanos=cast(Union[int, float, sympy.Basic], nanos)
739            ),
740        )
741    ],
742    num_qubits_param='num_qubits',
743)
744
745#
746# CircuitOperation serializer and deserializer
747#
748CIRCUIT_OP_SERIALIZER = op_serializer.CircuitOpSerializer()
749CIRCUIT_OP_DESERIALIZER = op_deserializer.CircuitOpDeserializer()
750