diff --git a/cirq-google/cirq_google/__init__.py b/cirq-google/cirq_google/__init__.py index 576981b4b74..f1651f1b8f2 100644 --- a/cirq-google/cirq_google/__init__.py +++ b/cirq-google/cirq_google/__init__.py @@ -111,12 +111,8 @@ CIRCUIT_SERIALIZER, CircuitSerializer, CircuitOpDeserializer, - DeserializingArg, - GateOpDeserializer, CircuitOpSerializer, - GateOpSerializer, Serializer, - SerializingArg, ) from cirq_google.workflow import ( diff --git a/cirq-google/cirq_google/json_test_data/spec.py b/cirq-google/cirq_google/json_test_data/spec.py index 393fcf8a3bd..15ddc58f45e 100644 --- a/cirq-google/cirq_google/json_test_data/spec.py +++ b/cirq-google/cirq_google/json_test_data/spec.py @@ -26,7 +26,6 @@ 'ConvertToSqrtIswapGates', 'ConvertToSycamoreGates', 'ConvertToXmonGates', - 'DeserializingArg', 'Engine', 'EngineJob', 'EngineProcessor', @@ -34,13 +33,10 @@ 'FSimPhaseCorrections', 'NoiseModelFromGoogleNoiseProperties', 'ProtoVersion', - 'GateOpSerializer', - 'GateOpDeserializer', 'GreedySequenceSearchStrategy', 'PhasedFSimCalibrationError', 'PhasedFSimEngineSimulator', 'PerQubitDepolarizingWithDampedReadoutNoiseModel', - 'SerializingArg', 'THETA_ZETA_GAMMA_FLOQUET_PHASED_FSIM_CHARACTERIZATION', 'ProcessorSampler', 'ValidatingSampler', diff --git a/cirq-google/cirq_google/serialization/__init__.py b/cirq-google/cirq_google/serialization/__init__.py index 6cc69e8164f..12f5eeec0df 100644 --- a/cirq-google/cirq_google/serialization/__init__.py +++ b/cirq-google/cirq_google/serialization/__init__.py @@ -16,19 +16,10 @@ from cirq_google.serialization.arg_func_langs import arg_from_proto - from cirq_google.serialization.circuit_serializer import CircuitSerializer, CIRCUIT_SERIALIZER -from cirq_google.serialization.op_deserializer import ( - CircuitOpDeserializer, - DeserializingArg, - GateOpDeserializer, -) +from cirq_google.serialization.op_deserializer import CircuitOpDeserializer -from cirq_google.serialization.op_serializer import ( - CircuitOpSerializer, - GateOpSerializer, - SerializingArg, -) +from cirq_google.serialization.op_serializer import CircuitOpSerializer from cirq_google.serialization.serializer import Serializer diff --git a/cirq-google/cirq_google/serialization/common_serializers.py b/cirq-google/cirq_google/serialization/common_serializers.py deleted file mode 100644 index d6fb6b15075..00000000000 --- a/cirq-google/cirq_google/serialization/common_serializers.py +++ /dev/null @@ -1,952 +0,0 @@ -# Copyright 2019 The Cirq Developers -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Common Serializers that can be used by APIs. - -This file contains the following serializers (and corresponding deserializers) - - - SINGLE_QUBIT_SERIALIZERS: A list of GateOpSerializer for single qubit - rotations using cirq Gates. - - MEASUREMENT_SERIALIZER: Single GateOpSerializer for the measurement gate - - SINGLE_QUBIT_SERIALIZERS: A list of GateOpSerializer for single qubit - rotations confined to half-pi increments using cirq Gates. - -""" -from typing import cast, List, Union - -import numpy as np -import sympy - -import cirq -from cirq_google.api import v2 -from cirq_google.experimental.ops import CouplerPulse -from cirq_google.ops import PhysicalZTag, SYC, fsim_gate_family -from cirq_google.serialization import op_deserializer, op_serializer - -# Type strings used in serialization for the two types of Z operations -PHYSICAL_Z = 'physical' -VIRTUAL_Z = 'virtual_propagates_forward' - -# Strings used for phase matching args -PHASE_MATCH_PHYS_Z = 'phys_z' - - -def _near_mod_n(e, t, n, atol=fsim_gate_family.DEFAULT_ATOL): - """Returns whether a value, e, translated by t, is equal to 0 mod n.""" - if isinstance(e, sympy.Symbol): - return False - return abs((e - t + 1) % n - 1) <= atol - - -def _near_mod_2pi(e, t, atol=fsim_gate_family.DEFAULT_ATOL): - """Returns whether a value, e, translated by t, is equal to 0 mod 2 * pi.""" - return _near_mod_n(e, t, n=2 * np.pi, atol=atol) - - -def _near_mod_2(e, t, atol=fsim_gate_family.DEFAULT_ATOL): - """Returns whether a value, e, translated by t, is equal to 0 mod 2.""" - return _near_mod_n(e, t, n=2, atol=atol) - - -def _convert_physical_z(op: cirq.Operation, proto: v2.program_pb2.Operation): - if 'type' in proto.args: - if proto.args['type'].arg_value.string_value == PHYSICAL_Z: - return op.with_tags(PhysicalZTag()) - return op - - -############################################# -# -# Single qubit serializers and deserializers -# -############################################# - -# -# Single qubit serializers for arbitrary rotations -# -_SINGLE_QUBIT_SERIALIZERS = [ - op_serializer._GateOpSerializer( - gate_type=cirq.PhasedXPowGate, - serialized_gate_id='xy', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter='phase_exponent', - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='half_turns', serialized_type=float, op_getter='exponent' - ), - ), - ], - ), - op_serializer._GateOpSerializer( - gate_type=cirq.XPowGate, - serialized_gate_id='xy', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter=lambda op: 0.0, - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='half_turns', serialized_type=float, op_getter='exponent' - ), - ), - ], - ), - op_serializer._GateOpSerializer( - gate_type=cirq.YPowGate, - serialized_gate_id='xy', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter=lambda op: 0.5, - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='half_turns', serialized_type=float, op_getter='exponent' - ), - ), - ], - ), - op_serializer._GateOpSerializer( - gate_type=cirq.ZPowGate, - serialized_gate_id='z', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='half_turns', serialized_type=float, op_getter='exponent' - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='type', - serialized_type=str, - op_getter=lambda op: PHYSICAL_Z if PhysicalZTag() in op.tags else VIRTUAL_Z, - ), - ), - ], - ), - op_serializer._GateOpSerializer( - gate_type=cirq.PhasedXZGate, - serialized_gate_id='xyz', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='x_exponent', serialized_type=float, op_getter='x_exponent' - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='z_exponent', serialized_type=float, op_getter='z_exponent' - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_phase_exponent', - serialized_type=float, - op_getter='axis_phase_exponent', - ), - ), - ], - ), -] - -# -# Single qubit deserializers for arbitrary rotations -# -_SINGLE_QUBIT_DESERIALIZERS = [ - op_deserializer._GateOpDeserializer( - serialized_gate_id='xy', - gate_constructor=cirq.PhasedXPowGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='axis_half_turns', - constructor_arg_name='phase_exponent', - default=0.0, - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='half_turns', constructor_arg_name='exponent', default=1.0 - ), - ), - ], - ), - op_deserializer._GateOpDeserializer( - serialized_gate_id='z', - gate_constructor=cirq.ZPowGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='half_turns', constructor_arg_name='exponent', default=1.0 - ), - ) - ], - op_wrapper=lambda op, proto: _convert_physical_z(op, proto), - ), - op_deserializer._GateOpDeserializer( - serialized_gate_id='xyz', - gate_constructor=cirq.PhasedXZGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='x_exponent', constructor_arg_name='x_exponent', default=0.0 - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='z_exponent', constructor_arg_name='z_exponent', default=0.0 - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='axis_phase_exponent', - constructor_arg_name='axis_phase_exponent', - default=0.0, - ), - ), - ], - ), -] - - -# -# Measurement Serializer and Deserializer -# -_MEASUREMENT_SERIALIZER = op_serializer._GateOpSerializer( - gate_type=cirq.MeasurementGate, - serialized_gate_id='meas', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='key', serialized_type=str, op_getter=cirq.measurement_key_name - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='invert_mask', serialized_type=List[bool], op_getter='invert_mask' - ), - ), - ], -) -_MEASUREMENT_DESERIALIZER = op_deserializer._GateOpDeserializer( - serialized_gate_id='meas', - gate_constructor=cirq.MeasurementGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg(serialized_name='key', constructor_arg_name='key'), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='invert_mask', - constructor_arg_name='invert_mask', - value_func=lambda x: tuple(cast(list, x)), - ), - ), - ], - num_qubits_param='num_qubits', -) - - -# -# Serializers for single qubit rotations confined to half-pi increments -# -_SINGLE_QUBIT_HALF_PI_SERIALIZERS = [ - op_serializer._GateOpSerializer( - gate_type=cirq.PhasedXPowGate, - serialized_gate_id='xy_pi', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter='phase_exponent', - ), - ) - ], - can_serialize_predicate=lambda op: _near_mod_2( - cast(cirq.PhasedXPowGate, op.gate).exponent, 1 - ), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.XPowGate, - serialized_gate_id='xy_pi', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter=lambda op: (cast(cirq.XPowGate, op.gate).exponent - 1) / 2, - ), - ) - ], - can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.XPowGate, op.gate).exponent, 1), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.YPowGate, - serialized_gate_id='xy_pi', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter=lambda op: cast(cirq.YPowGate, op.gate).exponent / 2, - ), - ) - ], - can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.YPowGate, op.gate).exponent, 1), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.XPowGate, - serialized_gate_id='xy_half_pi', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter=lambda op: cast(cirq.XPowGate, op.gate).exponent - 0.5, - ), - ) - ], - can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.XPowGate, op.gate).exponent, 0.5), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.YPowGate, - serialized_gate_id='xy_half_pi', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter=lambda op: cast(cirq.YPowGate, op.gate).exponent, - ), - ) - ], - can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.YPowGate, op.gate).exponent, 0.5), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.PhasedXPowGate, - serialized_gate_id='xy_half_pi', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='axis_half_turns', - serialized_type=float, - op_getter='phase_exponent', - ), - ) - ], - can_serialize_predicate=lambda op: _near_mod_2( - cast(cirq.PhasedXPowGate, op.gate).exponent, 0.5 - ), - ), -] - -# -# Deserializers for single qubit rotations confined to half-pi increments -# -_SINGLE_QUBIT_HALF_PI_DESERIALIZERS = [ - op_deserializer._GateOpDeserializer( - serialized_gate_id='xy_pi', - gate_constructor=cirq.PhasedXPowGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='axis_half_turns', constructor_arg_name='phase_exponent' - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='axis_half_turns', - constructor_arg_name='exponent', - value_func=lambda _: 1, - ), - ), - ], - ), - op_deserializer._GateOpDeserializer( - serialized_gate_id='xy_half_pi', - gate_constructor=cirq.PhasedXPowGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='axis_half_turns', constructor_arg_name='phase_exponent' - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='axis_half_turns', - constructor_arg_name='exponent', - value_func=lambda _: 0.5, - ), - ), - ], - ), -] - -############################################# -# -# Two qubit serializers and deserializers -# -############################################# - -_phase_match_arg = cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='phase_match', - serialized_type=str, - op_getter=lambda op: PHASE_MATCH_PHYS_Z if PhysicalZTag() in op.tags else None, - required=False, - ), -) - - -def _add_phase_match(op: cirq.Operation, proto: v2.program_pb2.Operation): - if 'phase_match' in proto.args: - if proto.args['phase_match'].arg_value.string_value == PHASE_MATCH_PHYS_Z: - return op.with_tags(PhysicalZTag()) - return op - - -# -# CZ Serializer and deserializer -# - -# Only CZ -CZ_SERIALIZER = op_serializer._GateOpSerializer( - gate_type=cirq.CZPowGate, - serialized_gate_id='cz', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='half_turns', serialized_type=float, op_getter='exponent' - ), - ), - _phase_match_arg, - ], - can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.CZPowGate, op.gate).exponent, 1.0), -) - -# CZ to any power -_CZ_POW_SERIALIZER = op_serializer._GateOpSerializer( - gate_type=cirq.CZPowGate, - serialized_gate_id='cz', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='half_turns', serialized_type=float, op_getter='exponent' - ), - ), - _phase_match_arg, - ], -) - -_CZ_POW_DESERIALIZER = op_deserializer._GateOpDeserializer( - serialized_gate_id='cz', - gate_constructor=cirq.CZPowGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='half_turns', constructor_arg_name='exponent', default=1.0 - ), - ) - ], - op_wrapper=lambda op, proto: _add_phase_match(op, proto), -) - -# -# Sycamore Gate Serializer and deserializer -# -_SYC_SERIALIZER = op_serializer._GateOpSerializer( - gate_type=cirq.FSimGate, - serialized_gate_id='syc', - args=[_phase_match_arg], - can_serialize_predicate=( - lambda op: _near_mod_2pi(cast(cirq.FSimGate, op.gate).theta, np.pi / 2) - and _near_mod_2pi(cast(cirq.FSimGate, op.gate).phi, np.pi / 6) - ), -) - -_SYC_DESERIALIZER = op_deserializer._GateOpDeserializer( - serialized_gate_id='syc', - gate_constructor=lambda: cirq.FSimGate(theta=np.pi / 2, phi=np.pi / 6), - args=[], - op_wrapper=lambda op, proto: _add_phase_match(op, proto), -) - -# -# sqrt(ISWAP) serializer and deserializer -# (e.g. ISWAP ** 0.5) -# -_SQRT_ISWAP_SERIALIZERS = [ - op_serializer._GateOpSerializer( - gate_type=cirq.FSimGate, - serialized_gate_id='fsim_pi_4', - args=[_phase_match_arg], - can_serialize_predicate=( - lambda op: _near_mod_2pi(cast(cirq.FSimGate, op.gate).theta, np.pi / 4) - and _near_mod_2pi(cast(cirq.FSimGate, op.gate).phi, 0) - ), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.ISwapPowGate, - serialized_gate_id='fsim_pi_4', - args=[_phase_match_arg], - can_serialize_predicate=( - lambda op: _near_mod_n(cast(cirq.ISwapPowGate, op.gate).exponent, -0.5, 4) - ), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.FSimGate, - serialized_gate_id='inv_fsim_pi_4', - args=[_phase_match_arg], - can_serialize_predicate=( - lambda op: _near_mod_2pi(cast(cirq.FSimGate, op.gate).theta, -np.pi / 4) - and _near_mod_2pi(cast(cirq.FSimGate, op.gate).phi, 0) - ), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.ISwapPowGate, - serialized_gate_id='inv_fsim_pi_4', - args=[_phase_match_arg], - can_serialize_predicate=( - lambda op: _near_mod_n(cast(cirq.ISwapPowGate, op.gate).exponent, +0.5, 4) - ), - ), -] - -_SQRT_ISWAP_DESERIALIZERS = [ - op_deserializer._GateOpDeserializer( - serialized_gate_id='fsim_pi_4', - gate_constructor=lambda: cirq.FSimGate(theta=np.pi / 4, phi=0), - args=[], - op_wrapper=lambda op, proto: _add_phase_match(op, proto), - ), - op_deserializer._GateOpDeserializer( - serialized_gate_id='inv_fsim_pi_4', - gate_constructor=lambda: cirq.FSimGate(theta=-np.pi / 4, phi=0), - args=[], - op_wrapper=lambda op, proto: _add_phase_match(op, proto), - ), -] - -_LIMITED_FSIM_GATE_FAMILY = fsim_gate_family.FSimGateFamily( - gates_to_accept=[ - cirq.IdentityGate(2), - cirq.SQRT_ISWAP_INV, - cirq.SQRT_ISWAP, - cirq.ISWAP, - cirq.ISWAP_INV, - SYC, - cirq.CZ, - ], - gate_types_to_check=[cirq.FSimGate], - allow_symbols=True, -) -_LIMITED_ISWAP_GATE_FAMILY = fsim_gate_family.FSimGateFamily( - gates_to_accept=[ - cirq.IdentityGate(2), - cirq.SQRT_ISWAP_INV, - cirq.SQRT_ISWAP, - cirq.ISWAP, - cirq.ISWAP_INV, - ], - gate_types_to_check=[cirq.ISwapPowGate], - allow_symbols=True, -) -_LIMITED_FSIM_SERIALIZERS = [ - op_serializer._GateOpSerializer( - gate_type=cirq.FSimGate, - serialized_gate_id='fsim', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='theta', serialized_type=float, op_getter='theta' - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='phi', serialized_type=float, op_getter='phi' - ), - ), - _phase_match_arg, - ], - can_serialize_predicate=(lambda op: op in _LIMITED_FSIM_GATE_FAMILY), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.ISwapPowGate, - serialized_gate_id='fsim', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='theta', - serialized_type=float, - # Note that ISWAP ** 0.5 is Fsim(-pi/4,0) - op_getter=(lambda op: cast(cirq.ISwapPowGate, op.gate).exponent * -np.pi / 2), - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='phi', serialized_type=float, op_getter=lambda e: 0 - ), - ), - _phase_match_arg, - ], - can_serialize_predicate=(lambda op: op in _LIMITED_ISWAP_GATE_FAMILY), - ), - op_serializer._GateOpSerializer( - gate_type=cirq.CZPowGate, - serialized_gate_id='fsim', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='theta', serialized_type=float, op_getter=lambda e: 0 - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='phi', serialized_type=float, op_getter=lambda e: np.pi - ), - ), - _phase_match_arg, - ], - can_serialize_predicate=lambda op: _near_mod_2(cast(cirq.CZPowGate, op.gate).exponent, 1.0), - ), -] - - -_LIMITED_FSIM_DESERIALIZER = op_deserializer._GateOpDeserializer( - serialized_gate_id='fsim', - gate_constructor=cirq.FSimGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='theta', constructor_arg_name='theta', default=0.0 - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='phi', constructor_arg_name='phi', default=0.0 - ), - ), - ], - op_wrapper=lambda op, proto: _add_phase_match(op, proto), -) - -############################################# -# -# Miscellaneous serializers and deserializers -# -############################################# - -# -# Coupler Pulse serializer and deserializer -# - -_COUPLER_PULSE_SERIALIZER = op_serializer._GateOpSerializer( - gate_type=CouplerPulse, - serialized_gate_id='coupler_pulse', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='coupling_mhz', serialized_type=float, op_getter='coupling_mhz' - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='hold_time_ns', - serialized_type=float, - op_getter=lambda op: cast(CouplerPulse, op.gate).hold_time.total_nanos(), - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='rise_time_ns', - serialized_type=float, - op_getter=lambda op: cast(CouplerPulse, op.gate).rise_time.total_nanos(), - ), - ), - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='padding_time_ns', - serialized_type=float, - op_getter=lambda op: cast(CouplerPulse, op.gate).padding_time.total_nanos(), - ), - ), - ], -) -_COUPLER_PULSE_DESERIALIZER = op_deserializer._GateOpDeserializer( - serialized_gate_id='coupler_pulse', - gate_constructor=CouplerPulse, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='coupling_mhz', constructor_arg_name='coupling_mhz' - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='hold_time_ns', - constructor_arg_name='hold_time', - value_func=lambda nanos: cirq.Duration( - nanos=cast(Union[int, float, sympy.Expr], nanos) - ), - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='rise_time_ns', - constructor_arg_name='rise_time', - value_func=lambda nanos: cirq.Duration( - nanos=cast(Union[int, float, sympy.Expr], nanos) - ), - ), - ), - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='padding_time_ns', - constructor_arg_name='padding_time', - value_func=lambda nanos: cirq.Duration( - nanos=cast(Union[int, float, sympy.Expr], nanos) - ), - ), - ), - ], -) - -# -# WaitGate serializer and deserializer -# -_WAIT_GATE_SERIALIZER = op_serializer._GateOpSerializer( - gate_type=cirq.WaitGate, - serialized_gate_id='wait', - args=[ - cast( - op_serializer.SerializingArg, - op_serializer._SerializingArg( - serialized_name='nanos', - serialized_type=float, - op_getter=lambda op: cast(cirq.WaitGate, op.gate).duration.total_nanos(), - ), - ) - ], -) -_WAIT_GATE_DESERIALIZER = op_deserializer._GateOpDeserializer( - serialized_gate_id='wait', - gate_constructor=cirq.WaitGate, - args=[ - cast( - op_deserializer.DeserializingArg, - op_deserializer._DeserializingArg( - serialized_name='nanos', - constructor_arg_name='duration', - value_func=lambda nanos: cirq.Duration( - nanos=cast(Union[int, float, sympy.Expr], nanos) - ), - ), - ) - ], - num_qubits_param='num_qubits', -) - -# -# CircuitOperation serializer and deserializer -# -CIRCUIT_OP_SERIALIZER = op_serializer.CircuitOpSerializer() -CIRCUIT_OP_DESERIALIZER = op_deserializer.CircuitOpDeserializer() - - -# HACK: to allow these to be used in gate_sets.py without throwing deprecation warnings during -# module load. -SINGLE_QUBIT_SERIALIZERS = _SINGLE_QUBIT_SERIALIZERS -SINGLE_QUBIT_DESERIALIZERS = _SINGLE_QUBIT_DESERIALIZERS -SINGLE_QUBIT_HALF_PI_SERIALIZERS = _SINGLE_QUBIT_HALF_PI_SERIALIZERS -SINGLE_QUBIT_HALF_PI_DESERIALIZERS = _SINGLE_QUBIT_HALF_PI_DESERIALIZERS -MEASUREMENT_SERIALIZER = _MEASUREMENT_SERIALIZER -MEASUREMENT_DESERIALIZER = _MEASUREMENT_DESERIALIZER -CZ_POW_SERIALIZER = _CZ_POW_SERIALIZER -CZ_POW_DESERIALIZER = _CZ_POW_DESERIALIZER -SYC_SERIALIZER = _SYC_SERIALIZER -SYC_DESERIALIZER = _SYC_DESERIALIZER -SQRT_ISWAP_SERIALIZERS = _SQRT_ISWAP_SERIALIZERS -SQRT_ISWAP_DESERIALIZERS = _SQRT_ISWAP_DESERIALIZERS -LIMITED_FSIM_SERIALIZERS = _LIMITED_FSIM_SERIALIZERS -LIMITED_FSIM_DESERIALIZER = _LIMITED_FSIM_DESERIALIZER -COUPLER_PULSE_SERIALIZER = _COUPLER_PULSE_SERIALIZER -COUPLER_PULSE_DESERIALIZER = _COUPLER_PULSE_DESERIALIZER -WAIT_GATE_SERIALIZER = _WAIT_GATE_SERIALIZER -WAIT_GATE_DESERIALIZER = _WAIT_GATE_DESERIALIZER - - -cirq._compat.deprecate_attributes( - __name__, - { - 'SINGLE_QUBIT_SERIALIZERS': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'SINGLE_QUBIT_DESERIALIZERS': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'SINGLE_QUBIT_HALF_PI_SERIALIZERS': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'SINGLE_QUBIT_HALF_PI_DESERIALIZERS': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'MEASUREMENT_SERIALIZER': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'MEASUREMENT_DESERIALIZER': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'CZ_SERIALIZER': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'CZ_POW_SERIALIZER': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'CZ_POW_DESERIALIZER': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'SYC_SERIALIZER': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'SYC_DESERIALIZER': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'SQRT_ISWAP_SERIALIZERS': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'SQRT_ISWAP_DESERIALIZERS': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'LIMITED_FSIM_SERIALIZERS': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'LIMITED_FSIM_DESERIALIZER': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'COUPLER_PULSE_SERIALIZER': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'COUPLER_PULSE_DESERIALIZER': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'WAIT_GATE_SERIALIZER': ( - 'v0.16', - 'GateOpSerializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - 'WAIT_GATE_DESERIALIZER': ( - 'v0.16', - 'GateOpDeserializer will no longer be available.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', - ), - }, -) diff --git a/cirq-google/cirq_google/serialization/op_deserializer.py b/cirq-google/cirq_google/serialization/op_deserializer.py index 0623b2442f6..32c67469bfe 100644 --- a/cirq-google/cirq_google/serialization/op_deserializer.py +++ b/cirq-google/cirq_google/serialization/op_deserializer.py @@ -12,15 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any, Callable, Dict, List, Optional, Sequence -from dataclasses import dataclass +from typing import Any, List import abc import sympy import cirq from cirq_google.api import v2 -from cirq_google.ops.calibration_tag import CalibrationTag from cirq_google.serialization import arg_func_langs @@ -65,218 +63,6 @@ def from_proto( """ -@dataclass(frozen=True) -class _DeserializingArg: - """HACK: non-deprecated version of DeserializingArg. - - This is used by global gatesets to bypass the behavior that deprecation warnings thrown - during module loading fail unit tests. - """ - - serialized_name: str - constructor_arg_name: str - value_func: Optional[Callable[[arg_func_langs.ARG_LIKE], Any]] = None - required: bool = True - default: Any = None - - -@cirq._compat.deprecated_class( - deadline='v0.16', - fix='Will no longer be used because GateOpDeserializer is deprecated.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', -) -@dataclass(frozen=True) -class DeserializingArg(_DeserializingArg): - """Specification of the arguments to deserialize an argument to a gate. - - Args: - serialized_name: The serialized name of the gate that is being - deserialized. - constructor_arg_name: The name of the argument in the constructor of - the gate corresponding to this serialized argument. - value_func: Sometimes a value from the serialized proto needs to - converted to an appropriate type or form. This function takes the - serialized value and returns the appropriate type. Defaults to - None. - required: Whether a value must be specified when constructing the - deserialized gate. Defaults to True. - default: default value to set if the value is not present in the - arg. If set, required is ignored. - """ - - -class _GateOpDeserializer(OpDeserializer): - """HACK: non-deprecated version of GateOpDeserializer. - - This is used by global gatesets to bypass the behavior that deprecation warnings thrown - during module loading fail unit tests. - """ - - def __init__( - self, - serialized_gate_id: str, - gate_constructor: Callable, - args: Sequence[DeserializingArg], - num_qubits_param: Optional[str] = None, - op_wrapper: Callable[ - [cirq.Operation, v2.program_pb2.Operation], cirq.Operation - ] = lambda x, y: x, - deserialize_tokens: Optional[bool] = True, - ): - self._serialized_gate_id = serialized_gate_id - self._gate_constructor = gate_constructor - self._args = args - self._num_qubits_param = num_qubits_param - self._op_wrapper = op_wrapper - self._deserialize_tokens = deserialize_tokens - - @property - def serialized_id(self): - return self._serialized_gate_id - - def from_proto( - self, - proto: v2.program_pb2.Operation, - *, - arg_function_language: str = '', - constants: List[v2.program_pb2.Constant] = None, - deserialized_constants: List[Any] = None, # unused - ) -> cirq.Operation: - qubits = [v2.qubit_from_proto_id(q.id) for q in proto.qubits] - args = self._args_from_proto(proto, arg_function_language=arg_function_language) - if self._num_qubits_param is not None: - args[self._num_qubits_param] = len(qubits) - gate = self._gate_constructor(**args) - op = self._op_wrapper(gate.on(*qubits), proto) - if self._deserialize_tokens: - which = proto.WhichOneof('token') - if which == 'token_constant_index': - if not constants: - raise ValueError( - 'Proto has references to constants table ' - 'but none was passed in, value =' - f'{proto}' - ) - op = op.with_tags( - CalibrationTag(constants[proto.token_constant_index].string_value) - ) - elif which == 'token_value': - op = op.with_tags(CalibrationTag(proto.token_value)) - return op - - def _args_from_proto( - self, proto: v2.program_pb2.Operation, *, arg_function_language: str - ) -> Dict[str, arg_func_langs.ARG_LIKE]: - return_args = {} - for arg in self._args: - if arg.serialized_name not in proto.args: - if arg.default: - return_args[arg.constructor_arg_name] = arg.default - continue - elif arg.required: - raise ValueError( - f'Argument {arg.serialized_name} ' - 'not in deserializing args, but is required.' - ) - - value = arg_func_langs.arg_from_proto( - proto.args[arg.serialized_name], - arg_function_language=arg_function_language, - required_arg_name=None if not arg.required else arg.serialized_name, - ) - - if arg.value_func is not None and value is not None: - value = arg.value_func(value) - - if value is not None: - return_args[arg.constructor_arg_name] = value - return return_args - - -@cirq._compat.deprecated_class( - deadline='v0.16', - fix='Will no longer be supported.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', -) -class GateOpDeserializer(_GateOpDeserializer): - """Describes how to deserialize a proto to a given Gate type. - - Attributes: - serialized_gate_id: The id used when serializing the gate. - """ - - def __init__( - self, - serialized_gate_id: str, - gate_constructor: Callable, - args: Sequence[DeserializingArg], - num_qubits_param: Optional[str] = None, - op_wrapper: Callable[ - [cirq.Operation, v2.program_pb2.Operation], cirq.Operation - ] = lambda x, y: x, - deserialize_tokens: Optional[bool] = True, - ): - """Constructs a deserializer. - - Args: - serialized_gate_id: The serialized id of the gate that is being - deserialized. - gate_constructor: A function that produces the deserialized gate - given arguments from args. - args: A list of the arguments to be read from the serialized - gate and the information required to use this to construct - the gate using the gate_constructor above. - num_qubits_param: Some gate constructors require that the number - of qubits be passed to their constructor. This is the name - of the parameter in the constructor for this value. If None, - no number of qubits is passed to the constructor. - op_wrapper: An optional Callable to modify the resulting - GateOperation, for instance, to add tags - deserialize_tokens: Whether to convert tokens to - CalibrationTags. Defaults to True. - """ - super().__init__( - serialized_gate_id, - gate_constructor, - args, - num_qubits_param, - op_wrapper, - deserialize_tokens, - ) - - def from_proto( - self, - proto: v2.program_pb2.Operation, - *, - arg_function_language: str = '', - constants: List[v2.program_pb2.Constant] = None, - deserialized_constants: List[Any] = None, # unused - ) -> cirq.Operation: - """Turns a cirq_google.api.v2.Operation proto into a GateOperation. - - Args: - proto: The proto object to be deserialized. - arg_function_language: The `arg_function_language` field from - `Program.Language`. - constants: The list of Constant protos referenced by constant - table indices in `proto`. - deserialized_constants: Unused in this method. - - Returns: - The deserialized GateOperation represented by `proto`. - - Raises: - ValueError: If the proto references a missing constants table, or a required arg is - missing. - """ - return super().from_proto( - proto, - arg_function_language=arg_function_language, - constants=constants, - deserialized_constants=deserialized_constants, - ) - - class CircuitOpDeserializer(OpDeserializer): """Describes how to serialize CircuitOperations.""" diff --git a/cirq-google/cirq_google/serialization/op_deserializer_test.py b/cirq-google/cirq_google/serialization/op_deserializer_test.py index 36ed39be650..738ec62d446 100644 --- a/cirq-google/cirq_google/serialization/op_deserializer_test.py +++ b/cirq-google/cirq_google/serialization/op_deserializer_test.py @@ -12,12 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, List import pytest import sympy -from google.protobuf import json_format - import cirq import cirq_google as cg from cirq_google.api import v2 @@ -26,296 +23,6 @@ DEFAULT_TOKEN = 'test_tag' -def op_proto(json_dict: Dict) -> v2.program_pb2.Operation: - op = v2.program_pb2.Operation() - json_format.ParseDict(json_dict, op) - return op - - -@cirq.value_equality -class GateWithAttribute(cirq.testing.SingleQubitGate): - def __init__(self, val, not_req=None): - self.val = val - self.not_req = not_req - - def _value_equality_values_(self): - return (self.val,) - - -def base_deserializer(): - # Deprecated: cirq_google.GateOpDeserializer and cirq_google.DeserializingArg. - with cirq.testing.assert_deprecated('CircuitSerializer', deadline='v0.16', count=2): - return cg.GateOpDeserializer( - serialized_gate_id='my_gate', - gate_constructor=GateWithAttribute, - args=[cg.DeserializingArg(serialized_name='my_val', constructor_arg_name='val')], - ) - - -def _create_gate_op_deserializer(*, serialized_gate_id, gate_constructor, args): - with cirq.testing.assert_deprecated('CircuitSerializer', deadline='v0.16', count=1): - return cg.GateOpDeserializer( - serialized_gate_id=serialized_gate_id, gate_constructor=gate_constructor, args=args - ) - - -def _create_deserializing_arg( - *, serialized_name, constructor_arg_name, value_func=None, required=True, default=None -): - with cirq.testing.assert_deprecated('CircuitSerializer', deadline='v0.16', count=1): - return cg.DeserializingArg( - serialized_name=serialized_name, - constructor_arg_name=constructor_arg_name, - value_func=value_func, - required=required, - default=default, - ) - - -TEST_CASES = [ - (float, 1.0, {'arg_value': {'float_value': 1.0}}), - (str, 'abc', {'arg_value': {'string_value': 'abc'}}), - (float, 1, {'arg_value': {'float_value': 1.0}}), - (List[bool], [True, False], {'arg_value': {'bool_values': {'values': [True, False]}}}), - (sympy.Symbol, sympy.Symbol('x'), {'symbol': 'x'}), - ( - float, - sympy.Symbol('x') - sympy.Symbol('y'), - { - 'func': { - 'type': 'add', - 'args': [ - {'symbol': 'x'}, - { - 'func': { - 'type': 'mul', - 'args': [{'arg_value': {'float_value': -1.0}}, {'symbol': 'y'}], - } - }, - ], - } - }, - ), -] - - -@pytest.mark.parametrize(('val_type', 'val', 'arg_value'), TEST_CASES) -def test_from_proto(val_type, val, arg_value): - deserializer = base_deserializer() - serialized = op_proto( - {'gate': {'id': 'my_gate'}, 'args': {'my_val': arg_value}, 'qubits': [{'id': '1_2'}]} - ) - q = cirq.GridQubit(1, 2) - result = deserializer.from_proto(serialized, arg_function_language='linear') - assert result == GateWithAttribute(val)(q) - - -def test_from_proto_required_missing(): - deserializer = base_deserializer() - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'not_my_val': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - } - ) - with pytest.raises(Exception, match='my_val'): - deserializer.from_proto(serialized) - - -def test_from_proto_unknown_function(): - deserializer = base_deserializer() - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': { - 'my_val': { - 'func': { - 'type': 'UNKNOWN_OPERATION', - 'args': [{'symbol': 'x'}, {'arg_value': {'float_value': -1.0}}], - } - } - }, - 'qubits': [{'id': '1_2'}], - } - ) - with pytest.raises(ValueError, match='Unrecognized function type'): - _ = deserializer.from_proto(serialized) - - -def test_from_proto_value_type_not_recognized(): - deserializer = base_deserializer() - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {}}}, - 'qubits': [{'id': '1_2'}], - } - ) - with pytest.raises(ValueError, match='Unrecognized value type'): - _ = deserializer.from_proto(serialized) - - -def test_from_proto_function_argument_not_set(): - deserializer = base_deserializer() - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'func': {'type': 'mul', 'args': [{'symbol': 'x'}, {}]}}}, - 'qubits': [{'id': '1_2'}], - } - ) - with pytest.raises(ValueError, match='A multiplication argument is missing'): - _ = deserializer.from_proto(serialized, arg_function_language='linear') - - -def test_from_proto_value_func(): - deserializer = _create_gate_op_deserializer( - serialized_gate_id='my_gate', - gate_constructor=GateWithAttribute, - args=[ - _create_deserializing_arg( - serialized_name='my_val', constructor_arg_name='val', value_func=lambda x: x + 1 - ) - ], - ) - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - } - ) - q = cirq.GridQubit(1, 2) - result = deserializer.from_proto(serialized) - assert result == GateWithAttribute(1.125)(q) - - -def test_from_proto_not_required_ok(): - deserializer = _create_gate_op_deserializer( - serialized_gate_id='my_gate', - gate_constructor=GateWithAttribute, - args=[ - _create_deserializing_arg(serialized_name='my_val', constructor_arg_name='val'), - _create_deserializing_arg( - serialized_name='not_req', constructor_arg_name='not_req', required=False - ), - ], - ) - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - } - ) - q = cirq.GridQubit(1, 2) - result = deserializer.from_proto(serialized) - assert result == GateWithAttribute(0.125)(q) - - -def test_from_proto_missing_required_arg(): - deserializer = _create_gate_op_deserializer( - serialized_gate_id='my_gate', - gate_constructor=GateWithAttribute, - args=[ - _create_deserializing_arg(serialized_name='my_val', constructor_arg_name='val'), - _create_deserializing_arg( - serialized_name='not_req', constructor_arg_name='not_req', required=False - ), - ], - ) - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'not_req': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - } - ) - with pytest.raises(ValueError): - deserializer.from_proto(serialized) - - -def test_from_proto_required_arg_not_assigned(): - deserializer = _create_gate_op_deserializer( - serialized_gate_id='my_gate', - gate_constructor=GateWithAttribute, - args=[ - _create_deserializing_arg(serialized_name='my_val', constructor_arg_name='val'), - _create_deserializing_arg( - serialized_name='not_req', constructor_arg_name='not_req', required=False - ), - ], - ) - serialized = op_proto( - {'gate': {'id': 'my_gate'}, 'args': {'my_val': {}}, 'qubits': [{'id': '1_2'}]} - ) - with pytest.raises(ValueError): - deserializer.from_proto(serialized) - - -def test_defaults(): - deserializer = _create_gate_op_deserializer( - serialized_gate_id='my_gate', - gate_constructor=GateWithAttribute, - args=[ - _create_deserializing_arg( - serialized_name='my_val', constructor_arg_name='val', default=1.0 - ), - _create_deserializing_arg( - serialized_name='not_req', - constructor_arg_name='not_req', - default='hello', - required=False, - ), - ], - ) - serialized = op_proto({'gate': {'id': 'my_gate'}, 'args': {}, 'qubits': [{'id': '1_2'}]}) - g = GateWithAttribute(1.0) - g.not_req = 'hello' - assert deserializer.from_proto(serialized) == g(cirq.GridQubit(1, 2)) - - -def test_token(): - deserializer = base_deserializer() - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 1.25}}}, - 'qubits': [{'id': '1_2'}], - 'token_value': 'abc123', - } - ) - op = GateWithAttribute(1.25)(cirq.GridQubit(1, 2)) - op = op.with_tags(cg.CalibrationTag('abc123')) - assert deserializer.from_proto(serialized) == op - - -def test_token_with_references(): - deserializer = base_deserializer() - serialized = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 1.25}}}, - 'qubits': [{'id': '1_2'}], - 'token_constant_index': 1, - } - ) - op = GateWithAttribute(1.25)(cirq.GridQubit(1, 2)) - op = op.with_tags(cg.CalibrationTag('abc123')) - constants = [] - constant = v2.program_pb2.Constant() - constant.string_value = 'my_token' - constants.append(constant) - constant = v2.program_pb2.Constant() - constant.string_value = 'abc123' - constants.append(constant) - assert deserializer.from_proto(serialized, constants=constants) == op - - with pytest.raises(ValueError, match='Proto has references to constants table'): - deserializer.from_proto(serialized) - - def default_circuit_proto(): op1 = v2.program_pb2.Operation() op1.gate.id = 'x_pow' diff --git a/cirq-google/cirq_google/serialization/op_serializer.py b/cirq-google/cirq_google/serialization/op_serializer.py index bf838f4434b..fb5c5ee758a 100644 --- a/cirq-google/cirq_google/serialization/op_serializer.py +++ b/cirq-google/cirq_google/serialization/op_serializer.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass -from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union +from typing import Any, Callable, Dict, List, Optional, Type, TypeVar import numbers import abc @@ -22,8 +21,7 @@ import cirq from cirq.circuits import circuit_operation from cirq_google.api import v2 -from cirq_google.ops.calibration_tag import CalibrationTag -from cirq_google.serialization.arg_func_langs import arg_to_proto, ARG_LIKE, SUPPORTED_SYMPY_OPS +from cirq_google.serialization.arg_func_langs import arg_to_proto # Type for variables that are subclasses of ops.Gate. Gate = TypeVar('Gate', bound=cirq.Gate) @@ -98,261 +96,6 @@ def can_serialize_operation(self, op: cirq.Operation) -> bool: return self.can_serialize_predicate(op) -@dataclass(frozen=True) -class _SerializingArg: - """HACK: non-deprecated version of SerializingArg. - - This is used by global gatesets to bypass the behavior that deprecation warnings thrown - during module loading fail unit tests. - """ - - serialized_name: str - serialized_type: Type[ARG_LIKE] - op_getter: Union[str, Callable[[cirq.Operation], Optional[ARG_LIKE]]] - required: bool = True - default: Any = None - - -@cirq._compat.deprecated_class( - deadline='v0.16', - fix='Will no longer be used because GateOpSerializer is deprecated.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', -) -@dataclass(frozen=True) -class SerializingArg(_SerializingArg): - """Specification of the arguments for a Gate and its serialization. - - Args: - serialized_name: The name of the argument when it is serialized. - serialized_type: The type of the argument when it is serialized. - op_getter: The name of the property or attribute for getting the - value of this argument from a gate, or a function that takes a - operation and returns this value. The later can be used to supply - a value of the serialized arg by supplying a lambda that - returns this value (i.e. `lambda x: default_value`) - required: Whether this argument is a required argument for the - serialized form. - default: default value. avoid serializing if this is the value. - Note that the DeserializingArg must also have this as default. - """ - - -class _GateOpSerializer(OpSerializer): - """HACK: non-deprecated version of GateOpSerializer. - - This is used by global gatesets to bypass the behavior that deprecation warnings thrown - during module loading fail unit tests. - """ - - def __init__( - self, - *, - gate_type: Type[Gate], - serialized_gate_id: str, - args: List[SerializingArg], - can_serialize_predicate: Callable[[cirq.Operation], bool] = lambda x: True, - serialize_tokens: Optional[bool] = True, - ): - self._gate_type = gate_type - self._serialized_gate_id = serialized_gate_id - self._args = args - self._can_serialize_predicate = can_serialize_predicate - self._serialize_tokens = serialize_tokens - - @property - def internal_type(self): - return self._gate_type - - @property - def serialized_id(self): - return self._serialized_gate_id - - @property - def args(self): - return self._args - - @property - def can_serialize_predicate(self): - return self._can_serialize_predicate - - def can_serialize_operation(self, op: cirq.Operation) -> bool: - supported_gate_type = self._gate_type in type(op.gate).mro() - return supported_gate_type and super().can_serialize_operation(op) - - def to_proto( - self, - op: cirq.Operation, - msg: Optional[v2.program_pb2.Operation] = None, - *, - arg_function_language: Optional[str] = '', - constants: List[v2.program_pb2.Constant] = None, - raw_constants: Dict[Any, int] = None, - ) -> Optional[v2.program_pb2.Operation]: - - gate = op.gate - if not isinstance(gate, self.internal_type): - raise ValueError( - f'Gate of type {type(gate)} but serializer expected type {self.internal_type}' - ) - - if not self._can_serialize_predicate(op): - return None - - if msg is None: - msg = v2.program_pb2.Operation() - - msg.gate.id = self._serialized_gate_id - for qubit in op.qubits: - msg.qubits.add().id = v2.qubit_to_proto_id(qubit) - for arg in self._args: - value = self._value_from_gate(op, arg) - if value is not None and (not arg.default or value != arg.default): - arg_to_proto( - value, - out=msg.args[arg.serialized_name], - arg_function_language=arg_function_language, - ) - if self._serialize_tokens: - for tag in op.tags: - if isinstance(tag, CalibrationTag): - if constants is not None: - constant = v2.program_pb2.Constant() - constant.string_value = tag.token - try: - msg.token_constant_index = constants.index(constant) - except ValueError: - # Token not found, add it to the list - msg.token_constant_index = len(constants) - constants.append(constant) - if raw_constants is not None: - raw_constants[tag.token] = msg.token_constant_index - else: - msg.token_value = tag.token - return msg - - def _value_from_gate(self, op: cirq.Operation, arg: SerializingArg) -> Optional[ARG_LIKE]: - value = None - op_getter = arg.op_getter - if isinstance(op_getter, str): - gate = op.gate - value = getattr(gate, op_getter, None) - if value is None and arg.required: - raise ValueError(f'Gate {gate!r} does not have attribute or property {op_getter}') - elif callable(op_getter): - value = op_getter(op) - - if arg.required and value is None: - raise ValueError( - 'Argument {} is required, but could not get from op {!r}'.format( - arg.serialized_name, op - ) - ) - - if isinstance(value, SUPPORTED_SYMPY_OPS): - return value - - if value is not None: - self._check_type(value, arg) - - return value - - def _check_type(self, value: ARG_LIKE, arg: SerializingArg) -> None: - if arg.serialized_type == float: - if not isinstance(value, (float, int, np.integer, np.floating)): - raise ValueError(f'Expected type convertible to float but was {type(value)}') - elif arg.serialized_type == List[bool]: - if not isinstance(value, (list, tuple, np.ndarray)) or not all( - isinstance(x, (bool, np.bool_)) for x in value - ): - raise ValueError(f'Expected type List[bool] but was {type(value)}') - elif value is not None and not isinstance(value, arg.serialized_type): - raise ValueError( - 'Argument {} had type {} but gate returned type {}'.format( - arg.serialized_name, arg.serialized_type, type(value) - ) - ) - - -@cirq._compat.deprecated_class( - deadline='v0.16', - fix='Will no longer be supported.' - ' CircuitSerializer will be the only supported circuit serializer going forward.', -) -class GateOpSerializer(_GateOpSerializer): - """Describes how to serialize a GateOperation for a given Gate type. - - Attributes: - gate_type: The type of the gate that can be serialized. - serialized_gate_id: The id used when serializing the gate. - serialize_tokens: Whether to convert CalibrationTags into tokens - on the Operation proto. Defaults to True. - """ - - def __init__( - self, - *, - gate_type: Type[Gate], - serialized_gate_id: str, - args: List[SerializingArg], - can_serialize_predicate: Callable[[cirq.Operation], bool] = lambda x: True, - serialize_tokens: Optional[bool] = True, - ): - """Construct the serializer. - - Args: - gate_type: The type of the gate that is being serialized. - serialized_gate_id: The string id of the gate when serialized. - args: A list of specification of the arguments to the gate when - serializing, including how to get this information from the - gate of the given gate type. - can_serialize_predicate: Sometimes an Operation can only be - serialized for particular parameters. This predicate will be - checked before attempting to serialize the Operation. If the - predicate is False, serialization will result in a None value. - Default value is a lambda that always returns True. - serialize_tokens: Whether to convert calibration tags into tokens - on the Operation proto. - """ - super().__init__( - gate_type=gate_type, - serialized_gate_id=serialized_gate_id, - args=args, - can_serialize_predicate=can_serialize_predicate, - serialize_tokens=serialize_tokens, - ) - - def can_serialize_operation(self, op: cirq.Operation) -> bool: - """Whether the given operation can be serialized by this serializer. - - This checks that the gate is a subclass of the gate type for this - serializer, and that the gate returns true for - `can_serializer_predicate` called on the gate. - """ - return super().can_serialize_operation(op) - - def to_proto( - self, - op: cirq.Operation, - msg: Optional[v2.program_pb2.Operation] = None, - *, - arg_function_language: Optional[str] = '', - constants: List[v2.program_pb2.Constant] = None, - raw_constants: Dict[Any, int] = None, - ) -> Optional[v2.program_pb2.Operation]: - """Returns the cirq_google.api.v2.Operation message as a proto dict. - - Note that this function may modify the constant list if it adds - tokens to the circuit's constant table. - """ - return super().to_proto( - op, - msg, - arg_function_language=arg_function_language, - constants=constants, - raw_constants=raw_constants, - ) - - class CircuitOpSerializer(OpSerializer): """Describes how to serialize CircuitOperations.""" diff --git a/cirq-google/cirq_google/serialization/op_serializer_test.py b/cirq-google/cirq_google/serialization/op_serializer_test.py index 1f3b0bc2f06..028a5aae135 100644 --- a/cirq-google/cirq_google/serialization/op_serializer_test.py +++ b/cirq-google/cirq_google/serialization/op_serializer_test.py @@ -12,15 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, List - -import copy -import numpy as np import pytest import sympy -from google.protobuf import json_format - import cirq import cirq_google as cg from cirq_google.api import v2 @@ -29,449 +23,6 @@ DEFAULT_TOKEN = 'test_tag' -def _create_gate_op_serializer( - *, - gate_type, - serialized_gate_id, - args, - can_serialize_predicate=lambda x: True, - serialize_tokens=True, -): - with cirq.testing.assert_deprecated('CircuitSerializer', deadline='v0.16', count=1): - return cg.GateOpSerializer( - gate_type=gate_type, - serialized_gate_id=serialized_gate_id, - args=args, - can_serialize_predicate=can_serialize_predicate, - serialize_tokens=serialize_tokens, - ) - - -def _create_serializing_arg( - *, serialized_name, serialized_type, op_getter, required=True, default=None -): - with cirq.testing.assert_deprecated('CircuitSerializer', deadline='v0.16', count=1): - return cg.SerializingArg( - serialized_name=serialized_name, - serialized_type=serialized_type, - op_getter=op_getter, - required=required, - default=default, - ) - - -def op_proto(json: Dict) -> v2.program_pb2.Operation: - op = v2.program_pb2.Operation() - json_format.ParseDict(json, op) - return op - - -class GateWithAttribute(cirq.testing.SingleQubitGate): - def __init__(self, val): - self.val = val - - -class GateWithProperty(cirq.testing.SingleQubitGate): - def __init__(self, val, not_req=None): - self._val = val - self._not_req = not_req - - @property - def val(self): - return self._val - - -class GateWithMethod(cirq.testing.SingleQubitGate): - def __init__(self, val): - self._val = val - - def get_val(self): - return self._val - - -class SubclassGate(GateWithAttribute): - - pass - - -def get_val(op): - return op.gate.get_val() - - -TEST_CASES = ( - (float, 1.0, {'arg_value': {'float_value': 1.0}}), - (float, np.short(1), {'arg_value': {'float_value': 1.0}}), - (float, np.double(1.0), {'arg_value': {'float_value': 1.0}}), - (str, 'abc', {'arg_value': {'string_value': 'abc'}}), - (float, 1, {'arg_value': {'float_value': 1.0}}), - (List[bool], [True, False], {'arg_value': {'bool_values': {'values': [True, False]}}}), - (List[bool], (True, False), {'arg_value': {'bool_values': {'values': [True, False]}}}), - ( - List[bool], - np.array([True, False], dtype=bool), - {'arg_value': {'bool_values': {'values': [True, False]}}}, - ), - (sympy.Symbol, sympy.Symbol('x'), {'symbol': 'x'}), - (float, sympy.Symbol('x'), {'symbol': 'x'}), - ( - float, - sympy.Symbol('x') - sympy.Symbol('y'), - { - 'func': { - 'type': 'add', - 'args': [ - {'symbol': 'x'}, - { - 'func': { - 'type': 'mul', - 'args': [{'arg_value': {'float_value': -1.0}}, {'symbol': 'y'}], - } - }, - ], - } - }, - ), -) - - -@pytest.mark.parametrize(('val_type', 'val', 'arg_value'), TEST_CASES) -def test_to_proto_attribute(val_type, val, arg_value): - serializer = _create_gate_op_serializer( - gate_type=GateWithAttribute, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=val_type, op_getter='val' - ) - ], - ) - q = cirq.GridQubit(1, 2) - result = serializer.to_proto(GateWithAttribute(val)(q), arg_function_language='linear') - expected = op_proto( - {'gate': {'id': 'my_gate'}, 'args': {'my_val': arg_value}, 'qubits': [{'id': '1_2'}]} - ) - assert result == expected - - -@pytest.mark.parametrize(('val_type', 'val', 'arg_value'), TEST_CASES) -def test_to_proto_property(val_type, val, arg_value): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=val_type, op_getter='val' - ) - ], - ) - q = cirq.GridQubit(1, 2) - result = serializer.to_proto(GateWithProperty(val)(q), arg_function_language='linear') - expected = op_proto( - {'gate': {'id': 'my_gate'}, 'args': {'my_val': arg_value}, 'qubits': [{'id': '1_2'}]} - ) - assert result == expected - - -@pytest.mark.parametrize(('val_type', 'val', 'arg_value'), TEST_CASES) -def test_to_proto_callable(val_type, val, arg_value): - serializer = _create_gate_op_serializer( - gate_type=GateWithMethod, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=val_type, op_getter=get_val - ) - ], - ) - q = cirq.GridQubit(1, 2) - result = serializer.to_proto(GateWithMethod(val)(q), arg_function_language='linear') - expected = op_proto( - {'gate': {'id': 'my_gate'}, 'args': {'my_val': arg_value}, 'qubits': [{'id': '1_2'}]} - ) - assert result == expected - - -def test_to_proto_gate_predicate(): - serializer = _create_gate_op_serializer( - gate_type=GateWithAttribute, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ) - ], - can_serialize_predicate=lambda x: x.gate.val == 1, - ) - q = cirq.GridQubit(1, 2) - assert serializer.to_proto(GateWithAttribute(0)(q)) is None - assert serializer.to_proto(GateWithAttribute(1)(q)) is not None - assert not serializer.can_serialize_operation(GateWithAttribute(0)(q)) - assert serializer.can_serialize_operation(GateWithAttribute(1)(q)) - - -def test_to_proto_gate_mismatch(): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ) - ], - ) - q = cirq.GridQubit(1, 2) - with pytest.raises(ValueError, match='GateWithAttribute.*GateWithProperty'): - serializer.to_proto(GateWithAttribute(1.0)(q)) - - -def test_to_proto_unsupported_type(): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=bytes, op_getter='val' - ) - ], - ) - q = cirq.GridQubit(1, 2) - with pytest.raises(ValueError, match='bytes'): - serializer.to_proto(GateWithProperty(b's')(q)) - - -def test_to_proto_named_qubit_supported(): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ) - ], - ) - q = cirq.NamedQubit('a') - arg_value = 1.0 - result = serializer.to_proto(GateWithProperty(arg_value)(q)) - - expected = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': arg_value}}}, - 'qubits': [{'id': 'a'}], - } - ) - assert result == expected - - -def test_to_proto_line_qubit_supported(): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ) - ], - ) - q = cirq.LineQubit('10') - arg_value = 1.0 - result = serializer.to_proto(GateWithProperty(arg_value)(q)) - - expected = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': arg_value}}}, - 'qubits': [{'id': '10'}], - } - ) - assert result == expected - - -def test_to_proto_required_but_not_present(): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter=lambda x: None - ) - ], - ) - q = cirq.GridQubit(1, 2) - with pytest.raises(ValueError, match='required'): - serializer.to_proto(GateWithProperty(1.0)(q)) - - -def test_to_proto_no_getattr(): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='nope' - ) - ], - ) - q = cirq.GridQubit(1, 2) - with pytest.raises(ValueError, match='does not have'): - serializer.to_proto(GateWithProperty(1.0)(q)) - - -def test_to_proto_not_required_ok(): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ), - _create_serializing_arg( - serialized_name='not_req', - serialized_type=float, - op_getter='not_req', - required=False, - ), - ], - ) - expected = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - } - ) - - q = cirq.GridQubit(1, 2) - assert serializer.to_proto(GateWithProperty(0.125)(q)) == expected - - -@pytest.mark.parametrize( - ('val_type', 'val'), - ( - (float, 's'), - (str, 1.0), - (sympy.Symbol, 1.0), - (List[bool], [1.0]), - (List[bool], 'a'), - (List[bool], (1.0,)), - ), -) -def test_to_proto_type_mismatch(val_type, val): - serializer = _create_gate_op_serializer( - gate_type=GateWithProperty, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=val_type, op_getter='val' - ) - ], - ) - q = cirq.GridQubit(1, 2) - with pytest.raises(ValueError, match=str(type(val))): - serializer.to_proto(GateWithProperty(val)(q)) - - -def test_can_serialize_operation_subclass(): - serializer = _create_gate_op_serializer( - gate_type=GateWithAttribute, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ) - ], - can_serialize_predicate=lambda x: x.gate.val == 1, - ) - q = cirq.GridQubit(1, 1) - assert serializer.can_serialize_operation(SubclassGate(1)(q)) - assert not serializer.can_serialize_operation(SubclassGate(0)(q)) - - -def test_defaults_not_serialized(): - serializer = _create_gate_op_serializer( - gate_type=GateWithAttribute, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, default=1.0, op_getter='val' - ) - ], - ) - q = cirq.GridQubit(1, 2) - no_default = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - } - ) - assert no_default == serializer.to_proto(GateWithAttribute(0.125)(q)) - with_default = op_proto({'gate': {'id': 'my_gate'}, 'qubits': [{'id': '1_2'}]}) - assert with_default == serializer.to_proto(GateWithAttribute(1.0)(q)) - - -def test_token_serialization(): - serializer = _create_gate_op_serializer( - gate_type=GateWithAttribute, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ) - ], - ) - q = cirq.GridQubit(1, 2) - tag = cg.CalibrationTag('my_token') - expected = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - 'token_value': 'my_token', - } - ) - assert expected == serializer.to_proto(GateWithAttribute(0.125)(q).with_tags(tag)) - - -ONE_CONSTANT = [v2.program_pb2.Constant(string_value='my_token')] -TWO_CONSTANTS = [ - v2.program_pb2.Constant(string_value='other_token'), - v2.program_pb2.Constant(string_value='my_token'), -] - - -@pytest.mark.parametrize( - ('constants', 'expected_index', 'expected_constants'), - (([], 0, ONE_CONSTANT), (ONE_CONSTANT, 0, ONE_CONSTANT), (TWO_CONSTANTS, 1, TWO_CONSTANTS)), -) -def test_token_serialization_with_constant_reference(constants, expected_index, expected_constants): - serializer = _create_gate_op_serializer( - gate_type=GateWithAttribute, - serialized_gate_id='my_gate', - args=[ - _create_serializing_arg( - serialized_name='my_val', serialized_type=float, op_getter='val' - ) - ], - ) - # Make a local copy since we are modifying the array in-place. - constants = copy.copy(constants) - q = cirq.GridQubit(1, 2) - tag = cg.CalibrationTag('my_token') - expected = op_proto( - { - 'gate': {'id': 'my_gate'}, - 'args': {'my_val': {'arg_value': {'float_value': 0.125}}}, - 'qubits': [{'id': '1_2'}], - 'token_constant_index': expected_index, - } - ) - assert expected == serializer.to_proto( - GateWithAttribute(0.125)(q).with_tags(tag), constants=constants - ) - assert constants == expected_constants - - def default_circuit_proto(): op1 = v2.program_pb2.Operation() op1.gate.id = 'x_pow'