def test_assymetric_gate(): spec = device_pb2.DeviceSpecification() for row in range(5): for col in range(2): spec.valid_qubits.extend( [v2.qubit_to_proto_id(cirq.GridQubit(row, col))]) grid_targets = spec.valid_targets.add() grid_targets.name = 'left_to_right' grid_targets.target_ordering = device_pb2.TargetSet.ASYMMETRIC for row in range(5): new_target = grid_targets.targets.add() new_target.ids.extend([ v2.qubit_to_proto_id(cirq.GridQubit(row, 0)), v2.qubit_to_proto_id(cirq.GridQubit(row, 1)) ]) gs_proto = spec.valid_gate_sets.add() gs_proto.name = 'cz_left_to_right_only' gate = gs_proto.valid_gates.add() gate.id = 'cz' gate.valid_targets.extend(['left_to_right']) dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[_JUST_CZ]) for row in range(5): dev.validate_operation( cirq.CZ(cirq.GridQubit(row, 0), cirq.GridQubit(row, 1))) with pytest.raises(ValueError): dev.validate_operation( cirq.CZ(cirq.GridQubit(row, 1), cirq.GridQubit(row, 0)))
def test_constrained_permutations(): spec = device_pb2.DeviceSpecification() for row in range(5): for col in range(2): spec.valid_qubits.extend( [v2.qubit_to_proto_id(cirq.GridQubit(row, col))]) grid_targets = spec.valid_targets.add() grid_targets.name = 'meas_on_first_line' grid_targets.target_ordering = device_pb2.TargetSet.SUBSET_PERMUTATION new_target = grid_targets.targets.add() new_target.ids.extend( [v2.qubit_to_proto_id(cirq.GridQubit(i, 0)) for i in range(5)]) gs_proto = spec.valid_gate_sets.add() gs_proto.name = 'meas_set' gate = gs_proto.valid_gates.add() gate.id = 'meas' gate.valid_targets.extend(['meas_on_first_line']) dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[_JUST_MEAS]) dev.validate_operation(cirq.measure(cirq.GridQubit(0, 0))) dev.validate_operation(cirq.measure(cirq.GridQubit(1, 0))) dev.validate_operation(cirq.measure(cirq.GridQubit(2, 0))) dev.validate_operation( cirq.measure(*[cirq.GridQubit(i, 0) for i in range(5)])) with pytest.raises(ValueError): dev.validate_operation(cirq.measure(cirq.GridQubit(1, 1))) with pytest.raises(ValueError): dev.validate_operation( cirq.measure(cirq.GridQubit(0, 0), cirq.GridQubit(1, 1)))
def test_results_from_proto_default_ordering(): proto = v2.result_pb2.Result() sr = proto.sweep_results.add() sr.repetitions = 8 pr = sr.parameterized_results.add() pr.params.assignments.update({'i': 1}) mr = pr.measurement_results.add() mr.key = 'foo' for qubit, results in [ (q(0, 1), 0b1100_1100), (q(1, 1), 0b1010_1010), (q(0, 0), 0b1111_0000), ]: qmr = mr.qubit_measurement_results.add() qmr.qubit.id = v2.qubit_to_proto_id(qubit) qmr.results = bytes([results]) trial_results = v2.results_from_proto(proto) trial = trial_results[0][0] assert trial.params == cirq.ParamResolver({'i': 1}) assert trial.repetitions == 8 np.testing.assert_array_equal( trial.measurements['foo'], np.array([ [0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0], [0, 0, 1], [0, 1, 1], [1, 0, 1], [1, 1, 1], ], dtype=bool))
def to_proto( self, op: 'cirq.Operation', msg: Optional[v2.program_pb2.Operation] = None, *, arg_function_language: Optional[str] = '', ) -> Optional[v2.program_pb2.Operation]: """Returns the cirq.google.api.v2.Operation message as a proto dict.""" gate = op.gate if not isinstance(gate, self.gate_type): raise ValueError( 'Gate of type {} but serializer expected type {}'.format( type(gate), self.gate_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: _arg_to_proto(value, out=msg.args[arg.serialized_name], arg_function_language=arg_function_language) return msg
def results_to_proto( trial_sweeps: Iterable[Iterable[study.TrialResult]], measurements: List[MeasureInfo], *, out: Optional[result_pb2.Result] = None, ) -> result_pb2.Result: """Converts trial results from multiple sweeps to v2 protobuf message. Args: trial_sweeps: Iterable over sweeps and then over trial results within each sweep. measurements: List of info about measurements in the program. out: Optional message to populate. If not given, create a new message. """ if out is None: out = result_pb2.Result() for trial_sweep in trial_sweeps: sweep_result = out.sweep_results.add() for i, trial_result in enumerate(trial_sweep): if i == 0: sweep_result.repetitions = trial_result.repetitions elif trial_result.repetitions != sweep_result.repetitions: raise ValueError( 'different numbers of repetitions in one sweep') pr = sweep_result.parameterized_results.add() pr.params.assignments.update(trial_result.params.param_dict) for m in measurements: mr = pr.measurement_results.add() mr.key = m.key m_data = trial_result.measurements[m.key] for i, qubit in enumerate(m.qubits): qmr = mr.qubit_measurement_results.add() qmr.qubit.id = v2.qubit_to_proto_id(qubit) qmr.results = pack_bits(m_data[:, i]) return out
def to_proto( self, op: 'cirq.GateOperation', msg: Optional[v2.program_pb2.Operation] = None ) -> Optional[v2.program_pb2.Operation]: """Returns the cirq.api.google.v2.Operation message as a proto dict.""" if not all( isinstance(qubit, devices.GridQubit) for qubit in op.qubits): raise ValueError('All qubits must be GridQubits') gate = op.gate if not isinstance(gate, self.gate_type): raise ValueError( 'Gate of type {} but serializer expected type {}'.format( type(gate), self.gate_type)) if not self.can_serialize_predicate(gate): 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 = api_v2.qubit_to_proto_id( cast(devices.GridQubit, qubit)) for arg in self.args: value = self._value_from_gate(gate, arg) if value is not None: self._arg_value_to_proto(value, msg.args[arg.serialized_name]) return msg
def serialize_paulisum(paulisum): """Constructs a pauli_sum proto from `cirq.PauliSum` or `cirq.PauliString`. Args: paulisum: A `cirq.PauliSum` object. Returns: A pauli_sum proto object. """ if isinstance(paulisum, cirq.PauliString): paulisum = cirq.PauliSum.from_pauli_strings(paulisum) if not isinstance(paulisum, cirq.PauliSum): raise TypeError("serialize requires a cirq.PauliSum object." " Given: " + str(type(paulisum))) if any(not isinstance(qubit, cirq.GridQubit) for qubit in paulisum.qubits): raise ValueError("Attempted to serialize a paulisum that doesn't use " "only cirq.GridQubits.") paulisum_proto = pauli_sum_pb2.PauliSum() for term in paulisum: pauliterm_proto = pauli_sum_pb2.PauliTerm() pauliterm_proto.coefficient_real = term.coefficient.real pauliterm_proto.coefficient_imag = term.coefficient.imag for t in sorted(term.items()): # sort to keep qubits ordered. pauliterm_proto.paulis.add( qubit_id=v2.qubit_to_proto_id(t[0]), pauli_type=str(t[1]), ) paulisum_proto.terms.extend([pauliterm_proto]) return paulisum_proto
def test_qubit_to_proto_id(): assert v2.qubit_to_proto_id(cirq.GridQubit(1, 2)) == '1_2' assert v2.qubit_to_proto_id(cirq.GridQubit(10, 2)) == '10_2' assert v2.qubit_to_proto_id(cirq.GridQubit(-1, 2)) == '-1_2' assert v2.qubit_to_proto_id(cirq.LineQubit(1)) == '1' assert v2.qubit_to_proto_id(cirq.LineQubit(10)) == '10' assert v2.qubit_to_proto_id(cirq.LineQubit(-1)) == '-1' assert v2.qubit_to_proto_id(cirq.NamedQubit('named')) == 'named'
def test_number_of_qubits_cz(): spec = device_pb2.DeviceSpecification() spec.valid_qubits.extend( [v2.qubit_to_proto_id(cirq.GridQubit(0, 0)), v2.qubit_to_proto_id(cirq.GridQubit(0, 1))] ) grid_targets = spec.valid_targets.add() grid_targets.name = '2_qubit_anywhere' grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC gs_proto = spec.valid_gate_sets.add() gs_proto.name = 'cz_requires_three_qubits' gate = gs_proto.valid_gates.add() gate.id = 'cz' gate.valid_targets.extend(['2_qubit_anywhere']) gate.number_of_qubits = 3 dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[_JUST_CZ]) with pytest.raises(ValueError): dev.validate_operation(cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)))
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, ) -> 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. """ gate = op.gate if not isinstance(gate, self.gate_type): raise ValueError( 'Gate of type {} but serializer expected type {}'.format( type(gate), self.gate_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) else: msg.token_value = tag.token return msg
def test_to_proto_id_unsupport_qid(): class ValidQubit(cirq.Qid): def __init__(self, name): self._name = name @property def dimension(self): pass def _comparison_key(self): pass with pytest.raises(ValueError, match='ValidQubit'): _ = v2.qubit_to_proto_id(ValidQubit('d'))
def test_unconstrained_gate(): spec = device_pb2.DeviceSpecification() for row in range(5): for col in range(5): spec.valid_qubits.extend([v2.qubit_to_proto_id(cirq.GridQubit(row, col))]) grid_targets = spec.valid_targets.add() grid_targets.name = '2_qubit_anywhere' grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC gs_proto = spec.valid_gate_sets.add() gs_proto.name = 'cz_free_for_all' gate = gs_proto.valid_gates.add() gate.id = 'cz' gate.valid_targets.extend(['2_qubit_anywhere']) dev = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[_JUST_CZ]) valid_qubit1 = cirq.GridQubit(4, 4) for row in range(4): for col in range(4): valid_qubit2 = cirq.GridQubit(row, col) dev.validate_operation(cirq.CZ(valid_qubit1, valid_qubit2))
def to_proto(self) -> v2.metrics_pb2.MetricsSnapshot: """Reconstruct the protobuf message represented by this class.""" proto = v2.metrics_pb2.MetricsSnapshot() for key in self._metric_dict: for target, value_list in self._metric_dict[key].items(): current_metric = proto.metrics.add() current_metric.name = key current_metric.targets.extend( [v2.qubit_to_proto_id(q) for q in target]) for value in value_list: current_value = current_metric.values.add() if isinstance(value, float): current_value.double_val = value elif isinstance(value, int): current_value.int64_val = value elif isinstance(value, str): current_value.str_val = value else: raise ValueError(f'Unsupported metric value {value}. ' 'Must be int, float, or str to ' 'convert to proto.') return proto
def test_results_from_proto_duplicate_qubit(): measurements = [ v2.MeasureInfo('foo', [q(0, 0), q(0, 1), q(1, 1)], slot=0, invert_mask=[False, False, False]) ] proto = v2.result_pb2.Result() sr = proto.sweep_results.add() sr.repetitions = 8 pr = sr.parameterized_results.add() pr.params.assignments.update({'i': 0}) mr = pr.measurement_results.add() mr.key = 'foo' for qubit, results in [ (q(0, 0), 0b1100_1100), (q(0, 1), 0b1010_1010), (q(0, 1), 0b1111_0000), ]: qmr = mr.qubit_measurement_results.add() qmr.qubit.id = v2.qubit_to_proto_id(qubit) qmr.results = bytes([results]) with pytest.raises(ValueError, match='qubit already exists'): v2.results_from_proto(proto, measurements)
def create_device_proto_from_diagram( ascii_grid: str, gate_sets: Optional[Iterable[ serializable_gate_set.SerializableGateSet]] = None, durations_picos: Dict[str, int] = None, ) -> device_pb2.DeviceSpecification: """ Parse ASCIIart device layout into DeviceSpecification proto containing information about qubits and targets. Note that this does not populate the gate set information of the proto. This function also assumes that only adjacent qubits can be targets. Args: ascii_grid: An ASCII version of the grid, see _parse_device for details gate_set: A serializable gate_set object that is used to define the translation between gate ids and cirq Gate objects durations_picos: A dictionary with keys of gate ids and values of the duration of that gate in picoseconds """ qubits, _ = _parse_device(ascii_grid) spec = device_pb2.DeviceSpecification() # Create valid qubit list qubit_set = frozenset(qubits) spec.valid_qubits.extend([v2.qubit_to_proto_id(q) for q in qubits]) # Set up a target set for measurement (any qubit permutation) meas_targets = spec.valid_targets.add() meas_targets.name = _MEAS_TARGET_SET meas_targets.target_ordering = device_pb2.TargetSet.SUBSET_PERMUTATION # Set up a target set for 2 qubit gates (all adjacent pairs) grid_targets = spec.valid_targets.add() grid_targets.name = _2_QUBIT_TARGET_SET grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC # Create the target set as all adjacent pairs on the grid neighbor_set: Set[Tuple] = set() for q in qubits: for neighbor in sorted(q.neighbors(qubit_set)): if (neighbor, q) not in neighbor_set: # Don't add pairs twice new_target = grid_targets.targets.add() new_target.ids.extend( (v2.qubit_to_proto_id(q), v2.qubit_to_proto_id(neighbor))) neighbor_set.add((q, neighbor)) # Create gate sets arg_def = device_pb2.ArgDefinition for gate_set in gate_sets or []: gs_proto = spec.valid_gate_sets.add() gs_proto.name = gate_set.gate_set_name gate_ids: Set[str] = set() for gate_type in gate_set.serializers: for serializer in gate_set.serializers[gate_type]: gate_id = serializer.serialized_gate_id if gate_id in gate_ids: # Only add each type once continue gate_ids.add(gate_id) gate = gs_proto.valid_gates.add() gate.id = gate_id # Choose target set and number of qubits based on gate type. # Note: if it is not a measurement gate and doesn't inherit # from SingleQubitGate, it's assumed to be a two qubit gate. if gate_type == MeasurementGate: gate.valid_targets.extend([_MEAS_TARGET_SET]) elif gate_type == WaitGate: # TODO(#2537): Refactor gate-sets / device to eliminate # The need for checking type here. gate.number_of_qubits = 1 elif issubclass(gate_type, SingleQubitGate): gate.number_of_qubits = 1 else: # This must be a two-qubit gate gate.valid_targets.extend([_2_QUBIT_TARGET_SET]) gate.number_of_qubits = 2 # Add gate duration if (durations_picos is not None and gate.id in durations_picos): gate.gate_duration_picos = durations_picos[gate.id] # Add argument names and types for each gate. for arg in serializer.args: new_arg = gate.valid_args.add() if arg.serialized_type == str: new_arg.type = arg_def.STRING if arg.serialized_type == float: new_arg.type = arg_def.FLOAT if arg.serialized_type == List[bool]: new_arg.type = arg_def.REPEATED_BOOLEAN new_arg.name = arg.serialized_name # Note: this does not yet support adding allowed_ranges return spec
def create_device_proto_for_qubits( qubits: Collection['cirq.Qid'], pairs: Collection[Tuple['cirq.Qid', 'cirq.Qid']], gate_sets: Optional[Iterable[ serializable_gate_set.SerializableGateSet]] = None, durations_picos: Optional[Dict[str, int]] = None, out: Optional[device_pb2.DeviceSpecification] = None, ) -> device_pb2.DeviceSpecification: """Create device spec for the given qubits and coupled pairs. Args: qubits: Qubits that can perform single-qubit gates. pairs: Pairs of coupled qubits that can perform two-qubit gates. gate_sets: Gate sets that define the translation between gate ids and cirq Gate objects. durations_picos: A map from gate ids to gate durations in picoseconds. out: If given, populate this proto, otherwise create a new proto. """ if out is None: out = device_pb2.DeviceSpecification() # Create valid qubit list out.valid_qubits.extend(v2.qubit_to_proto_id(q) for q in qubits) # Set up a target set for measurement (any qubit permutation) meas_targets = out.valid_targets.add() meas_targets.name = _MEAS_TARGET_SET meas_targets.target_ordering = device_pb2.TargetSet.SUBSET_PERMUTATION # Set up a target set for 2 qubit gates (specified qubit pairs) grid_targets = out.valid_targets.add() grid_targets.name = _2_QUBIT_TARGET_SET grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC for pair in pairs: new_target = grid_targets.targets.add() new_target.ids.extend(v2.qubit_to_proto_id(q) for q in pair) # Create gate sets arg_def = device_pb2.ArgDefinition for gate_set in gate_sets or []: gs_proto = out.valid_gate_sets.add() gs_proto.name = gate_set.gate_set_name gate_ids: Set[str] = set() for gate_type in gate_set.serializers: for serializer in gate_set.serializers[gate_type]: gate_id = serializer.serialized_gate_id if gate_id in gate_ids: # Only add each type once continue gate_ids.add(gate_id) gate = gs_proto.valid_gates.add() gate.id = gate_id # Choose target set and number of qubits based on gate type. # Note: if it is not a measurement gate and doesn't inherit # from SingleQubitGate, it's assumed to be a two qubit gate. if gate_type == MeasurementGate: gate.valid_targets.append(_MEAS_TARGET_SET) elif gate_type == WaitGate: # TODO: Refactor gate-sets / device to eliminate the need # to keep checking type here. # Github issue: # https://github.com/quantumlib/Cirq/issues/2537 gate.number_of_qubits = 1 elif issubclass(gate_type, SingleQubitGate): gate.number_of_qubits = 1 else: # This must be a two-qubit gate gate.valid_targets.append(_2_QUBIT_TARGET_SET) gate.number_of_qubits = 2 # Add gate duration if durations_picos is not None and gate.id in durations_picos: gate.gate_duration_picos = durations_picos[gate.id] # Add argument names and types for each gate. for arg in serializer.args: new_arg = gate.valid_args.add() if arg.serialized_type == str: new_arg.type = arg_def.STRING if arg.serialized_type == float: new_arg.type = arg_def.FLOAT if arg.serialized_type == List[bool]: new_arg.type = arg_def.REPEATED_BOOLEAN new_arg.name = arg.serialized_name # Note: this does not yet support adding allowed_ranges return out
def _serialize_controls(gate): """Helper to serialize control qubits if applicable.""" if hasattr(gate, '_tfq_control_qubits'): return ','.join( v2.qubit_to_proto_id(q) for q in gate._tfq_control_qubits) return ''