code: def gradient_descent(
      start, loss, grad, manifold, lr=0.01, max_iter=256, precision=1e-5
  ):
      """Operate a gradient descent on a given manifold.
  
      Until either max_iter or a given precision is reached.
      """
      x = start
      for i in range(max_iter):
          x_prev = x
          euclidean_grad = -lr * grad(x)
          tangent_vec = manifold.to_tangent(
              vector=euclidean_grad, base_point=x
          )
          x = manifold.metric.exp(base_point=x, tangent_vec=tangent_vec)
          if (
              gs.abs(loss(x, use_gs=True) - loss(x_prev, use_gs=True))
              <= precision
          ):
              logging.info("x: %s", x)
              logging.info("reached precision %s", precision)
              logging.info("iterations: %d", i)
              break
          yield x, loss(x)
  
file_path: geomstats/examples/gradient_descent_s2.py
imports: import logging
  import matplotlib
  import matplotlib.animation
  import matplotlib.pyplot
  import numpy
  import geomstats.backend
  import geomstats.visualization
  from geomstats.geometry.hypersphere import Hypersphere
  from geomstats.geometry.spd_matrices import SPDMatrices
label_desc: Use image node_id 1 for calling a global function with example usage: gradient_descent(start, loss, grad, manifold, lr, max_iter, precision) without return types