def decompose_to_target_gateset(self, op: 'cirq.Operation',
                                 moment_idx: int) -> DecomposeResult:
     if not 1 <= protocols.num_qubits(op) <= 2:
         return self._decompose_multi_qubit_operation(op, moment_idx)
     if protocols.num_qubits(op) == 1:
         return self._decompose_single_qubit_operation(op, moment_idx)
     new_optree = self._decompose_two_qubit_operation(op, moment_idx)
     if new_optree is NotImplemented or new_optree is None:
         return new_optree
     new_optree = [*ops.flatten_to_ops_or_moments(new_optree)]
     op_untagged = op.untagged
     old_optree = ([*op_untagged.circuit]
                   if isinstance(op_untagged, circuits.CircuitOperation)
                   and self._intermediate_result_tag in op.tags else [op])
     old_2q_gate_count = sum(1 for o in ops.flatten_to_ops(old_optree)
                             if len(o.qubits) == 2)
     new_2q_gate_count = sum(1 for o in ops.flatten_to_ops(new_optree)
                             if len(o.qubits) == 2)
     switch_to_new = (any(
         protocols.num_qubits(op) == 2 and op not in self
         for op in ops.flatten_to_ops(old_optree))
                      or new_2q_gate_count < old_2q_gate_count)
     if switch_to_new:
         return new_optree
     mapped_old_optree: List['cirq.OP_TREE'] = []
     for old_op in ops.flatten_to_ops(old_optree):
         if old_op in self:
             mapped_old_optree.append(old_op)
         else:
             decomposed_op = self._decompose_single_qubit_operation(
                 old_op, moment_idx)
             if decomposed_op is None or decomposed_op is NotImplemented:
                 return NotImplemented
             mapped_old_optree.append(decomposed_op)
     return mapped_old_optree
Esempio n. 2
0
def _translate_cirq_operation_to_braket_instruction(
    op: cirq_ops.Operation,
) -> List[Instruction]:
    """Converts the Cirq operation to an equivalent Braket instruction or list
    of instructions.

    Args:
        op: Cirq operation to convert.

    Raises:
        ValueError: If the operation cannot be converted to Braket.
    """
    nqubits = protocols.num_qubits(op)

    if nqubits == 1:
        return _translate_one_qubit_cirq_operation_to_braket_instruction(op)

    elif nqubits == 2:
        return _translate_two_qubit_cirq_operation_to_braket_instruction(op)

    elif nqubits == 3:
        qubits = [q.x for q in op.qubits]

        if op == cirq_ops.TOFFOLI.on(*op.qubits):
            return [Instruction(braket_gates.CCNot(), qubits)]
        elif op == cirq_ops.FREDKIN.on(*op.qubits):
            return [Instruction(braket_gates.CSwap(), qubits)]
        else:
            _raise_cirq_to_braket_error(op)
    # Unsupported gates.
    else:
        _raise_cirq_to_braket_error(op)
Esempio n. 3
0
def assert_has_consistent_apply_unitary(val: Any,
                                        *,
                                        qubit_count: Optional[int] = None,
                                        atol: float = 1e-8) -> None:
    """Tests whether a value's _apply_unitary_ is correct.

    Contrasts the effects of the value's `_apply_unitary_` with the
    matrix returned by the value's `_unitary_` method.

    Args:
        val: The value under test. Should have a `__pow__` method.
        qubit_count: Usually inferred. The number of qubits the value acts on.
            This argument isn't needed if the gate has a unitary matrix or
            implements `cirq.SingleQubitGate`/`cirq.TwoQubitGate`/
            `cirq.ThreeQubitGate`.
        atol: Absolute error tolerance.
    """

    expected = protocols.unitary(val, default=None)

    qubit_counts = [
        qubit_count,
        # Only fall back to using the unitary size if num_qubits or qid_shape
        # protocols are not defined.
        protocols.num_qubits(val,
                             default=expected.shape[0].bit_length() -
                             1 if expected is not None else None),
        _infer_qubit_count(val)
    ]
    qubit_counts = [e for e in qubit_counts if e is not None]
    if not qubit_counts:
        raise NotImplementedError(
            'Failed to infer qubit count of <{!r}>. Specify it.'.format(val))
    assert len(set(qubit_counts)) == 1, (
        'Inconsistent qubit counts from different methods: {}'.format(
            qubit_counts))
    n = cast(int, qubit_counts[0])
    qid_shape = protocols.qid_shape(val, default=(2, ) * n)

    eye = linalg.eye_tensor((2, ) + qid_shape, dtype=np.complex128)
    actual = protocols.apply_unitary(
        unitary_value=val,
        args=protocols.ApplyUnitaryArgs(target_tensor=eye,
                                        available_buffer=np.ones_like(eye) *
                                        float('nan'),
                                        axes=list(range(1, n + 1))),
        default=None)

    # If you don't have a unitary, you shouldn't be able to apply a unitary.
    if expected is None:
        assert actual is None
    else:
        expected = np.kron(np.eye(2), expected)

    # If you applied a unitary, it should match the one you say you have.
    if actual is not None:
        np.testing.assert_allclose(actual.reshape((np.prod(
            (2, ) + qid_shape, dtype=int), ) * 2),
                                   expected,
                                   atol=atol)
Esempio n. 4
0
def route_circuit(circuit: circuits.Circuit,
                  device_graph: nx.Graph,
                  *,
                  algo_name: Optional[str] = None,
                  router: Optional[Callable[..., SwapNetwork]] = None,
                  **kwargs) -> SwapNetwork:
    """Routes a circuit on a given device.

    Args:
        circuit: The circuit to route.
        device_graph: The device's graph, in which each vertex is a qubit and
            each edge indicates the ability to do an operation on those qubits.
        algo_name: The name of a routing algorithm. Must be in ROUTERS.
        router: The function that actually does the routing.
        **kwargs: Arguments to pass to the routing algorithm.

    Exactly one of algo_name and router must be specified.
    """

    if any(protocols.num_qubits(op) > 2 for op in circuit.all_operations()):
        raise ValueError('Can only route circuits with operations that act on'
                         ' at most 2 qubits.')

    if len(list(circuit.all_qubits())) > device_graph.number_of_nodes():
        raise ValueError('Number of logical qubits is greater than number'
                         ' of physical qubits.')

    if not (algo_name is None or router is None):
        raise ValueError(
            'At most one of algo_name or router can be specified.')
    if algo_name is not None:
        router = ROUTERS[algo_name]
    elif router is None:
        raise ValueError(f'No routing algorithm specified.')
    return router(circuit, device_graph, **kwargs)
Esempio n. 5
0
    def __init__(
        self,
        gate: Union[Type[raw_types.Gate], raw_types.Gate],
        *,
        name: Optional[str] = None,
        description: Optional[str] = None,
        max_parallel_allowed: Optional[int] = None,
    ) -> None:
        """Inits ParallelGateFamily

        Args:
            gate: The gate which can act in parallel. It can be a python `type` inheriting from
                `cirq.Gate` or a non-parameterized instance of a `cirq.Gate`. If an instance of
                `cirq.ParallelGate` is passed, then the corresponding `gate.sub_gate` is used.
            name: The name of the gate family.
            description: Human readable description of the gate family.
            max_parallel_allowed: The maximum number of qubits on which a given gate `g`
            can act on. If None, then any number of qubits are allowed.
        """
        if isinstance(gate, parallel_gate.ParallelGate):
            if not max_parallel_allowed:
                max_parallel_allowed = protocols.num_qubits(gate)
            gate = cast(parallel_gate.ParallelGate, gate).sub_gate
        self._max_parallel_allowed = max_parallel_allowed
        super().__init__(gate, name=name, description=description)
Esempio n. 6
0
 def _predicate(self, gate: raw_types.Gate) -> bool:
     if (self._max_parallel_allowed is not None
             and protocols.num_qubits(gate) > self._max_parallel_allowed):
         return False
     gate = gate.sub_gate if isinstance(
         gate, parallel_gate.ParallelGate) else gate
     return super()._predicate(gate)
Esempio n. 7
0
 def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
     op_untagged = op.untagged
     if (
         deep
         and isinstance(op_untagged, circuits.CircuitOperation)
         and merged_circuit_op_tag not in op.tags
     ):
         return op_untagged.replace(
             circuit=_rewrite_merged_k_qubit_unitaries(
                 op_untagged.circuit,
                 context=context,
                 k=k,
                 rewriter=rewriter,
                 merged_circuit_op_tag=merged_circuit_op_tag,
             ).freeze()
         ).with_tags(*op.tags)
     if not (protocols.num_qubits(op) <= k and protocols.has_unitary(op)):
         return op
     if rewriter:
         return rewriter(
             cast(circuits.CircuitOperation, op_untagged)
             if merged_circuit_op_tag in op.tags
             else circuits.CircuitOperation(circuits.FrozenCircuit(op))
         )
     return ops.MatrixGate(protocols.unitary(op)).on(*op.qubits)
Esempio n. 8
0
def assert_has_consistent_qid_shape(val: Any) -> None:
    """Tests whether a value's `_qid_shape_` and `_num_qubits_` are correct and
    consistent.

    Verifies that the entries in the shape are all positive integers and the
    length of shape equals `_num_qubits_` (and also equals `len(qubits)` if
    `val` has `qubits`.

    Args:
        val: The value under test. Should have `_qid_shape_` and/or
            `num_qubits_` methods. Can optionally have a `qubits` property.
    """
    default = (-1, )
    qid_shape = protocols.qid_shape(val, default)
    num_qubits = protocols.num_qubits(val, default)
    if qid_shape is default or num_qubits is default:
        return  # Nothing to check
    assert all(
        d >= 1 for d in
        qid_shape), f'Not all entries in qid_shape are positive: {qid_shape}'
    assert (
        len(qid_shape) == num_qubits
    ), f'Length of qid_shape and num_qubits disagree: {qid_shape}, {num_qubits}'

    if isinstance(val, ops.Operation):
        assert num_qubits == len(
            val.qubits
        ), f'Length of num_qubits and val.qubits disagrees: {num_qubits}, {len(val.qubits)}'
Esempio n. 9
0
def state_vector_has_stabilizer(state_vector: np.ndarray,
                                stabilizer: DensePauliString) -> bool:
    """Checks that the state_vector is stabilized by the given stabilizer.

    The stabilizer should not modify the value of the state_vector, up to the
    global phase.

    Args:
        state_vector: An input state vector. Is not mutated by this function.
        stabilizer: A potential stabilizer of the above state_vector as a
          DensePauliString.

    Returns:
        Whether the stabilizer stabilizes the supplied state.
    """

    qubits = LineQubit.range(protocols.num_qubits(stabilizer))
    args = state_vector_simulation_state.StateVectorSimulationState(
        available_buffer=np.empty_like(state_vector),
        qubits=qubits,
        prng=np.random.RandomState(),
        initial_state=state_vector.copy(),
        dtype=state_vector.dtype,
    )
    protocols.act_on(stabilizer, args, qubits)
    return np.allclose(args.target_tensor, state_vector)
Esempio n. 10
0
 def _commutes_(self, other: Any, atol: Union[int, float] = 1e-8
               ) -> Union[bool, NotImplementedType]:
     if (isinstance(other, ops.Gate) and
             isinstance(other, ops.InterchangeableQubitsGate) and
             protocols.num_qubits(other) == 2):
         return True
     return NotImplemented
def assert_pauli_expansion_is_consistent_with_unitary(val: Any) -> None:
    """Checks Pauli expansion against unitary matrix."""
    # Check to see if the protocol is supported without doing a fallback
    # to unitary, otherwise the test is vacuous.
    method = getattr(val, '_pauli_expansion_', None)
    if method is None:
        return

    pauli_expansion = protocols.pauli_expansion(val, default=None)
    if pauli_expansion is None:
        return

    unitary = protocols.unitary(val, None)
    if unitary is None:
        return

    num_qubits = protocols.num_qubits(val,
                                      default=unitary.shape[0].bit_length() -
                                      1)
    basis = operator_spaces.kron_bases(operator_spaces.PAULI_BASIS,
                                       repeat=num_qubits)

    recovered_unitary = operator_spaces.matrix_from_basis_coefficients(
        pauli_expansion, basis)
    assert np.allclose(unitary, recovered_unitary, rtol=0, atol=1e-12)
    def _strat_act_from_single_qubit_decompose(
        self, val: Any, qubits: Sequence['cirq.Qid']
    ) -> bool:
        if num_qubits(val) == 1:
            if not has_unitary(val):
                return NotImplemented
            u = unitary(val)
            clifford_gate = SingleQubitCliffordGate.from_unitary(u)
            if clifford_gate is not None:
                # Gather the effective unitary applied so as to correct for the
                # global phase later.
                final_unitary = np.eye(2)
                for axis, quarter_turns in clifford_gate.decompose_rotation():
                    gate = axis ** (quarter_turns / 2)
                    self._strat_apply_gate(gate, qubits)
                    final_unitary = np.matmul(unitary(gate), final_unitary)

                # Find the entry with the largest magnitude in the input unitary.
                k = max(np.ndindex(*u.shape), key=lambda t: abs(u[t]))
                # Correct the global phase that wasn't conserved in the above
                # decomposition.
                self._state.apply_global_phase(u[k] / final_unitary[k])
                return True

        return NotImplemented
def _strat_act_on_stabilizer_ch_form_from_single_qubit_decompose(
        val: Any, args: 'cirq.ActOnStabilizerCHFormArgs') -> bool:
    if num_qubits(val) == 1:
        if not has_unitary(val):
            return NotImplemented
        u = unitary(val)
        clifford_gate = SingleQubitCliffordGate.from_unitary(u)
        if clifford_gate is not None:
            # Gather the effective unitary applied so as to correct for the
            # global phase later.
            final_unitary = np.eye(2)
            for axis, quarter_turns in clifford_gate.decompose_rotation():
                gate = None  # type: Optional[cirq.Gate]
                if axis == pauli_gates.X:
                    gate = common_gates.XPowGate(exponent=quarter_turns / 2)
                    assert gate._act_on_(args)
                elif axis == pauli_gates.Y:
                    gate = common_gates.YPowGate(exponent=quarter_turns / 2)
                    assert gate._act_on_(args)
                else:
                    assert axis == pauli_gates.Z
                    gate = common_gates.ZPowGate(exponent=quarter_turns / 2)
                    assert gate._act_on_(args)

                final_unitary = np.matmul(unitary(gate), final_unitary)

            # Find the entry with the largest magnitude in the input unitary.
            k = max(np.ndindex(*u.shape), key=lambda t: abs(u[t]))
            # Correct the global phase that wasn't conserved in the above
            # decomposition.
            args.state.omega *= u[k] / final_unitary[k]
            return True

    return NotImplemented
Esempio n. 14
0
def _translate_cirq_operation_to_braket_instruction(
    op: cirq_ops.Operation, ) -> List[Instruction]:
    """Converts the Cirq operation to an equivalent Braket instruction or list
    of instructions.

    Args:
        op: Cirq operation to convert.

    Raises:
        ValueError: If the operation cannot be converted to Braket.
    """
    nqubits = protocols.num_qubits(op)

    if nqubits == 1:
        return _translate_one_qubit_cirq_operation_to_braket_instruction(op)

    elif nqubits == 2:
        return _translate_two_qubit_cirq_operation_to_braket_instruction(op)

    elif nqubits == 3:
        qubits = [q.x for q in op.qubits]

        if isinstance(op.gate, cirq_ops.TOFFOLI):
            return [Instruction(braket_gates.CCNot(), qubits)]
        elif isinstance(op.gate, cirq_ops.FREDKIN):
            return [Instruction(braket_gates.CSwap(), qubits)]

    # Unsupported gates.
    else:
        raise ValueError(
            f"Unable to convert {op} to Braket. If you think this is a bug, "
            "you can open an issue on the Mitiq GitHub at"
            " https://github.com/unitaryfund/mitiq.")
Esempio n. 15
0
 def can_merge_moment(m: 'cirq.Moment'):
     return all(
         protocols.num_qubits(op) == 1
         and protocols.has_unitary(op)
         and tags_to_ignore.isdisjoint(op.tags)
         for op in m
     )
Esempio n. 16
0
def state_vector_has_stabilizer(state_vector: np.ndarray,
                                stabilizer: DensePauliString) -> bool:
    """Checks that the state_vector is stabilized by the given stabilizer.

    The stabilizer should not modify the value of the state_vector, up to the
    global phase.

    Args:
        state_vector: An input state vector. Is not mutated by this function.
        stabilizer: A potential stabilizer of the above state_vector as a
          DensePauliString.

    Returns:
        Whether the stabilizer stabilizes the supplied state.
    """

    args = act_on_state_vector_args.ActOnStateVectorArgs(
        target_tensor=state_vector.copy(),
        available_buffer=np.empty_like(state_vector),
        axes=range(protocols.num_qubits(stabilizer)),
        prng=np.random.RandomState(),
        log_of_measurement_results={},
    )
    protocols.act_on(stabilizer, args)
    return np.allclose(args.target_tensor, state_vector)
Esempio n. 17
0
def assert_has_consistent_qid_shape(val: Any,
                                    qubit_count: Optional[int] = None) -> None:
    """Tests whether a value's `_qid_shape_` and `_num_qubits_` are correct and
    consistent.

    Verifies that the entries in the shape are all positive integers and the
    length of shape equals `_num_qubits_` (and also equals `len(qubits)` if
    `val` has `qubits`.

    Args:
        val: The value under test. Should have `_qid_shape_` and/or
            `num_qubits_` methods. Can optionally have a `qubits` property.
        qubit_count: The expected number of qubits val should use.
    """
    default = (-1,)
    qid_shape = protocols.qid_shape(val, default)
    num_qubits = protocols.num_qubits(val, default)
    if qid_shape is default or num_qubits is default:
        return  # Nothing to check
    assert all(d >= 1 for d in qid_shape), (
        f'Not all entries in qid_shape are positive: {qid_shape}')
    assert len(qid_shape) == num_qubits, (
        f'Length of qid_shape and num_qubits disagree: {qid_shape}, '
        f'{num_qubits}')
    if qubit_count is not None:
        assert qubit_count == num_qubits, (
            f'Expected qubits and num_qubits disagree: {qubit_count}, '
            f'{num_qubits}')
    infer_qubit_count = _infer_qubit_count(val)
    if infer_qubit_count is not None:
        assert infer_qubit_count == num_qubits, (
            f'Length of qubits and num_qubits disagree: {infer_qubit_count}, '
            f'{num_qubits}')
def build_entangling_layers(
    qubits: Sequence[devices.GridQubit], two_qubit_gate: ops.Gate
) -> List[ops.Moment]:
    """Builds a sequence of gates that entangle all pairs of qubits on a grid.

    The qubits are restricted to be physically on a square grid with distinct
    row and column indices (not every node of the grid needs to have a
    qubit). To entangle all pairs of qubits, a user-specified two-qubit gate
    is applied between each and every pair of qubit that are next to each
    other. In general, a total of four sets of parallel operations are needed to
    perform all possible two-qubit gates. We proceed as follows:

    The first layer applies two-qubit gates to qubits (i, j) and (i, j + 1)
    where i is any integer and j is an even integer. The second layer
    applies two-qubit gates to qubits (i, j) and (i + 1, j) where i is an even
    integer and j is any integer. The third layer applies two-qubit gates
    to qubits (i, j) and (i, j + 1) where i is any integer and j is an odd
    integer. The fourth layer applies two-qubit gates to qubits (i, j) and
    (i + 1, j) where i is an odd integer and j is any integer.

    After the layers are built as above, any empty layer is ejected.:

                 Cycle 1:                            Cycle 2:
        q00 ── q01    q02 ── q03            q00    q01    q02    q03
                                             |      |      |      |
        q10 ── q11    q12 ── q13            q10    q11    q12    q13

        q20 ── q21    q22 ── q23            q20    q21    q22    q23
                                             |      |      |      |
        q30 ── q31    q32 ── q33            q30    q31    q32    q33

                  Cycle 3:                           Cycle 4:
        q00    q01 ── q02    q03            q00    q01    q02    q03

        q10    q11 ── q12    q13            q10    q11    q12    q13
                                             |      |      |      |
        q20    q21 ── q22    q23            q20    q21    q22    q23

        q30    q31 ── q32    q33            q30    q31    q32    q33

    Args:
        qubits: The grid qubits included in the entangling operations.
        two_qubit_gate: The two-qubit gate to be applied between all
            neighboring pairs of qubits.

    Returns:
        A list of ops.Moment, with a maximum length of 4. Each ops.Moment
        includes two-qubit gates which can be performed at the same time.

    Raises:
        ValueError: two-qubit gate is not used.
    """
    if protocols.num_qubits(two_qubit_gate) != 2:
        raise ValueError('Input must be a two-qubit gate')
    interaction_sequence = _default_interaction_sequence(qubits)
    return [
        ops.Moment([two_qubit_gate(q_a, q_b) for (q_a, q_b) in pairs])
        for pairs in interaction_sequence
    ]
Esempio n. 19
0
 def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
     if not (protocols.num_qubits(op) <= k and protocols.has_unitary(op)):
         return op
     if rewriter:
         return rewriter(
             cast(circuits.CircuitOperation, op.untagged
                  ) if merged_circuit_op_tag in op.tags else circuits.
             CircuitOperation(circuits.FrozenCircuit(op)))
     return ops.MatrixGate(protocols.unitary(op)).on(*op.qubits)
Esempio n. 20
0
    def validate_args(self, qubits: Sequence[Qid]) -> None:
        """Checks if this gate can be applied to the given qubits.

        By default checks if input is of type Qid and qubit count.
        Child classes can override.

        Args:
            qubits: The collection of qubits to potentially apply the gate to.

        Throws:
            ValueError: The gate can't be applied to the qubits.
        """
        if len(qubits) != protocols.num_qubits(self):
            raise ValueError('Wrong number of qubits for <{!r}>. '
                             'Expected {} qubits but got <{!r}>.'.format(
                                 self, protocols.num_qubits(self), qubits))

        if any([not isinstance(qubit, Qid) for qubit in qubits]):
            raise ValueError('Gate was called with type different than Qid.')
Esempio n. 21
0
def _strat_has_stabilizer_effect_from_unitary(val: Any) -> Optional[bool]:
    """Attempts to infer whether val has stabilizer effect from its unitary.
    Returns whether unitary of `val` normalizes the Pauli group. Works only for
    2x2 unitaries.
    """
    # Do not try this strategy if there is no unitary or if the number of
    # qubits is not 1 since that would be expensive.
    if not protocols.has_unitary(val) or protocols.num_qubits(val) != 1:
        return None
    unitary = protocols.unitary(val)
    return SingleQubitCliffordGate.from_unitary(unitary) is not None
Esempio n. 22
0
def assert_act_on_clifford_tableau_effect_matches_unitary(val: Any) -> None:
    """Checks that act_on with CliffordTableau generates stabilizers that
    stabilize the final state vector. Does not work with Operations or Gates
    expecting non-qubit Qids."""

    # pylint: disable=unused-variable
    __tracebackhide__ = True
    # pylint: enable=unused-variable

    num_qubits_val = protocols.num_qubits(val)

    if not protocols.has_unitary(val) or \
            protocols.qid_shape(val) != (2,) * num_qubits_val:
        return None

    qubits = LineQubit.range(protocols.num_qubits(val) * 2)
    qubit_map = {qubit: i for i, qubit in enumerate(qubits)}

    circuit = Circuit()
    for i in range(num_qubits_val):
        circuit.append([
            common_gates.H(qubits[i]),
            common_gates.CNOT(qubits[i], qubits[-i - 1])
        ])
    if hasattr(val, "on"):
        circuit.append(val.on(*qubits[:num_qubits_val]))
    else:
        circuit.append(val.with_qubits(*qubits[:num_qubits_val]))

    tableau = _final_clifford_tableau(circuit, qubit_map)
    if tableau is None:
        return None

    state_vector = np.reshape(final_state_vector(circuit, qubit_order=qubits),
                              protocols.qid_shape(qubits))

    assert all(
        state_vector_has_stabilizer(state_vector, stab)
        for stab in tableau.stabilizers()), (
            "act_on clifford tableau is not consistent with "
            "final_state_vector simulation.\n\nval: {!r}".format(val))
Esempio n. 23
0
 def preprocess_transformers(self) -> List['cirq.TRANSFORMER']:
     """List of transformers which should be run before decomposing individual operations."""
     return [
         _create_transformer_with_kwargs(
             expand_composite.expand_composite,
             no_decomp=lambda op: protocols.num_qubits(op) <= self.num_qubits,
         ),
         _create_transformer_with_kwargs(
             merge_k_qubit_gates.merge_k_qubit_unitaries,
             k=self.num_qubits,
             rewriter=lambda op: op.with_tags(self._intermediate_result_tag),
         ),
     ]
Esempio n. 24
0
def state_vector_has_stabilizer(state_vector: np.ndarray,
                                stabilizer: DensePauliString) -> bool:
    """Checks that the stabilizer does not modify the value of the
    state_vector, including the global phase. Does not mutate the input
    state_vector."""

    args = act_on_state_vector_args.ActOnStateVectorArgs(
        target_tensor=state_vector.copy(),
        available_buffer=np.empty_like(state_vector),
        axes=range(protocols.num_qubits(stabilizer)),
        prng=np.random.RandomState(),
        log_of_measurement_results={})
    protocols.act_on(stabilizer, args)
    return np.allclose(args.target_tensor, state_vector)
def _known_gate_with_no_decomposition(val: Any):
    """Checks whether `val` is a known gate with no default decomposition to default gateset."""
    if isinstance(val, ops.MatrixGate):
        return protocols.qid_shape(val) not in [(2, ), (2, ) * 2, (2, ) * 3]
    if isinstance(val,
                  ops.BaseDensePauliString) and not protocols.has_unitary(val):
        return True
    if isinstance(val, ops.ControlledGate):
        if protocols.is_parameterized(val):
            return True
        if isinstance(
                val.sub_gate,
                ops.MatrixGate) and protocols.num_qubits(val.sub_gate) > 1:
            return True
        if val.control_qid_shape != (2, ) * val.num_controls():
            return True
        return _known_gate_with_no_decomposition(val.sub_gate)
    return False
    def _strat_act_from_single_qubit_decompose(
        self, val: Any, qubits: Sequence['cirq.Qid']
    ) -> bool:
        if num_qubits(val) == 1:
            if not has_unitary(val):
                return NotImplemented
            u = unitary(val)
            gate_and_phase = SingleQubitCliffordGate.from_unitary_with_global_phase(u)
            if gate_and_phase is not None:
                clifford_gate, global_phase = gate_and_phase
                # Apply gates.
                for gate in clifford_gate.decompose_gate():
                    self._strat_apply_gate(gate, qubits)
                # Apply global phase.
                self._state.apply_global_phase(global_phase)
                return True

        return NotImplemented
Esempio n. 27
0
    def with_qubits(self, *new_qubits: 'cirq.Qid') -> 'CircuitOperation':
        """Returns a copy of this operation with an updated qubit mapping.

        Args:
            new_qubits: A list of qubits to target. Qubits in this list are
                matched to qubits in the circuit following default qubit order,
                ignoring any existing qubit map.

        Returns:
            A copy of this operation targeting `new_qubits`.

        Raises:
            ValueError: `new_qubits` has a different number of qubits than
                this operation.
        """
        expected = protocols.num_qubits(self.circuit)
        if len(new_qubits) != expected:
            raise ValueError(f'Expected {expected} qubits, got {len(new_qubits)}.')
        return self.with_qubit_mapping(dict(zip(self.qubits, new_qubits)))
def _strat_act_on_clifford_tableau_from_single_qubit_decompose(
    val: Any, args: 'cirq.ActOnCliffordTableauArgs', qubits: Sequence['cirq.Qid']
) -> bool:
    if num_qubits(val) == 1:
        if not has_unitary(val):
            return NotImplemented
        u = unitary(val)
        clifford_gate = SingleQubitCliffordGate.from_unitary(u)
        if clifford_gate is not None:
            for axis, quarter_turns in clifford_gate.decompose_rotation():
                if axis == pauli_gates.X:
                    common_gates.XPowGate(exponent=quarter_turns / 2)._act_on_(args, qubits)
                elif axis == pauli_gates.Y:
                    common_gates.YPowGate(exponent=quarter_turns / 2)._act_on_(args, qubits)
                else:
                    assert axis == pauli_gates.Z
                    common_gates.ZPowGate(exponent=quarter_turns / 2)._act_on_(args, qubits)
            return True

    return NotImplemented
Esempio n. 29
0
    def __pow__(self, power):
        if power == 1:
            return self

        if power == -1:
            # HACK: break cycle
            from cirq.devices import line_qubit

            decomposed = protocols.decompose_once_with_qubits(
                self,
                qubits=line_qubit.LineQubit.range(protocols.num_qubits(self)),
                default=None)
            if decomposed is None:
                return NotImplemented

            inverse_decomposed = protocols.inverse(decomposed, None)
            if inverse_decomposed is None:
                return NotImplemented

            return _InverseCompositeGate(self)

        return NotImplemented
Esempio n. 30
0
def entanglement_fidelity(operation: 'cirq.SupportsKraus') -> float:
    r"""Returns entanglement fidelity of a given quantum channel.

    Entanglement fidelity $F_e$ of a quantum channel $E: L(H) \to L(H)$ is the overlap between
    the maximally entangled state $|\phi\rangle = \frac{1}{\sqrt{dim H}} \sum_i|i\rangle|i\rangle$
    and the state obtained by sending one half of $|\phi\rangle$ through the channel $E$, i.e.

        $$
        F_e = \langle\phi|(E \otimes I)(|\phi\rangle\langle\phi|)|\phi\rangle
        $$

    where $I: L(H) \to L(H)$ is the identity map.

    Args:
        operation: Quantum channel whose entanglement fidelity is to be computed.
    Returns:
        Entanglement fidelity of the channel represented by operation.
    """
    f = 0.0
    for k in protocols.kraus(operation):
        f += np.abs(np.trace(k)) ** 2
    n_qubits = protocols.num_qubits(operation)
    return float(f / 4**n_qubits)