code: def line_search(f, f_deriv, maxiter=20, c1=1e-4, c2=0.9):
      """
      Find ``x`` that satisfies strong Wolfe conditions.
      ``x > 0`` is assumed to be a descent direction.
  
      Parameters
      ----------
      f : callable f(x)
          Objective scalar function.
  
      f_deriv : callable f'(x)
          Objective function derivative.
  
      maxiter : int
          Maximum number of iterations. Defaults ``20``.
  
      c1 : float
          Parameter for Armijo condition rule. Defaults ``1e-4``.
  
      c2 : float
          Parameter for curvature condition rule. Defaults ``0.9``.
  
      Returns
      -------
      Variable
          Value ``x`` that satisfies strong Wolfe conditions and
          minimize function ``f``.
  
      Notes
      -----
      Uses the line search algorithm to enforce strong Wolfe
      conditions.  See Wright and Nocedal, 'Numerical Optimization',
      1999, pg. 59-60.
      For the zoom phase it uses an algorithm by [...].
      """
      if not 0 < c1 < 1:
          raise ValueError("c1 should be a float between 0 and 1")
  
      if not 0 < c2 < 1:
          raise ValueError("c2 should be a float between 0 and 1")
  
      if c2 < c1:
          raise ValueError("c2 needs to be greater than c1")
  
      if maxiter <= 0:
          raise ValueError("maxiter needs to be greater than 0")
  
      c1, c2 = asfloat(c1), asfloat(c2)
  
      def search_iteration_step(
          condition,
          x_previous,
          x_current,
          y_previous,
          y_current,
          y_deriv_previous,
          iteration,
          x_star,
      ):
          y_deriv_current = f_deriv(x_current)
          x_new = x_current * asfloat(2)
          y_new = f(x_new)
  
          condition1 = tf.logical_or(
              y_current > (y0 + c1 * x_current * y_deriv_0),
              tf.logical_and(
                  y_current >= y_previous,
                  tf.not_equal(iteration, 1),
              ),
          )
          condition2 = tf.abs(y_deriv_current) <= -c2 * y_deriv_0
          condition3 = y_deriv_current >= 0
  
          x_star = tf.where(
              condition1,
              zoom(
                  x_previous,
                  x_current,
                  y_previous,
                  y_current,
                  y_deriv_previous,
                  f,
                  f_deriv,
                  y0,
                  y_deriv_0,
                  c1,
                  c2,
              ),
              tf.where(
                  condition2,
                  x_current,
                  tf.where(
                      condition3,
                      zoom(
                          x_current,
                          x_previous,
                          y_current,
                          y_previous,
                          y_deriv_current,
                          f,
                          f_deriv,
                          y0,
                          y_deriv_0,
                          c1,
                          c2,
                      ),
                      x_new,
                  ),
              ),
          )
          y_deriv_previous_new = tf.where(
              condition1, y_deriv_previous, y_deriv_current
          )
  
          is_any_condition_satisfied = sequential_or(
              condition1, condition2, condition3
          )
  
          y_current_new = tf.where(
              is_any_condition_satisfied, y_current, y_new
          )
          continue_searching_condition = tf.logical_and(
              tf.not_equal(x_new, 0),
              tf.logical_not(is_any_condition_satisfied),
          )
  
          return [
              continue_searching_condition,
              x_current,
              x_new,
              y_current,
              y_current_new,
              y_deriv_previous_new,
              iteration + 1,
              x_star,
          ]
  
      one = tf.constant(asfloat(1))
      zero = tf.constant(asfloat(0))
  
      x0, x1 = zero, one
      y0, y1 = f(x0), f(x1)
      y_deriv_0 = f_deriv(x0)
  
      outs = tf.while_loop(
          cond=lambda condition, *args: condition,
          body=search_iteration_step,
          loop_vars=[True, x0, x1, y0, y1, y_deriv_0, 1, zero],
          back_prop=False,
          maximum_iterations=maxiter,
      )
      return outs[-1]
  
file_path: neupy/neupy/algorithms/minsearch/wolfe.py
imports: import tensorflow
  from neupy.utils import asfloat
label_desc: Use image node_id 3 for calling a global function with example usage: line_search(f, f_deriv, maxiter, c1, c2) and returns: outs, list