code: def _bisect(value_and_gradients_function, initial_args, f_lim):
      """Actual implementation of bisect given initial_args in a _BracketResult."""
  
      def _loop_cond(curr):
          # TODO(b/112524024): Also take into account max_iterations.
          return ~tf.reduce_all(curr.stopped)
  
      def _loop_body(curr):
          """Narrow down interval to satisfy opposite slope conditions."""
          mid = value_and_gradients_function(
              (curr.left.x + curr.right.x) / 2
          )
  
          # If the mid point has a value of -inf, we have found a minimum; jump
          # both ends of the interval there and exit.
          finished = _is_negative_inf(mid.f)
  
          # Otherwise, fail if the midpoint has a `nan` value or derivative, or if the
          # left/right points are so close to it that we can't distinguish them any
          # more.
          failed = curr.failed | (
              ~finished
              & ~curr.stopped
              & (
                  _bad_nan(mid)
                  | tf.equal(mid.x, curr.left.x)
                  | tf.equal(mid.x, curr.right.x)
              )
          )
  
          # We will update only non-stopped and non-failed batch members.
          to_update = ~(curr.stopped | failed)
  
          # If the mid point has a negative slope and the function value at that point
          # is small enough, we can use it as a new left end point to narrow down the
          # interval.  Otherwise it becomes the new right end-point.
          update_left = (mid.df < 0) & (mid.f <= f_lim)
          left = val_where(
              to_update & (update_left | finished), mid, curr.left
          )
          right = val_where(
              to_update & (~update_left | finished), mid, curr.right
          )
          # If mid point has a finite value and a positive slope, then we have found a
          # suitable right end point to bracket a minimum within opposite slopes.
          # Otherwise, the mid point has a negative slope but the function value at
          # that point is too high to work as left end point (including +inf as a
          # possibility), so we are in the same situation in which we started the
          # loop.  We just update the right end point and continue.
          stopped = curr.stopped | failed | finished | _is_rising(right)
  
          return [
              _IntermediateResult(
                  iteration=curr.iteration,
                  stopped=stopped,
                  failed=failed,
                  num_evals=curr.num_evals + 1,
                  left=left,
                  right=right,
              )
          ]
  
      # The interval needs updating if the right end point has a negative slope and
      # the value of the function at that point is too high. It is not a valid left
      # end point but along with the current left end point, it encloses another
      # minimum. The loop above tries to narrow the interval so that it satisfies
      # the opposite slope conditions.
      return tf.while_loop(
          cond=_loop_cond, body=_loop_body, loop_vars=[initial_args]
      )[0]
  
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 8 for calling a global function with example usage: _bisect(value_and_gradients_function, initial_args, f_lim) and returns: tf, unknown, list