Пример #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)))
Пример #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)))
Пример #3
0
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
Пример #5
0
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
Пример #6
0
    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
Пример #7
0
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
Пример #8
0
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'
Пример #9
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)))
Пример #10
0
    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
Пример #11
0
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'))
Пример #12
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))
Пример #13
0
 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
Пример #14
0
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)
Пример #15
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
Пример #16
0
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
Пример #17
0
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 ''