Exemple #1
0
def cirq_to_qlm(circ, sep_measures=False, **kwargs):
    """ Converts a google cirq circuit to a qlm circuit

    Args:
        cirq: the cirq circuit to convert
        sep_measures: Separates measures from the
            circuit:

             - if set to :code:`True` measures won't be included in the resulting circuits,
               qubits to be measured will be put in a list, the resulting measureless
               circuit and this list will be returned in a tuple : (resulting_circuit, list_qubits)
             - if set to :code:`False`, measures will be converted normally (Default set to False)

        kwargs: these are the options that you would use on a regular
            to_circ function, to generate a QLM circuit from a PyAQASM program
            these are added for more flexibility, for advanced users


    Returns:
        :code:`tuple` or :class:`~qat.core.Circuit`: If :code:`sep_measures` is set
        to:

         - :code:`True`: the result is a tuple composed of a
           :class:`~qat.core.Circuit` and a list of qubits that should be
           measured
         - :code:`False`: the result is a :class:`~qat.core.Circuit`
    """
    # building a qubit map to use correct qubits
    qubits = ops.QubitOrder.as_qubit_order(ops.QubitOrder.DEFAULT).order_for(
        circ.all_qubits())
    qmap = {qbit: i for i, qbit in enumerate(qubits)}

    # extracting operations
    operations = tuple(ops.flatten_op_tree(circ.all_operations()))

    # pyaqasm initialization
    prog = Program()
    qreg = prog.qalloc(len(qubits))
    to_measure = []
    # building operations
    for op in operations:
        qbs = []
        for qb in op.qubits:
            qbs.append(qreg[qmap[qb]])
            if (cirq.is_measurement(cast(ops.GateOperation, op))
                    and sep_measures):
                to_measure.append(qmap[qb])
        if cirq.is_measurement(cast(ops.GateOperation, op)):
            if not sep_measures:
                prog.measure(qbs, qbs)
        elif isinstance(_get_gate(op.gate), str) and _get_gate(
                op.gate) == "none":
            continue
        else:
            prog.apply(_get_gate(op.gate), qbs)

    if sep_measures:
        return prog.to_circ(**kwargs), list(set(to_measure))

    return prog.to_circ(**kwargs)
Exemple #2
0
def test_measurement_keys():
    class Composite(cirq.Gate):
        def _decompose_(self, qubits):
            yield cirq.measure(qubits[0], key='inner1')
            yield cirq.measure(qubits[1], key='inner2')
            yield cirq.reset(qubits[0])

        def num_qubits(self) -> int:
            return 2

    class MeasurementKeysGate(cirq.Gate):
        def _measurement_key_names_(self):
            return ['a', 'b']

        def num_qubits(self) -> int:
            return 1

    class DeprecatedMagicMethod(cirq.Gate):
        def _measurement_keys_(self):
            return ['a', 'b']

        def num_qubits(self) -> int:
            return 1

    a, b = cirq.LineQubit.range(2)
    assert cirq.is_measurement(Composite())
    with cirq.testing.assert_deprecated(deadline="v0.13"):
        assert cirq.measurement_keys(Composite()) == {'inner1', 'inner2'}
    with cirq.testing.assert_deprecated(deadline="v0.13"):
        assert cirq.measurement_key_names(
            DeprecatedMagicMethod()) == {'a', 'b'}
    with cirq.testing.assert_deprecated(deadline="v0.13"):
        assert cirq.measurement_key_names(
            DeprecatedMagicMethod().on(a)) == {'a', 'b'}
    assert cirq.measurement_key_names(Composite()) == {'inner1', 'inner2'}
    assert cirq.measurement_key_names(Composite().on(
        a, b)) == {'inner1', 'inner2'}
    assert not cirq.is_measurement(Composite(), allow_decompose=False)
    assert cirq.measurement_key_names(Composite(),
                                      allow_decompose=False) == set()
    assert cirq.measurement_key_names(Composite().on(a, b),
                                      allow_decompose=False) == set()

    assert cirq.measurement_key_names(None) == set()
    assert cirq.measurement_key_names([]) == set()
    assert cirq.measurement_key_names(cirq.X) == set()
    assert cirq.measurement_key_names(cirq.X(a)) == set()
    assert cirq.measurement_key_names(None, allow_decompose=False) == set()
    assert cirq.measurement_key_names([], allow_decompose=False) == set()
    assert cirq.measurement_key_names(cirq.X, allow_decompose=False) == set()
    assert cirq.measurement_key_names(cirq.measure(a, key='out')) == {'out'}
    assert cirq.measurement_key_names(cirq.measure(a, key='out'),
                                      allow_decompose=False) == {'out'}

    assert cirq.measurement_key_names(
        cirq.Circuit(cirq.measure(a, key='a'),
                     cirq.measure(b, key='2'))) == {'a', '2'}
    assert cirq.measurement_key_names(MeasurementKeysGate()) == {'a', 'b'}
    assert cirq.measurement_key_names(
        MeasurementKeysGate().on(a)) == {'a', 'b'}
Exemple #3
0
def test_measurement_keys():
    a = cirq.NamedQubit('a')
    b = cirq.NamedQubit('b')
    m = cirq.Moment(cirq.X(a), cirq.X(b))
    assert cirq.measurement_key_names(m) == set()
    assert not cirq.is_measurement(m)

    m2 = cirq.Moment(cirq.measure(a, b, key='foo'))
    assert cirq.measurement_key_names(m2) == {'foo'}
    assert cirq.is_measurement(m2)
Exemple #4
0
def test_tagged_measurement():
    assert not cirq.is_measurement(cirq.GlobalPhaseOperation(coefficient=-1.0).with_tags('tag0'))

    a = cirq.LineQubit(0)
    op = cirq.measure(a, key='m').with_tags('tag')
    assert cirq.is_measurement(op)

    remap_op = cirq.with_measurement_key_mapping(op, {'m': 'k'})
    assert remap_op.tags == ('tag',)
    assert cirq.is_measurement(remap_op)
    assert cirq.measurement_keys(remap_op) == {'k'}
    assert cirq.with_measurement_key_mapping(op, {'x': 'k'}) == op
Exemple #5
0
def test_measurement_key():
    class ReturnsStr:
        def _measurement_key_name_(self):
            return 'door locker'

    class DeprecatedMagicMethod(cirq.SingleQubitGate):
        def _measurement_key_(self):
            return 'door locker'

    assert cirq.is_measurement(ReturnsStr())
    with cirq.testing.assert_deprecated(deadline="v0.13"):
        assert cirq.measurement_key(ReturnsStr()) == 'door locker'
    with cirq.testing.assert_deprecated(deadline="v0.13"):
        assert cirq.measurement_key_name(
            DeprecatedMagicMethod()) == 'door locker'
    with cirq.testing.assert_deprecated(deadline="v0.13"):
        assert (cirq.measurement_key_name(DeprecatedMagicMethod().on(
            cirq.LineQubit(0))) == 'door locker')

    assert cirq.measurement_key_name(ReturnsStr()) == 'door locker'

    assert cirq.measurement_key_name(ReturnsStr(), None) == 'door locker'
    assert cirq.measurement_key_name(ReturnsStr(),
                                     NotImplemented) == 'door locker'
    assert cirq.measurement_key_name(ReturnsStr(), 'a') == 'door locker'
Exemple #6
0
def test_non_measurement_with_key():
    class NonMeasurementGate(cirq.Gate):
        def _is_measurement_(self):
            return False

        def _decompose_(self, qubits):
            # Decompose should not be called by `is_measurement`
            assert False

        def _measurement_key_name_(self):
            # `measurement_key_name`` should not be called by `is_measurement`
            assert False

        def _measurement_key_names_(self):
            # `measurement_key_names`` should not be called by `is_measurement`
            assert False

        def _measurement_key_obj_(self):
            # `measurement_key_obj`` should not be called by `is_measurement`
            assert False

        def _measurement_key_objs_(self):
            # `measurement_key_objs`` should not be called by `is_measurement`
            assert False

        def num_qubits(self) -> int:
            return 2  # coverage: ignore

    assert not cirq.is_measurement(NonMeasurementGate())
Exemple #7
0
def _verify_unique_measurement_keys(operations: Iterable[cirq.Operation]):
    seen: Set[str] = set()
    for op in operations:
        if cirq.is_measurement(op):
            key = cirq.measurement_key_name(op)
            if key in seen:
                raise ValueError(f'Measurement key {key} repeated')
            seen.add(key)
def test_is_measurement_memoization():
    a = cirq.LineQubit(0)
    circuit = cirq.FrozenCircuit(cirq.measure(a, key='m'))
    c_op = cirq.CircuitOperation(circuit)
    assert circuit._has_measurements is None
    # Memoize `_has_measurements` in the circuit.
    assert cirq.is_measurement(c_op)
    assert circuit._has_measurements is True
Exemple #9
0
def get_all_measurement_keys(circuit: cirq.Circuit) -> set:
    all_measurement_keys = set()

    for moment in circuit:
        for op in moment:
            if cirq.is_measurement(op):
                all_measurement_keys.add(cirq.measurement_key(op))

    return all_measurement_keys
def test_eval_repr(key):
    # Basic safeguard against repr-inequality.
    op = cirq.GateOperation(
        gate=cirq.PauliMeasurementGate([cirq.X, cirq.Y], key),
        qubits=[cirq.GridQubit(0, 1), cirq.GridQubit(1, 1)],
    )
    cirq.testing.assert_equivalent_repr(op)
    assert cirq.is_measurement(op)
    assert cirq.measurement_key_name(op) == str(key)
Exemple #11
0
def test_measurement_without_key():
    class MeasurementWithoutKey:
        def _is_measurement_(self):
            return True

    with pytest.raises(TypeError, match='no measurement keys'):
        _ = cirq.measurement_key(MeasurementWithoutKey())

    assert cirq.is_measurement(MeasurementWithoutKey())
Exemple #12
0
def sample_circuit(
    ideal_circuit: QPROGRAM,
    representations: List[OperationRepresentation],
    random_state: Optional[Union[int, np.random.RandomState]] = None,
) -> Tuple[QPROGRAM, int, float]:
    """Samples an implementable circuit from the PEC representation of the
    input ideal circuit & returns this circuit as well as its sign and norm.

    This function iterates through each operation in the circuit and samples
    an implementable sequence. The returned sign (norm) is the product of signs
    (norms) sampled for each operation.

    Args:
        ideal_circuit: The ideal circuit from which an implementable circuit
            is sampled.
        representations: List of representations of every operation in the
            input circuit. If a representation cannot be found for an operation
            in the circuit, a ValueError is raised.
        random_state: Seed for sampling.

    Returns:
        imp_circuit: The sampled implementable circuit.
        sign: The sign associated to sampled_circuit.
        norm: The one norm of the PEC coefficients of the circuit.

    Raises:
        ValueError:
            If a representation is not found for an operation in the circuit.
    """
    if isinstance(random_state, int):
        random_state = np.random.RandomState(random_state)

    # TODO: Likely to cause issues - conversions may introduce gates which are
    #  not included in `decompositions`.
    ideal, rtype = convert_to_mitiq(ideal_circuit)

    # copy and remove all moments
    sampled_circuit = deepcopy(ideal)[0:0]

    # Iterate over all operations
    sign = 1
    norm = 1.0
    for op in ideal.all_operations():
        # Ignore all measurements.
        if cirq.is_measurement(op):
            continue

        imp_seq, loc_sign, loc_norm = sample_sequence(cirq.Circuit(op),
                                                      representations,
                                                      random_state)
        cirq_seq, _ = convert_to_mitiq(imp_seq)
        sign *= loc_sign
        norm *= loc_norm
        sampled_circuit.append(cirq_seq.all_operations())

    return convert_from_mitiq(sampled_circuit, rtype), sign, norm
Exemple #13
0
def _needs_trajectories(circuit: cirq.Circuit) -> bool:
    """Checks if the circuit requires trajectory simulation."""
    for op in circuit.all_operations():
        test_op = (op if
                   not cirq.is_parameterized(op) else cirq.resolve_parameters(
                       op, {param: 1
                            for param in cirq.parameter_names(op)}))
        if not (cirq.is_measurement(test_op) or cirq.has_unitary(test_op)):
            return True
    return False
Exemple #14
0
def test_measurement_key():
    class ReturnsStr:
        def _measurement_key_(self):
            return 'door locker'

    assert cirq.is_measurement(ReturnsStr())
    assert cirq.measurement_key(ReturnsStr()) == 'door locker'

    assert cirq.measurement_key(ReturnsStr(), None) == 'door locker'
    assert cirq.measurement_key(ReturnsStr(), NotImplemented) == 'door locker'
    assert cirq.measurement_key(ReturnsStr(), 'a') == 'door locker'
Exemple #15
0
def test_tagged_operation():
    q1 = cirq.GridQubit(1, 1)
    q2 = cirq.GridQubit(2, 2)
    op = cirq.X(q1).with_tags('tag1')
    op_repr = "cirq.X(cirq.GridQubit(1, 1))"
    assert repr(op) == f"cirq.TaggedOperation({op_repr}, 'tag1')"

    assert op.qubits == (q1, )
    assert op.tags == ('tag1', )
    assert op.gate == cirq.X
    assert op.with_qubits(q2) == cirq.X(q2).with_tags('tag1')
    assert op.with_qubits(q2).qubits == (q2, )
    assert not cirq.is_measurement(op)
Exemple #16
0
 def simulate_op(op, temp_state):
     indices = [qubit_map[q] for q in op.qubits]
     if isinstance(op.gate, cirq.ResetChannel):
         self._simulate_reset(op, temp_state, indices)
     elif cirq.is_measurement(op):
         if perform_measurements:
             self._simulate_measurement(
                 op, temp_state, indices, measurements)
     else:
         if cirq.num_qubits(op) <= 3:
             self._simulate_from_matrix(op, temp_state, indices)
         else:
             decomp_ops = cirq.decompose_once(op, default=None)
             if decomp_ops is None:
                 self._simulate_from_matrix(op, temp_state, indices)
             else:
                 for sub_op in cirq.flatten_op_tree(decomp_ops):
                     simulate_op(sub_op, temp_state)
Exemple #17
0
def represent_operations_in_circuit_with_local_depolarizing_noise(
    ideal_circuit: QPROGRAM, noise_level: float
) -> List[OperationRepresentation]:
    """Iterates over all unique operations of the input ``ideal_circuit`` and,
    for each of them, generates the corresponding quasi-probability
    representation (linear combination of implementable noisy operations).

    This function assumes that the tensor product of ``k`` single-qubit
    depolarizing channels affects each implemented operation, where
    ``k`` is the number of qubits associated to the operation.

    This function internally calls
    :func:`represent_operation_with_local_depolarizing_noise` (more details
    about the quasi-probability representation can be found in its docstring).

    Args:
        ideal_circuit: The ideal circuit, whose ideal operations should be
            represented.
        noise_level: The (gate-independent) depolarizing noise level.

    Returns:
        The list of quasi-probability representations associated to
        the operations of the input ``ideal_circuit``.

    .. note::
        Measurement gates are ignored (not represented).

    .. note::
        The returned representations are always defined in terms of
        Cirq circuits, even if the input is not a ``cirq.Circuit``.
    """
    circ, _ = convert_to_mitiq(ideal_circuit)

    representations = []
    for op in set(circ.all_operations()):
        if is_measurement(op):
            continue
        representations.append(
            represent_operation_with_local_depolarizing_noise(
                Circuit(op),
                noise_level,
            )
        )
    return representations
Exemple #18
0
 def simulate_op(op, temp_state):
     indices = [qubit_map[q] for q in op.qubits]
     if isinstance(op.gate, cirq.ResetChannel):
         self._simulate_reset(op, temp_state, indices)
     elif cirq.is_measurement(op):
         if perform_measurements:
             self._simulate_measurement(op, temp_state, indices,
                                        measurements)
     else:
         decomp_ops = cirq.decompose_once(op, default=None)
         if decomp_ops is None:
             self._simulate_from_matrix(op, temp_state, indices)
         else:
             try:
                 temp2_state = temp_state.copy()
                 for sub_op in cirq.flatten_op_tree(decomp_ops):
                     simulate_op(sub_op, temp2_state)
                 temp_state[...] = temp2_state
             except ValueError:
                 # Non-classical unitary in the decomposition
                 self._simulate_from_matrix(op, temp_state, indices)
Exemple #19
0
def test_is_measurement():
    q = cirq.NamedQubit('q')
    assert cirq.is_measurement(cirq.measure(q))
    assert cirq.is_measurement(cirq.MeasurementGate(num_qubits=1, key='b'))

    assert not cirq.is_measurement(cirq.X(q))
    assert not cirq.is_measurement(cirq.X)
    assert not cirq.is_measurement(cirq.bit_flip(1))

    class NotImplementedOperation(cirq.Operation):
        def with_qubits(self, *new_qubits) -> 'NotImplementedOperation':
            raise NotImplementedError()

        @property
        def qubits(self):
            return cirq.LineQubit.range(2)

    assert not cirq.is_measurement(NotImplementedOperation())
Exemple #20
0
 def validate_operation(self, operation: 'cirq.Operation') -> None:
     if not cirq.is_measurement(operation):
         raise ValueError(
             f'{operation} is not a measurement and this device only measures!'
         )
Exemple #21
0
 def keep(op):
     return ((cirq.num_qubits(op) <= 32 and
              (cirq.has_unitary(op) or cirq.has_mixture(op)))
             or cirq.is_measurement(op)
             or isinstance(op.gate, cirq.ResetChannel))
Exemple #22
0
 def keep(potential_op):
     return (cirq.has_unitary(potential_op) or
             cirq.has_mixture(potential_op) or
             cirq.is_measurement(potential_op) or
             cirq.op_gate_isinstance(potential_op, cirq.ResetChannel))
def test_consistent_protocols(observable, key):
    gate = cirq.PauliMeasurementGate(observable, key=key)
    cirq.testing.assert_implements_consistent_protocols(gate)
    assert cirq.is_measurement(gate)
    assert cirq.measurement_key_name(gate) == str(key)
Exemple #24
0
    def translate_cirq_to_qtrajectory(
        self,
        qubit_order: cirq.ops.QubitOrderOrList = cirq.ops.QubitOrder.DEFAULT
    ) -> qsim.NoisyCircuit:
        """
        Translates this noisy Cirq circuit to the qsim representation.
        :qubit_order: Ordering of qubits
        :return: a C++ qsim NoisyCircuit object
        """
        qsim_ncircuit = qsim.NoisyCircuit()
        ordered_qubits = cirq.ops.QubitOrder.as_qubit_order(
            qubit_order).order_for(self.all_qubits())

        # qsim numbers qubits in reverse order from cirq
        ordered_qubits = list(reversed(ordered_qubits))

        qsim_ncircuit.num_qubits = len(ordered_qubits)

        def has_qsim_kind(op: cirq.ops.GateOperation):
            return _cirq_gate_kind(op.gate) != None

        def to_matrix(op: cirq.ops.GateOperation):
            mat = cirq.unitary(op.gate, None)
            if mat is None:
                return NotImplemented

            return cirq.ops.MatrixGate(mat).on(*op.qubits)

        qubit_to_index_dict = {q: i for i, q in enumerate(ordered_qubits)}
        time_offset = 0
        for moment in self:
            moment_length = 0
            ops_by_gate = []
            ops_by_mix = []
            ops_by_channel = []
            # Capture ops of each type in the appropriate list.
            for qsim_op in moment:
                if cirq.has_unitary(qsim_op) or cirq.is_measurement(qsim_op):
                    oplist = cirq.decompose(qsim_op,
                                            fallback_decomposer=to_matrix,
                                            keep=has_qsim_kind)
                    ops_by_gate.append(oplist)
                    moment_length = max(moment_length, len(oplist))
                    pass
                elif cirq.has_mixture(qsim_op):
                    ops_by_mix.append(qsim_op)
                    moment_length = max(moment_length, 1)
                    pass
                elif cirq.has_channel(qsim_op):
                    ops_by_channel.append(qsim_op)
                    moment_length = max(moment_length, 1)
                    pass
                else:
                    raise ValueError(f'Encountered unparseable op: {qsim_op}')

            # Gates must be added in time order.
            for gi in range(moment_length):
                # Handle gate output.
                for gate_ops in ops_by_gate:
                    if gi >= len(gate_ops):
                        continue
                    qsim_op = gate_ops[gi]
                    time = time_offset + gi
                    gate_kind = _cirq_gate_kind(qsim_op.gate)
                    add_op_to_circuit(qsim_op, time, qubit_to_index_dict,
                                      qsim_ncircuit)
                # Handle mixture output.
                for mixture in ops_by_mix:
                    mixdata = []
                    for prob, mat in cirq.mixture(mixture):
                        square_mat = np.reshape(mat,
                                                (int(np.sqrt(mat.size)), -1))
                        unitary = cirq.is_unitary(square_mat)
                        # Package matrix into a qsim-friendly format.
                        mat = np.reshape(mat, (-1, )).astype(np.complex64,
                                                             copy=False)
                        mixdata.append((prob, mat.view(np.float32), unitary))
                    qubits = [qubit_to_index_dict[q] for q in mixture.qubits]
                    qsim.add_channel(time_offset, qubits, mixdata,
                                     qsim_ncircuit)
                # Handle channel output.
                for channel in ops_by_channel:
                    chdata = []
                    for i, mat in enumerate(cirq.channel(channel)):
                        square_mat = np.reshape(mat,
                                                (int(np.sqrt(mat.size)), -1))
                        unitary = cirq.is_unitary(square_mat)
                        singular_vals = np.linalg.svd(square_mat)[1]
                        lower_bound_prob = min(singular_vals)**2
                        # Package matrix into a qsim-friendly format.
                        mat = np.reshape(mat, (-1, )).astype(np.complex64,
                                                             copy=False)
                        chdata.append(
                            (lower_bound_prob, mat.view(np.float32), unitary))
                    qubits = [qubit_to_index_dict[q] for q in channel.qubits]
                    qsim.add_channel(time_offset, qubits, chdata,
                                     qsim_ncircuit)
            time_offset += moment_length

        return qsim_ncircuit
Exemple #25
0
 def _can_be_in_run_prefix(self, val):
     return not cirq.is_measurement(val)
Exemple #26
0
def sample_circuit(
    ideal_circuit: QPROGRAM,
    representations: Sequence[OperationRepresentation],
    random_state: Optional[Union[int, np.random.RandomState]] = None,
    num_samples: int = 1,
) -> Tuple[List[QPROGRAM], List[int], float]:
    """Samples a list of implementable circuits from the quasi-probability
    representation of the input ideal circuit.
    Returns the list of circuits, the corresponding list of signs and the
    one-norm of the quasi-probability representation (of the full circuit).

    Args:
        ideal_circuit: The ideal circuit from which an implementable circuit
            is sampled.
        representations: List of representations of every operation in the
            input circuit. If a representation cannot be found for an operation
            in the circuit, a ValueError is raised.
        random_state: Seed for sampling.
        num_samples: The number of samples.

    Returns:
        The tuple (``sampled_circuits``, ``signs``, ``norm``) where
        ``sampled_circuits`` are the sampled implementable circuits,
        ``signs`` are the signs associated to sampled_circuits and
        ``norm`` is the one-norm of the circuit representation.

    Raises:
        ValueError:
            If a representation is not found for an operation in the circuit.
    """
    if isinstance(random_state, int):
        random_state = np.random.RandomState(random_state)

    # TODO: Likely to cause issues - conversions may introduce gates which are
    #  not included in `decompositions`.
    ideal, rtype = convert_to_mitiq(ideal_circuit)

    # copy and remove all moments
    sampled_circuits = [deepcopy(ideal)[0:0] for _ in range(num_samples)]
    sampled_signs = [1 for _ in range(num_samples)]
    norm = 1.0

    for op in ideal.all_operations():
        # Ignore all measurements.
        if cirq.is_measurement(op):
            continue

        sequences, loc_signs, loc_norm = sample_sequence(
            cirq.Circuit(op),
            representations,
            num_samples=num_samples,
            random_state=random_state,
        )

        norm *= loc_norm

        for j in range(num_samples):
            sampled_signs[j] *= loc_signs[j]
            cirq_seq, _ = convert_to_mitiq(sequences[j])
            sampled_circuits[j].append(cirq_seq.all_operations())

    native_circuits = [convert_from_mitiq(c, rtype) for c in sampled_circuits]

    return native_circuits, sampled_signs, norm