Example #1
0
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)))
Example #2
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)))
Example #3
0
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])
Example #5
0
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))
Example #6
0
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