code: def line_search(
      f,
      myfprime,
      xk,
      pk,
      gfk,
      old_fval,
      old_old_fval,
      args=(),
      c1=1e-4,
      c2=0.9,
      amax=50,
  ):
      """Find alpha that satisfies strong Wolfe conditions.
  
      :Parameters:
  
      f : objective function
      myfprime : objective function gradient (can be None)
      xk : ndarray -- start point
      pk : ndarray -- search direction
      gfk : ndarray -- gradient value for x=xk
      args : additional arguments for user functions
      c1 : number -- parameter for Armijo condition rule
      c2 : number - parameter for curvature condition rule
  
      :Returns:
  
      alpha0 : number -- required alpha (x_new = x0 + alpha * pk)
      fc : number of function evaluations
      gc : number of gradient evaluations
  
  
      Notes
  
      --------------------------------
  
      Uses the line search algorithm to enforce strong Wolfe conditions
      Wright and Nocedal, 'Numerical Optimization', 1999, pg. 59-60
  
      For the zoom phase it uses an algorithm by
  
      """
  
      global _ls_fc, _ls_gc, _ls_ingfk
      _ls_fc = 0
      _ls_gc = 0
      _ls_ingfk = None
  
      def phi(alpha):
          global _ls_fc
          _ls_fc += 1
          return f(xk + alpha * pk, *args)
  
      if isinstance(myfprime, type(())):
  
          def phiprime(alpha):
              global _ls_fc, _ls_ingfk
              _ls_fc += len(xk) + 1
              eps = myfprime[1]
              fprime = myfprime[0]
              newargs = (f, eps) + args
              _ls_ingfk = fprime(
                  xk + alpha * pk, *newargs
              )  # store for later use
              return numpy.dot(_ls_ingfk, pk)
  
      else:
          fprime = myfprime
  
          def phiprime(alpha):
              global _ls_gc, _ls_ingfk
              _ls_gc += 1
              _ls_ingfk = fprime(
                  xk + alpha * pk, *args
              )  # store for later use
              return numpy.dot(_ls_ingfk, pk)
  
      alpha0 = 0
      phi0 = old_fval
      derphi0 = numpy.dot(gfk, pk)
  
      alpha1 = pymin(1.0, 1.01 * 2 * (phi0 - old_old_fval) / derphi0)
  
      if alpha1 == 0:
          # This shouldn't happen. Perhaps the increment has slipped below
          # machine precision?  For now, set the return variables skip the
          # useless while loop, and raise warnflag=2 due to possible imprecision.
          alpha_star = None
          fval_star = old_fval
          old_fval = old_old_fval
          fprime_star = None
  
      phi_a1 = phi(alpha1)
      # derphi_a1 = phiprime(alpha1)  evaluated below
  
      phi_a0 = phi0
      derphi_a0 = derphi0
  
      i = 1
      maxiter = 10
      while 1:  # bracketing phase
          if alpha1 == 0:
              break
          if (phi_a1 > phi0 + c1 * alpha1 * derphi0) or (
              (phi_a1 >= phi_a0) and (i > 1)
          ):
              alpha_star, fval_star, fprime_star = zoom(
                  alpha0,
                  alpha1,
                  phi_a0,
                  phi_a1,
                  derphi_a0,
                  phi,
                  phiprime,
                  phi0,
                  derphi0,
                  c1,
                  c2,
              )
              break
  
          derphi_a1 = phiprime(alpha1)
          if abs(derphi_a1) <= -c2 * derphi0:
              alpha_star = alpha1
              fval_star = phi_a1
              fprime_star = derphi_a1
              break
  
          if derphi_a1 >= 0:
              alpha_star, fval_star, fprime_star = zoom(
                  alpha1,
                  alpha0,
                  phi_a1,
                  phi_a0,
                  derphi_a1,
                  phi,
                  phiprime,
                  phi0,
                  derphi0,
                  c1,
                  c2,
              )
              break
  
          alpha2 = (
              2 * alpha1
          )  # increase by factor of two on each iteration
          i = i + 1
          alpha0 = alpha1
          alpha1 = alpha2
          phi_a0 = phi_a1
          phi_a1 = phi(alpha1)
          derphi_a0 = derphi_a1
  
          # stopping test if lower function not found
          if i > maxiter:
              alpha_star = alpha1
              fval_star = phi_a1
              fprime_star = None
              break
  
      if fprime_star is not None:
          # fprime_star is a number (derphi) -- so use the most recently calculated gradient
          #                                     used in computing it derphi = gfk*pk
          #                                     this is the gradient at the next step
          #                                     no need to compute it again in the outer loop.
          fprime_star = _ls_ingfk
  
      return (
          alpha_star,
          _ls_fc,
          _ls_gc,
          fval_star,
          old_fval,
          fprime_star,
      )
  
imports: import numpy
  from numpy import atleast_1d, eye, mgrid, argmin, zeros, shape, empty, squeeze, isscalar, vectorize, asarray, absolute, sqrt, Inf, asfarray, isinf
  from mystic import linesearch
  from collections.abc import Callable
  import builtins
label_desc: Use image node_id 13 for calling a global function with example usage: line_search(f, myfprime, xk, pk, gfk, old_fval, old_old_fval, args, c1, c2, amax) and returns: alpha_star,  _ls_fc,  _ls_gc,  fval_star,  old_fval,  fprime_star, f, numpy, numpy