Return a sequence of tuples for a channel that is a mixture of unitaries.

    In contrast to `mixture` this method falls back to `unitary` if `_mixture_`
    is not implemented.

    A mixture channel is described by an iterable of tuples of the form

        (probability of unitary, unitary)

    The probability components of the tuples must sum to 1.0 and be between
    0 and 1 (inclusive) and the `unitary` must be a unitary matrix.

    Args:
        val: The value whose mixture_channel is being computed.
        default: A default value if val does not support mixture.

    Returns:
        An iterable of tuples of size 2. The first element of the tuple is a
        probability (between 0 and 1) and the second is the unitary that occurs
        with that probability. The probabilities will sum to 1.0.

def mixture_channel(
    val: Any,
    default: Any = RaiseTypeErrorIfNotProvided) -> Sequence[
    Tuple[float, np.ndarray]]:
    """Return a sequence of tuples for a channel that is a mixture of unitaries.

    In contrast to `mixture` this method falls back to `unitary` if `_mixture_`
    is not implemented.

    A mixture channel is described by an iterable of tuples of the form

        (probability of unitary, unitary)

    The probability components of the tuples must sum to 1.0 and be between
    0 and 1 (inclusive) and the `unitary` must be a unitary matrix.

    Args:
        val: The value whose mixture_channel is being computed.
        default: A default value if val does not support mixture.

    Returns:
        An iterable of tuples of size 2. The first element of the tuple is a
        probability (between 0 and 1) and the second is the unitary that occurs
        with that probability. The probabilities will sum to 1.0.
    """
    mixture_getter = getattr(val, '_mixture_', None)
    result = NotImplemented if mixture_getter is None else mixture_getter()
    if result is not NotImplemented:
        return result

    unitary_getter = getattr(val, '_unitary_', None)
    result = NotImplemented if unitary_getter is None else unitary_getter()
    if result is not NotImplemented:
        return ((1.0, result),)

    if default is not RaiseTypeErrorIfNotProvided:
        return default

    if mixture_getter is None and unitary_getter is None:
        raise TypeError(
            "object of type '{}' has no _mixture_ or _unitary_ method."
                .format(type(val)))

    raise TypeError("object of type '{}' does have a _mixture_ or _unitary_ "
                    "method, but it returned NotImplemented.".format(type(val)))