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_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 test_mixing_types(): """ Mixing SUBSET_PERMUTATION with SYMMETRIC targets is confusing, and not yet supported""" spec = device_pb2.DeviceSpecification() grid_targets = spec.valid_targets.add() grid_targets.name = 'subset' grid_targets.target_ordering = device_pb2.TargetSet.SUBSET_PERMUTATION grid_targets = spec.valid_targets.add() grid_targets.name = 'sym' grid_targets.target_ordering = device_pb2.TargetSet.SYMMETRIC gs_proto = spec.valid_gate_sets.add() gs_proto.name = 'set_with_mismatched_targets' gate = gs_proto.valid_gates.add() gate.id = 'meas' gate.valid_targets.extend(['subset', 'sym']) with pytest.raises(NotImplementedError): _ = cg.SerializableDevice.from_proto(proto=spec, gate_sets=[_JUST_MEAS])
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 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