Ejemplo n.º 1
0
def _strat_unitary_from_apply_unitary(val: Any) -> Optional[np.ndarray]:
    """Attempts to compute a value's unitary via its _apply_unitary_ method."""
    from cirq.protocols.apply_unitary import ApplyUnitaryArgs
    from cirq import ops

    # Check for the magic method.
    method = getattr(val, '_apply_unitary_', None)
    if method is None:
        return NotImplemented

    # Infer number of qubits.
    if isinstance(val, ops.Gate):
        n = val.num_qubits()
    elif isinstance(val, ops.Operation):
        n = len(val.qubits)
    else:
        return NotImplemented

    # Apply unitary effect to an identity matrix.
    state = np.eye(1 << n, dtype=np.complex128)
    state.shape = (2,) * (2 * n)
    buffer = np.empty_like(state)
    result = method(ApplyUnitaryArgs(state, buffer, range(n)))

    if result is NotImplemented or result is None:
        return result
    return result.reshape((1 << n, 1 << n))
Ejemplo n.º 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))
Ejemplo n.º 3
0
def _apply_unitary(val: Any, args: 'ApplyChannelArgs') -> Optional[np.ndarray]:
    """Attempt to use `apply_unitary` and return the result.

    If `val` does not support `apply_unitary` returns None.
    """
    left_args = ApplyUnitaryArgs(target_tensor=args.target_tensor,
                                 available_buffer=args.auxiliary_buffer0,
                                 axes=args.left_axes)
    left_result = apply_unitary(val, left_args, None)
    if left_result is None:
        return None
    right_args = ApplyUnitaryArgs(target_tensor=np.conjugate(left_result),
                                  available_buffer=args.out_buffer,
                                  axes=args.right_axes)
    right_result = apply_unitary(val, right_args)
    np.conjugate(right_result, out=right_result)
    return right_result
Ejemplo n.º 4
0
def _strat_has_unitary_from_apply_unitary(val: Any) -> Optional[bool]:
    """Attempts to infer a value's unitary-ness via its _apply_unitary_ method.
    """
    method = getattr(val, '_apply_unitary_', None)
    if method is None:
        return None

    val_qid_shape = qid_shape_protocol.qid_shape(val, None)
    if val_qid_shape is None:
        return None
    state = linalg.one_hot(shape=val_qid_shape, dtype=np.complex64)
    buffer = np.empty_like(state)
    result = method(ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape))))
    if result is NotImplemented:
        return None
    return result is not None
Ejemplo n.º 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))
Ejemplo n.º 6
0
def _strat_unitary_from_decompose(val: Any) -> Optional[np.ndarray]:
    """Attempts to compute a value's unitary via its _decompose_ method."""
    # Check if there's a decomposition.
    operations, qubits, val_qid_shape = (
        _try_decompose_into_operations_and_qubits(val))
    if operations is None:
        return NotImplemented

    # Apply sub-operations' unitary effects to an identity matrix.
    state = linalg.eye_tensor(val_qid_shape, dtype=np.complex128)
    buffer = np.empty_like(state)
    result = apply_unitaries(
        operations, qubits,
        ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape))), None)

    # Package result.
    if result is None:
        return None
    state_len = np.prod(val_qid_shape, dtype=int)
    return result.reshape((state_len, state_len))
Ejemplo n.º 7
0
def _strat_has_unitary_from_apply_unitary(val: Any) -> Optional[bool]:
    """Attempts to infer a value's unitary-ness via its _apply_unitary_ method.
    """
    from cirq.protocols.apply_unitary import ApplyUnitaryArgs
    from cirq import devices, linalg, ops

    method = getattr(val, '_apply_unitary_', None)
    if method is None:
        return None
    if isinstance(val, ops.Gate):
        val = val.on(*devices.LineQubit.range(val.num_qubits()))
    if not isinstance(val, ops.Operation):
        return None

    val_qid_shape = qid_shape_protocol.qid_shape(val)
    state = linalg.one_hot(shape=val_qid_shape, dtype=np.complex64)
    buffer = np.empty_like(state)
    result = method(ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape))))
    if result is NotImplemented:
        return None
    return result is not None
Ejemplo n.º 8
0
def _strat_unitary_from_apply_unitary(val: Any) -> Optional[np.ndarray]:
    """Attempts to compute a value's unitary via its _apply_unitary_ method."""
    # Check for the magic method.
    method = getattr(val, '_apply_unitary_', None)
    if method is None:
        return NotImplemented

    # Get the qid_shape.
    val_qid_shape = qid_shape_protocol.qid_shape(val, None)
    if val_qid_shape is None:
        return NotImplemented

    # Apply unitary effect to an identity matrix.
    state = linalg.eye_tensor(val_qid_shape, dtype=np.complex128)
    buffer = np.empty_like(state)
    result = method(ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape))))

    if result is NotImplemented or result is None:
        return result
    state_len = np.prod(val_qid_shape, dtype=int)
    return result.reshape((state_len, state_len))
Ejemplo n.º 9
0
def _strat_unitary_from_decompose(val: Any) -> Optional[np.ndarray]:
    """Attempts to compute a value's unitary via its _decompose_ method."""
    from cirq.protocols.apply_unitary import ApplyUnitaryArgs, apply_unitaries

    # Check if there's a decomposition.
    from cirq.protocols.has_unitary import (
        _try_decompose_into_operations_and_qubits)
    operations, qubits = _try_decompose_into_operations_and_qubits(val)
    if operations is None:
        return NotImplemented

    # Apply sub-operations' unitary effects to an identity matrix.
    n = len(qubits)
    state = np.eye(1 << n, dtype=np.complex128)
    state.shape = (2,) * (2 * n)
    buffer = np.empty_like(state)
    result = apply_unitaries(operations, qubits,
                             ApplyUnitaryArgs(state, buffer, range(n)), None)

    # Package result.
    if result is None:
        return None
    return result.reshape((1 << n, 1 << n))