Beispiel #1
0
def _try_decompose_into_operations_and_qubits(
    val: Any
) -> Tuple[Optional[List['cirq.Operation']], Sequence['cirq.Qid'], Tuple[int,
                                                                         ...]]:
    """Returns the value's decomposition (if any) and the qubits it applies to.
    """
    from cirq.protocols.decompose import (decompose_once,
                                          decompose_once_with_qubits)
    from cirq import LineQubit, Gate, Operation

    if isinstance(val, Gate):
        # Gates don't specify qubits, and so must be handled specially.
        qid_shape = qid_shape_protocol.qid_shape(val)
        qubits = LineQubit.range(len(qid_shape))  # type: Sequence[cirq.Qid]
        return decompose_once_with_qubits(val, qubits, None), qubits, qid_shape

    if isinstance(val, Operation):
        qid_shape = qid_shape_protocol.qid_shape(val)
        return decompose_once(val, None), val.qubits, qid_shape

    result = decompose_once(val, None)
    if result is not None:
        qubit_set = set()
        qid_shape_dict = defaultdict(lambda: 1)  # type: Dict[cirq.Qid, int]
        for op in result:
            for level, q in zip(qid_shape_protocol.qid_shape(op), op.qubits):
                qubit_set.add(q)
                qid_shape_dict[q] = max(qid_shape_dict[q], level)
        qubits = sorted(qubit_set)
        return result, qubits, tuple(qid_shape_dict[q] for q in qubits)

    return None, (), ()
Beispiel #2
0
def _decompose_and_get_unitary(val: 'cirq.Operation') -> np.ndarray:
    """Try to decompose an `Operation` and return its unitary.

    Returns:
        If `val` can be decomposed into unitaries, calculate the resulting
        unitary and return it. If it doesn't exist, None is returned.
    """
    from cirq.protocols.apply_unitary import apply_unitary, ApplyUnitaryArgs
    from cirq.protocols.decompose import decompose_once

    decomposed_val = decompose_once(val, None)
    if decomposed_val is not None:
        # Calculate the resulting unitary (if it exists)
        n = len(val.qubits)
        state = np.eye(1 << n, dtype=np.complex128)
        state.shape = (2, ) * (2 * n)
        buffer = np.zeros(state.shape, dtype=np.complex128)
        qubit_map = {q: i for i, q in enumerate(val.qubits)}
        result = state
        for op in decomposed_val:
            indices = [qubit_map[q] for q in op.qubits]
            result = apply_unitary(unitary_value=op,
                                   args=ApplyUnitaryArgs(
                                       state, buffer, indices),
                                   default=None)
            if result is None:
                return None
            if result is buffer:
                buffer = state
            state = result
        if result is not None:
            return result.reshape((1 << n, 1 << n))
Beispiel #3
0
def has_unitary(val: Any) -> bool:
    """Returns whether the value has a unitary matrix representation.

    Returns:
        If `val` has a _has_unitary_ method and its result is not
        NotImplemented, that result is returned. Otherwise, if `val` is a
        cirq.Operation, a decomposition will be attempted and the resulting
        unitary will be returned if unitaries exist for all operations of the
        decompostion. Otherwise, if the value has a _unitary_ method return if
        that has a non-default value. Returns False if neither function exists.
    """
    from cirq.protocols.decompose import decompose_once
    from cirq import Operation  # HACK: Avoids circular dependencies.
    getter = getattr(val, '_has_unitary_', None)
    result = NotImplemented if getter is None else getter()

    # Fallback to decomposition for operations
    if result is NotImplemented and isinstance(val, Operation):
        decomposed_val = decompose_once(val, None)
        if decomposed_val is not None:
            result = all(has_unitary(v) for v in decomposed_val)

    if result is not NotImplemented:
        return result

    # No _has_unitary_ function, use _unitary_ instead
    return unitary(val, None) is not None
Beispiel #4
0
def _try_decompose_into_operations_and_qubits(
        val: Any
) -> Tuple[Optional[List['cirq.Operation']], Sequence['cirq.Qid']]:
    """Returns the value's decomposition (if any) and the qubits it applies to.
    """
    from cirq.protocols.decompose import (decompose_once,
                                          decompose_once_with_qubits)
    from cirq import LineQubit, Gate, Operation

    if isinstance(val, Gate):
        # Gates don't specify qubits, and so must be handled specially.
        qubits = LineQubit.range(val.num_qubits())
        return decompose_once_with_qubits(val, qubits, None), qubits

    if isinstance(val, Operation):
        return decompose_once(val, None), val.qubits

    result = decompose_once(val, None)
    if result is not None:
        return result, sorted({q for op in result for q in op.qubits})

    return None, ()
Beispiel #5
0
def _decompose_and_get_unitary(
        val: Union['cirq.Operation', 'cirq.Gate']) -> np.ndarray:
    """Try to decompose a cirq.Operation or cirq.Gate, and return its unitary
    if it exists.

    Returns:
        If `val` can be decomposed into unitaries, calculate the resulting
        unitary and return it. If it doesn't exist, None is returned.
    """
    from cirq.protocols.apply_unitary import apply_unitary, ApplyUnitaryArgs
    from cirq.protocols.decompose import (decompose_once,
                                          decompose_once_with_qubits)
    from cirq import Gate, LineQubit, Operation

    if isinstance(val, Operation):
        qubits = val.qubits
        decomposed_val = decompose_once(val, default=None)
    elif isinstance(val, Gate):
        # Since gates don't know about qubits, we need to create some
        qubits = tuple(LineQubit.range(val.num_qubits()))
        decomposed_val = decompose_once_with_qubits(val, qubits, default=None)

    if decomposed_val is not None:
        # Calculate the resulting unitary (if it exists)
        n = len(qubits)
        state = np.eye(1 << n, dtype=np.complex128)
        state.shape = (2, ) * (2 * n)
        buffer = np.zeros(state.shape, dtype=np.complex128)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        result = state
        for op in decomposed_val:
            indices = [qubit_map[q] for q in op.qubits]
            result = apply_unitary(unitary_value=op,
                                   args=ApplyUnitaryArgs(
                                       state, buffer, indices),
                                   default=None)
            if result is None:
                return None
            if result is buffer:
                buffer = state
            state = result
        if result is not None:
            return result.reshape((1 << n, 1 << n))
Beispiel #6
0
def has_unitary(val: Any) -> bool:
    """Returns whether the value has a unitary matrix representation.

    Returns:
        If `val` has a _has_unitary_ method and its result is not
        NotImplemented, that result is returned. Otherwise, if `val` is a
        cirq.Gate or cirq.Operation, a decomposition is attempted and the
        resulting unitary is returned if has_unitary is True for all operations
        of the decompostion. Otherwise, if the value has a _unitary_ method
        return if that has a non-default value. Returns False if neither
        function exists.
    """
    from cirq.protocols.decompose import (decompose_once,
                                          decompose_once_with_qubits)
    # HACK: Avoids circular dependencies.
    from cirq import Gate, Operation, LineQubit

    getter = getattr(val, '_has_unitary_', None)
    result = NotImplemented if getter is None else getter()
    if result is not NotImplemented:
        return result

    # Fallback to explicit _unitary_
    unitary_getter = getattr(val, '_unitary_', None)
    if unitary_getter is not None and unitary_getter() is not NotImplemented:
        return True

    # Fallback to decomposition for gates and operations
    if isinstance(val, Gate):
        # Since gates don't know about qubits, we need to create some
        decomposed_val = decompose_once_with_qubits(val,
                                                    LineQubit.range(
                                                        val.num_qubits()),
                                                    default=None)
        if decomposed_val is not None:
            return all(has_unitary(v) for v in decomposed_val)
    elif isinstance(val, Operation):
        decomposed_val = decompose_once(val, default=None)
        if decomposed_val is not None:
            return all(has_unitary(v) for v in decomposed_val)

    # Finally, fallback to full unitary method, including decomposition
    return unitary(val, None) is not None