code: def _init_step(pos, prev_step, func, psi_1, psi_2, quad_step):
      """Finds initial step size for line seacrh at given point.
  
      Corresponds to I1-I2 in [HZ2006].
  
      Args:
        pos: ValueAndGradient for current point.
        prev_step: Step size at previous iteration.
        func: Callable taking real `Tensor` and returning ValueAndGradient,
          describes scalar function for line search.
        psi_1: Real scalar `Tensor`. Factor to multiply previous step to get right
          point for quadratic interpolation.
        psi_2: Real scalar `Tesnor`. Factor to multiply previous step if qudratic
          interpolation failed.
        quad_step: Boolean. Whether to try quadratic interpolation.
  
      Returns:
        _StepGuessResult namedtuple containing initial guess and additional data.
      """
      phi_0 = pos.f
      derphi_0 = pos.df
      step = func(psi_1 * prev_step)
      can_take = step.f > phi_0
      result = _StepGuessResult(
          step=step,
          func_evals=1,
          can_take=can_take,
          may_terminate=tf.zeros_like(can_take),
      )
  
      # Try to approximate function with a parabola and take its minimum as initial
      # guess.
      if quad_step:
          # Quadratic coefficient of parabola. If it's positive, parabola is convex
          # and has minimum.
          q_koef = step.f - phi_0 - step.x * derphi_0
          quad_step_success = tf.logical_and(
              step.f <= phi_0, q_koef > 0.0
          )
  
          def update_result_1():
              new_x = tf.compat.v1.where(
                  quad_step_success,
                  -0.5
                  * tf.math.divide_no_nan(
                      derphi_0 * step.x**2, q_koef
                  ),
                  result.step.x,
              )
              return _StepGuessResult(
                  step=func(new_x),
                  func_evals=result.func_evals + 1,
                  can_take=tf.math.logical_or(
                      result.can_take, quad_step_success
                  ),
                  may_terminate=tf.math.logical_or(
                      result.may_terminate, quad_step_success
                  ),
              )
  
          result = tf.cond(
              tf.math.reduce_any(quad_step_success),
              update_result_1,
              lambda: result,
          )
  
      def update_result_2():
          new_x = tf.compat.v1.where(
              can_take, result.step.x, psi_2 * prev_step
          )
          return _StepGuessResult(
              step=func(new_x),
              func_evals=result.func_evals + 1,
              can_take=tf.ones_like(can_take),
              may_terminate=result.may_terminate,
          )
  
      # According to [HZ2006] we should fall back to psi_2*prev_step when quadratic
      # interpolation failed. However, [JuliaLineSearches] retains guess
      # psi_1*prev_step if func(psi_1 * prev_step) > func(0), because then local
      # minimum is within (0, psi_1*prev_step).
      result = tf.cond(
          tf.math.reduce_all(result.can_take),
          lambda: result,
          update_result_2,
      )
  
      return result
  
file_path: tf-quant-finance/tf_quant_finance/math/optimizer/conjugate_gradient.py
imports: import collections
  from typing import Callable, Tuple
  import tensorflow.compat.v2
  from tensorflow_probability.python.optimizer import converged_all
  from tensorflow_probability.python.optimizer import linesearch
  from tf_quant_finance import types
  from tf_quant_finance import utils
label_desc: Use image node_id 2 for calling a global function with example usage: _init_step(pos, prev_step, func, psi_1, psi_2, quad_step) and returns: result, _StepGuessResult, _StepGuessResult