code: def matrix_rank(
      x: Union[tf.Tensor, tf.Variable],
      /,
      *,
      atol: Optional[Union[float, Tuple[float]]] = None,
      rtol: Optional[Union[float, Tuple[float]]] = None,
      hermitian: Optional[bool] = False,
      out: Optional[Union[tf.Tensor, tf.Variable]] = None,
  ) -> Union[tf.Tensor, tf.Variable]:
      if (tf.rank(x) < 2) or (0 in x.shape):
          return tf.convert_to_tensor(0, dtype=tf.int64)
      # we don't use the native matrix_rank function because the behaviour of the
      # tolerance argument is difficult to unify,
      # and the native implementation is compositional
      if hermitian:
          svd_values = tf.abs(tf.linalg.eigh(x)[0])
      else:
          svd_values = tf.linalg.svd(x, compute_uv=False)
      sigma = tf.reduce_max(svd_values, axis=-1, keepdims=False)
      atol = (
          atol
          if atol is not None
          else tf.experimental.numpy.finfo(x.dtype).eps
          * max(x.shape[-2:])
          * sigma
      )
      rtol = rtol if rtol is not None else 0.0
      tol = tf.maximum(atol, rtol * sigma)
      # make sure it's broadcastable again with svd_values
      tol = tf.expand_dims(tol, axis=-1)
      ret = tf.math.count_nonzero(svd_values > tol, axis=-1)
      return ret
  
imports: from typing import Union, Optional, Tuple, Literal, List, NamedTuple, Sequence
  from collections import namedtuple
  import tensorflow
  from tensorflow.python.framework.dtypes import DType
  import ivy
  from ivy import inf
  from ivy.func_wrapper import with_unsupported_dtypes, with_supported_dtypes
  from .None import backend_version
label_desc: Use image node_id 13 for calling a global function with example usage: matrix_rank() and returns: ret, tf