code: def bisect(
      value_and_gradients_function, initial_left, initial_right, f_lim
  ):
      """Bisects an interval and updates to satisfy opposite slope conditions.
  
      Corresponds to the step U3 in [Hager and Zhang (2006)][2].
  
      Tolerates non-finite candidate right end-points.  Specifically:
      - If f(x) = -inf, that's a minimum, so we should just jump both end-points
        there and report success.
      - If f(x) = nan, fail (that is, stop trying to bisect and report failure).
      - If f(x) = +inf, that's fine, but just not an acceptable right
        end-point, so keep bisecting.
  
      In all of these cases, takes care to ignore the derivative, because (a) it
      doesn't inflence the outcome, and (b) if the value is infinite, the derivative
      should be `nan` (whether the client code arranged for that to be so or not).
  
      Args:
        value_and_gradients_function: A Python callable that accepts a real scalar
          tensor and returns a namedtuple containing the value filed `f` of the
          function and its derivative value field `df` at that point.
          Alternatively, the function may representthe batching of `n` such line
          functions (e.g. projecting a single multivariate objective function along
          `n` distinct directions at once) accepting n points as input, i.e. a
          tensor of shape [n], and return a tuple of two tensors of shape [n], the
          function values and the corresponding derivatives at the input points.
        initial_left: Return value of value_and_gradients_function at the left end
          point of the current bracketing interval.
        initial_right: Return value of value_and_gradients_function at the right end
          point of the current bracketing interval.
        f_lim: real `Tensor` of shape [n]. The function value threshold for
          the approximate Wolfe conditions to be checked for each batch member.
  
      Returns:
        A namedtuple containing the following fields:
          iteration: An int32 scalar `Tensor`. The number of iterations performed.
            Bounded above by `max_iterations` parameter.
          stopped: A boolean scalar `Tensor`. True if the bisect algorithm
            terminated.
          failed: A scalar boolean tensor. Indicates whether the objective function
            failed to produce a finite value.
          num_evals: A scalar int32 tensor. The number of value and gradients
            function evaluations.
          left: Return value of value_and_gradients_function at the left end
            point of the bracketing interval found.
          right: Return value of value_and_gradients_function at the right end
            point of the bracketing interval found.
      """
      failed = ~is_finite(initial_left) | tf.math.is_nan(
          initial_right.f
      )
      finished = _is_negative_inf(initial_right.f)
      bisect_args = _IntermediateResult(
          iteration=tf.convert_to_tensor(0),
          stopped=failed
          | finished
          | ~_needs_bisect(initial_right, f_lim),
          failed=failed,
          num_evals=tf.convert_to_tensor(0),
          left=val_where(finished, initial_right, initial_left),
          right=initial_right,
      )
      return _bisect(value_and_gradients_function, bisect_args, f_lim)
  
file_path: probability/tensorflow_probability/python/optimizer/linesearch/internal/hager_zhang_lib.py
imports: import collections
  import tensorflow.compat.v2
  from tensorflow_probability.python.internal import broadcast_util
  from tensorflow_probability.python.internal import prefer_static
label_desc: Use image node_id 7 for calling a global function with example usage: bisect(value_and_gradients_function, initial_left, initial_right, f_lim) and returns: _bisect