code: def line_search(
      f,
      myfprime,
      xk,
      pk,
      gfk,
      old_fval,
      old_old_fval,
      args=(),
      c1=1e-4,
      c2=0.9,
      amax=50,
      self=None,
  ):
      """Find alpha that satisfies strong Wolfe conditions.
  
      :Parameters:
  
          f : callable f(x,*args)
              Objective function.
          myfprime : callable f'(x,*args)
              Objective function gradient (can be None).
          xk : ndarray
              Starting point.
          pk : ndarray
              Search direction.
          gfk : ndarray
              Gradient value for x=xk (xk being the current parameter
              estimate).
          args : tuple
              Additional arguments passed to objective function.
          c1 : float
              Parameter for Armijo condition rule.
          c2 : float
              Parameter for curvature condition rule.
  
      :Returns:
  
          alpha0 : float
              Alpha for which ``x_new = x0 + alpha * pk``.
          fc : int
              Number of function evaluations made.
          gc : int
              Number of gradient evaluations made.
  
      :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 [...].
  
      """
  
      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 = min(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 (
              self._EARLYEXIT
          ):  # In case it gets stuck in this loop, 'exit' will work
              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: from mystic._scipy060optimize import *
  from mystic._scipy060optimize import _cubicmin, _quadmin, _epsilon
  from mystic._scipy060optimize import _linesearch_powell, _endprint
label_desc: Use image node_id 1 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