<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def unitary(val: Any, default: TDefault = RaiseTypeErrorIfNotProvided ) -> Union[np.ndarray, TDefault]: """Returns a unitary matrix describing the given value. Args: val: The value to describe with a unitary matrix. default: Determines the fallback behavior when `val` doesn't have a unitary matrix. If `default` is not set, a TypeError is raised. If default is set to a value, that value is returned. Returns: If `val` has a _unitary_ method and its result is not NotImplemented, that result is returned. Otherwise, if `val` is a cirq.Gate or cirq.Operation, decomposition will be attempted and the resulting unitary is returned if unitaries exist for all operations of the decompostion. If the result is still NotImplemented and a default value was specified, the default value is returned. Raises: TypeError: `val` doesn't have a _unitary_ method (or that method returned NotImplemented) and also no default value was specified. """

    from cirq import Gate, Operation  # HACK: Avoids circular dependencies.

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

    # Fallback to decomposition for gates and operations
    if isinstance(val, (Gate, Operation)):
        decomposed_unitary = _decompose_and_get_unitary(val)
        if decomposed_unitary is not None:
            return decomposed_unitary

    if default is not RaiseTypeErrorIfNotProvided:
        return default

    if getter is None:
        raise TypeError("object of type '{}' "
                        "has no _unitary_ method.".format(type(val)))
    raise TypeError("object of type '{}' does have a _unitary_ method, "
                    "but it returned NotImplemented.".format(type(val)))