docs: 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)))