code: def gradient(
      x: tf.Tensor,
      /,
      *,
      spacing: Union[int, list, tuple] = 1,
      axis: Optional[Union[int, list, tuple]] = None,
      edge_order: int = 1,
  ) -> Union[tf.Tensor, List[tf.Tensor]]:
      # https://github.com/numpy/numpy/blob/v1.24.3/numpy/lib/function_base.py#L969-L1312
      x = tf.experimental.numpy.asanyarray(x)
      N = x.ndim  # number of dimensions
      if axis is None:
          axes = tuple(range(N))
      else:
          axes = _normalize_axis_tuple(axis, N)
  
      len_axes = len(axes)
      n = (
          -1
          if spacing is None
          else (0 if type(spacing) in (int, float) else len(spacing))
      )
      if n == -1:
          # no spacing argument - use 1 in all axes
          dx = [1.0] * len_axes
      elif n == 0:
          dx = [spacing] * len_axes
      elif n == 1 and tf.experimental.numpy.ndim(spacing[0]) == 0:
          # single scalar for all axes
          dx = spacing * len_axes
      elif n == len_axes:
          # scalar or 1d array for each axis
          dx = list(spacing)
          for i, distances in enumerate(dx):
              distances = tf.experimental.numpy.asanyarray(distances)
              if distances.ndim == 0:
                  continue
              elif distances.ndim != 1:
                  raise ValueError(
                      "distances must be either scalars or 1d"
                  )
              if len(distances) != x.shape[axes[i]]:
                  raise ValueError(
                      "when 1d, distances must match the length of the corresponding"
                      f" dimension {len(distances)} {x.shape[axes[i]]}"
                  )
              if distances.dtype.is_integer:
                  # Convert numpy integer types to float64 to avoid modular
                  # arithmetic in np.diff(distances).
                  distances = tf.cast(distances, tf.float64)
              diffx = tf.experimental.numpy.diff(distances)
              # if distances are constant reduce to the scalar case
              # since it brings a consistent speedup
              # cmp = diffx == diffx[0]
              if tf.reduce_all(tf.equal(diffx, diffx[0])):
                  diffx = diffx[0]
              # if tf.reduce_sum(tf.cast(cmp, tf.int32)) == cmp.numel():
              #     print(diffx, (diffx == diffx[0]))
              #     diffx = diffx[0]
              dx[i] = diffx
      else:
          raise TypeError("invalid number of arguments")
  
      if edge_order > 2:
          raise ValueError("'edge_order' greater than 2 not supported")
  
      # use central differences on interior and one-sided differences on the
      # endpoints. This preserves second order-accuracy over the full domain.
  
      outvals = []
  
      # create slice objects --- initially all are [:, :, ..., :]
      slice1 = [slice(None)] * N
      slice2 = [slice(None)] * N
      slice3 = [slice(None)] * N
      slice4 = [slice(None)] * N
  
      if x.dtype.is_integer:
          x = tf.cast(x, tf.float64)
  
      for axis, ax_dx in zip(axes, dx):
          if x.shape[axis] < edge_order + 1:
              raise ValueError(
                  "Shape of array too small to calculate a numerical gradient, "
                  "at least (edge_order + 1) elements are required."
              )
          # result allocation
          out = x.numpy()
  
          # spacing for the current axis
          uniform_spacing = tf.experimental.numpy.ndim(ax_dx) == 0
  
          # Numerical differentiation: 2nd order interior
          slice1[axis] = slice(1, -1)
          slice2[axis] = slice(None, -2)
          slice3[axis] = slice(1, -1)
          slice4[axis] = slice(2, None)
  
          if uniform_spacing:
              out[tuple(slice1)] = (
                  x[tuple(slice4)] - x[tuple(slice2)]
              ) / (2.0 * ax_dx)
          else:
              dx1 = ax_dx[0:-1]
              dx2 = ax_dx[1:]
              a = -(dx2) / (dx1 * (dx1 + dx2))
              b = (dx2 - dx1) / (dx1 * dx2)
              c = dx1 / (dx2 * (dx1 + dx2))
  
              out[tuple(slice1)] = (
                  a * x[tuple(slice2)]
                  + b * x[tuple(slice3)]
                  + c * x[tuple(slice4)]
              )
  
          # Numerical differentiation: 1st order edges
          if edge_order == 1:
              slice1[axis] = 0
              slice2[axis] = 1
              slice3[axis] = 0
              dx_0 = ax_dx if uniform_spacing else ax_dx[0]
              # 1D equivalent -- out[0] = (f[1] - f[0]) / (x[1] - x[0])
              out[tuple(slice1)] = (
                  x[tuple(slice2)] - x[tuple(slice3)]
              ) / dx_0
  
              slice1[axis] = -1
              slice2[axis] = -1
              slice3[axis] = -2
              dx_n = ax_dx if uniform_spacing else ax_dx[-1]
              # 1D equivalent -- out[-1] = (f[-1] - f[-2]) / (x[-1] - x[-2])
              out[tuple(slice1)] = (
                  x[tuple(slice2)] - x[tuple(slice3)]
              ) / dx_n
  
          # Numerical differentiation: 2nd order edges
          else:
              slice1[axis] = 0
              slice2[axis] = 0
              slice3[axis] = 1
              slice4[axis] = 2
              if uniform_spacing:
                  a = -1.5 / ax_dx
                  b = 2.0 / ax_dx
                  c = -0.5 / ax_dx
              else:
                  dx1 = ax_dx[0]
                  dx2 = ax_dx[1]
                  a = -(2.0 * dx1 + dx2) / (dx1 * (dx1 + dx2))
                  b = (dx1 + dx2) / (dx1 * dx2)
                  c = -dx1 / (dx2 * (dx1 + dx2))
              # 1D equivalent -- out[0] = a * f[0] + b * f[1] + c * f[2]
              out[tuple(slice1)] = (
                  a * x[tuple(slice2)]
                  + b * x[tuple(slice3)]
                  + c * x[tuple(slice4)]
              )
  
              slice1[axis] = -1
              slice2[axis] = -3
              slice3[axis] = -2
              slice4[axis] = -1
              if uniform_spacing:
                  a = 0.5 / ax_dx
                  b = -2.0 / ax_dx
                  c = 1.5 / ax_dx
              else:
                  dx1 = ax_dx[-2]
                  dx2 = ax_dx[-1]
                  a = (dx2) / (dx1 * (dx1 + dx2))
                  b = -(dx2 + dx1) / (dx1 * dx2)
                  c = (2.0 * dx2 + dx1) / (dx2 * (dx1 + dx2))
              # 1D equivalent -- out[-1] = a * f[-3] + b * f[-2] + c * f[-1]
              out[tuple(slice1)] = (
                  a * x[tuple(slice2)]
                  + b * x[tuple(slice3)]
                  + c * x[tuple(slice4)]
              )
  
          outvals.append(tf.convert_to_tensor(out))
  
          # reset the slice object in this dimension to ":"
          slice1[axis] = slice(None)
          slice2[axis] = slice(None)
          slice3[axis] = slice(None)
          slice4[axis] = slice(None)
  
      if len_axes == 1:
          return outvals[0]
      else:
          return outvals
  
imports: import operator
  from typing import Union, Optional, Tuple, List, Sequence
  from numbers import Number
  import tensorflow
  from tensorflow.python.ops.numpy_ops import np_math_ops
  import ivy
  from ivy import promote_types_of_inputs
  from ivy.func_wrapper import with_unsupported_dtypes, with_supported_dtypes
  from ..None import backend_version
label_desc: Use image node_id 20 for calling a global function with example usage: gradient() and returns: outvals, outvals