class_docstr: Class that has all functions required in order to apply line search over
  step parameter that used during the network training.
  
  Parameters
  ----------
  wolfe_maxiter : int
      Controls maximum number of iteration during the line search that
      identifies optimal step size during the weight update stage.
      Defaults to ``20``.
  
  wolfe_c1 : float
      Parameter for Armijo condition rule. It's used during the line search
      that identifies optimal step size during the weight update stage.
      Defaults ``1e-4``.
  
  wolfe_c2 : float
      Parameter for curvature condition rule. It's used during the line
      search that identifies optimal step size during the weight update
      stage. Defaults ``0.9``.
class_docstr_tok: ["Class","that","has","all","functions","required","in","order","to","apply","line","search","over","step","parameter","that","used","during","the","network","training",".","Parameters","--","--","--","--","--","wolfe_maxiter",":","int","Controls","maximum","number","of","iteration","during","the","line","search","that","identifies","optimal","step","size","during","the","weight","update","stage",".","Defaults","to","``","20","``",".","wolfe_c1",":","float","Parameter","for","Armijo","condition","rule",".","It","'s","used","during","the","line","search","that","identifies","optimal","step","size","during","the","weight","update","stage",".","Defaults","``","1e-4","``",".","wolfe_c2",":","float","Parameter","for","curvature","condition","rule",".","It","'s","used","during","the","line","search","that","identifies","optimal","step","size","during","the","weight","update","stage",".","Defaults","``","0.9","``","."]
code: def find_optimal_step(self, parameter_vector, parameter_update):
      network_inputs = as_tuple(self.network.inputs)
      layers_and_parameters = list(self.network.variables.items())
  
      def prediction(step):
          step = asfloat(step)
          updated_params = parameter_vector + step * parameter_update
  
          try:
              # This trick allow us to replace shared variables
              # with tensorflow variables and get output from the network
              start_pos = 0
              for (layer, varname), variable in layers_and_parameters:
                  n_param_values = int(variable.shape.num_elements())
                  end_pos = start_pos + n_param_values
  
                  updated_param_value = tf.reshape(
                      updated_params[start_pos:end_pos], variable.shape
                  )
  
                  setattr(layer, varname, updated_param_value)
                  start_pos = end_pos
  
              output = self.network.output(
                  *network_inputs, training=True
              )
  
          finally:
              # Restore previous parameters
              for (layer, varname), param in layers_and_parameters:
                  setattr(layer, varname, param)
  
          return output
  
      def phi(step):
          return self.loss(self.target, prediction(step))
  
      def derphi(step):
          error_func = self.loss(self.target, prediction(step))
          (gradient,) = tf.gradients(error_func, step)
          return gradient
  
      return line_search(
          phi, derphi, self.wolfe_maxiter, self.wolfe_c1, self.wolfe_c2
      )
  
file_path: neupy/neupy/algorithms/gd/quasi_newton.py
imports: import tensorflow
  from neupy.core.config import Configurable
  from neupy.core.properties import ChoiceProperty, NumberProperty, WithdrawProperty, IntProperty
  from neupy.utils.tf_utils import setup_parameter_updates
  from neupy.algorithms.minsearch.wolfe import line_search
  from neupy.utils import asfloat, dot, outer, as_tuple, function_name_scope, make_single_vector
  from .base import BaseOptimizer
label_desc: Use image node_id 1 for calling the WolfeLineSearchForStep obj's underlying member method code with example usage: obj.find_optimal_step(parameter_vector, parameter_update) and returns: line_search, output, self, gradient