code: def swap_curve_fit(
      float_leg_start_times: List[types.RealTensor],
      float_leg_end_times: List[types.RealTensor],
      float_leg_daycount_fractions: List[types.RealTensor],
      fixed_leg_start_times: List[types.RealTensor],
      fixed_leg_end_times: List[types.RealTensor],
      fixed_leg_daycount_fractions: List[types.RealTensor],
      fixed_leg_cashflows: List[types.RealTensor],
      present_values: List[types.RealTensor],
      initial_curve_rates: types.RealTensor,
      present_values_settlement_times: List[types.RealTensor] = None,
      float_leg_discount_rates: List[types.RealTensor] = None,
      float_leg_discount_times: List[types.RealTensor] = None,
      fixed_leg_discount_rates: List[types.RealTensor] = None,
      fixed_leg_discount_times: List[types.RealTensor] = None,
      optimizer: Callable[..., Any] = None,
      curve_interpolator: Callable[..., types.RealTensor] = None,
      instrument_weights: types.RealTensor = None,
      curve_tolerance: types.RealTensor = 1e-8,
      maximum_iterations: types.IntTensor = 50,
      dtype: tf.DType = None,
      name: str = None,
  ) -> scc.SwapCurveBuilderResult:
      """Constructs the zero swap curve using optimization.
  
      A zero swap curve is a function of time which gives the interest rate that
      can be used to project forward rates at arbitrary `t` for the valuation of
      interest rate securities.
  
      Suppose we have a set of `N` Interest Rate Swaps (IRS) `S_i` with increasing
      expiries whose market prices are known.
      Suppose also that the `i`th IRS issues cashflows at times `T_{ij}` where
      `1 <= j <= n_i` and `n_i` is the number of cashflows (including expiry)
      for the `i`th swap.
      Denote by `T_i` the time of final payment for the `i`th swap
      (hence `T_i = T_{i,n_i}`). This function estimates a set of rates `r(T_i)`
      such that when these rates are interpolated to all other cashflow times,
      the computed value of the swaps matches the market value of the swaps
      (within some tolerance). Rates at intermediate times are interpolated using
      the user specified interpolation method (the default interpolation method
      is linear interpolation on rates).
  
      #### Example:
  
      The following example illustrates the usage by building an implied swap curve
      from four vanilla (fixed to float) LIBOR swaps.
  
      ```python
  
      dtype = np.float64
  
      # Next we will set up LIBOR reset and payment times for four spot starting
      # swaps with maturities 1Y, 2Y, 3Y, 4Y. The LIBOR rate spans 6M.
  
      float_leg_start_times = [
                np.array([0., 0.5], dtype=dtype),
                np.array([0., 0.5, 1., 1.5], dtype=dtype),
                np.array([0., 0.5, 1.0, 1.5, 2.0, 2.5], dtype=dtype),
                np.array([0., 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5], dtype=dtype)
            ]
  
      float_leg_end_times = [
                np.array([0.5, 1.0], dtype=dtype),
                np.array([0.5, 1., 1.5, 2.0], dtype=dtype),
                np.array([0.5, 1.0, 1.5, 2.0, 2.5, 3.0], dtype=dtype),
                np.array([0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0], dtype=dtype)
            ]
  
      # Next we will set up start and end times for semi-annual fixed coupons.
  
      fixed_leg_start_times = [
                np.array([0., 0.5], dtype=dtype),
                np.array([0., 0.5, 1., 1.5], dtype=dtype),
                np.array([0., 0.5, 1.0, 1.5, 2.0, 2.5], dtype=dtype),
                np.array([0., 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5], dtype=dtype)
            ]
  
      fixed_leg_end_times = [
                np.array([0.5, 1.0], dtype=dtype),
                np.array([0.5, 1., 1.5, 2.0], dtype=dtype),
                np.array([0.5, 1.0, 1.5, 2.0, 2.5, 3.0], dtype=dtype),
                np.array([0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0], dtype=dtype)
            ]
  
      # Next setup a trivial daycount for floating and fixed legs.
  
      float_leg_daycount = [
                np.array([0.5, 0.5], dtype=dtype),
                np.array([0.5, 0.5, 0.5, 0.5], dtype=dtype),
                np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5], dtype=dtype),
                np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5], dtype=dtype)
            ]
  
      fixed_leg_daycount = [
                np.array([0.5, 0.5], dtype=dtype),
                np.array([0.5, 0.5, 0.5, 0.5], dtype=dtype),
                np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5], dtype=dtype),
                np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5], dtype=dtype)
            ]
  
      fixed_leg_cashflows = [
            # 1 year swap with 2.855% semi-annual fixed payments.
            np.array([-0.02855, -0.02855], dtype=dtype),
            # 2 year swap with 3.097% semi-annual fixed payments.
            np.array([-0.03097, -0.03097, -0.03097, -0.03097], dtype=dtype),
            # 3 year swap with 3.1% semi-annual fixed payments.
            np.array([-0.031, -0.031, -0.031, -0.031, -0.031, -0.031], dtype=dtype),
            # 4 year swap with 3.2% semi-annual fixed payments.
            np.array([-0.032, -0.032, -0.032, -0.032, -0.032, -0.032, -0.032,
            -0.032], dtype=dtype)
        ]
  
      # The present values of the above IRS.
      pvs = np.array([0., 0., 0., 0.], dtype=dtype)
  
      # Initial state of the curve.
      initial_curve_rates = np.array([0.01, 0.01, 0.01, 0.01], dtype=dtype)
  
      results = swap_curve_fit(float_leg_start_times, float_leg_end_times,
                               float_leg_daycount, fixed_leg_start_times,
                               fixed_leg_end_times, fixed_leg_cashflows,
                               fixed_leg_daycount, pvs, dtype=dtype,
                               initial_curve_rates=initial_curve_rates)
  
      #### References:
      [1]: Leif B.G. Andersen and Vladimir V. Piterbarg. Interest Rate Modeling,
          Volume I: Foundations and Vanilla Models. Chapter 6. 2010.
  
      Args:
        float_leg_start_times: List of `Tensor`s. Each `Tensor` must be either of
          shape `batch_shape  + [k_i]` or `[k_i]` and of the same real dtype. `k_i`
          may be of different sizes. Each `Tensor` represents the beginning of the
          accrual period for the forward rate which determines the floating payment.
          Each element in the list belong to a unique swap to be used to build the
          curve.
        float_leg_end_times: List of `Tensor`s of shapes and `dtype` compatible with
          `float_leg_start_times`. Each `Tensor` represents the end of the
          accrual period for the forward rate which determines the floating payment.
        float_leg_daycount_fractions: List of `Tensor`s of shapes and `dtype`
          compatible with `float_leg_start_times`. Each `Tensor` represents the
          daycount fraction of the forward rate which determines the floating
          payment.
        fixed_leg_start_times: List of `Tensor`s. Each `Tensor` must be either of
          shape `batch_shape  + [n_i]` or `[n_i]` and of the same real dtype.
          `n_i` may be of different sizes. All elements must have the same `dtype`
          as `float_leg_start_times`. Each `Tensor` represents the beginning of the
          accrual period fixed coupon.
        fixed_leg_end_times: List of `Tensor`s of shapes and `dtype` compatible with
          `fixed_leg_start_times`. All elements must have the same `dtype` as
          `fixed_leg_start_times`. Each `Tensor` represents the
          end of the accrual period for the fixed coupon.
        fixed_leg_daycount_fractions: List of `Tensor`s of shapes and `dtype`
        compatible with
          `fixed_leg_start_times` Each `Tensor` represents the daycount fraction
          applicable for the fixed payment.
        fixed_leg_cashflows: List of `Tensor`s of shapes and `dtype` compatible with
          `fixed_leg_start_times`. The input contains fixed cashflows at each
          coupon payment time including notional (if any). The sign should be
          negative (positive) to indicate net outgoing (incoming) cashflow.
        present_values: List containing `Tensor`s of the same dtype as
          elements of `fixed_leg_cashflows` and of shapes compatible with
          `batch_shape`. The length of the list must be the same as the length of
          `fixed_leg_cashflows`. The input contains the market price of the
          underlying instruments.
        initial_curve_rates: A `Tensor` of the `dtype` as `present_values` and of
          shape `[batch_shape, num_instruments]` where `num_instruments` is the
          length of `float_leg_start_times`. The starting guess for the discount
          rates used to initialize the iterative procedure.
        present_values_settlement_times: Optional list of `Tensor`s with the shapes
          and `dtype` compatible with `present_values` The settlement times for the
          present values is the time from now when the instrument is traded to the
          time that the purchase price is actually delivered. If not supplied, then
          it is assumed that the settlement times are zero for every bond.
          Default value: `None` which is equivalent to zero settlement times.
        float_leg_discount_rates: Optional list of `Tensor`s with the shapes
          and `dtype` compatible with `present_values`. This input contains the
          continuously compounded discount rates the will be used
          to discount the floating cashflows. This allows the swap curve to
          constructed using an independent discount curve (e.g. OIS curve). By
          default the cashflows are discounted using the curve that is being
          constructed.
        float_leg_discount_times: Optional list of `Tensor`s with the shapes
          and `dtype` compatible with `present_values`. This input contains the
          times corresponding to the rates specified via
          the `float_leg_discount_rates`.
        fixed_leg_discount_rates: Optional list of `Tensor`s with the shapes
          and `dtype` compatible with `present_values`. This input contains the
          continuously compounded discount rates the will be used to discount the
          fixed cashflows. This allows the swap curve to constructed using an
          independent discount curve (e.g. OIS curve). By default the cashflows are
          discounted using the curve that is being constructed.
        fixed_leg_discount_times: Optional list of `Tensor`s with the shapes
          and `dtype` compatible with `present_values`. This input contains the
          times corresponding to the rates specified via the
          `fixed_leg_discount_rates`.
        optimizer: Optional Python callable which implements the algorithm used
          to minimize the objective function during calibration. It should have
          the following interface: result =
            optimizer(value_and_gradients_function, initial_position, tolerance,
            max_iterations) `value_and_gradients_function` is a Python callable that
            accepts a point as a real `Tensor` and returns a tuple of `Tensor`s of
            real dtype containing the value of the function and its gradient at that
            point. 'initial_position' is a real `Tensor` containing the starting
            point of the optimization, 'tolerance' is a real scalar `Tensor` for
            stopping tolerance for the procedure and `max_iterations` specifies the
            maximum number of iterations.
          `optimizer` should return a namedtuple containing the items: `position`
            (a tensor containing the optimal value), `converged` (a boolean
            indicating whether the optimize converged according the specified
            criteria), `failed` (a boolean indicating if the optimization resulted
            in a failure), `num_iterations` (the number of iterations used), and
            `objective_value` ( the value of the objective function at the optimal
            value). The default value for `optimizer` is None and conjugate
            gradient algorithm is used.
          Default value: `None` - indicating conjugate gradient minimizer.
        curve_interpolator: Optional Python callable used to interpolate the zero
          swap rates at cashflow times. It should have the following interface:
          yi = curve_interpolator(xi, x, y)
          `x`, `y`, 'xi', 'yi' are all `Tensors` of real dtype. `x` and `y` are the
          sample points and values (respectively) of the function to be
          interpolated. `xi` are the points at which the interpolation is
          desired and `yi` are the corresponding interpolated values returned by the
          function. The default value for `curve_interpolator` is None in which
          case linear interpolation is used.
          Default value: `None`. If not supplied, the yields to maturity for the
            bonds is used as the initial value.
        instrument_weights: Optional 'Tensor' of the same dtype and shape as
          `initial_curve_rates`. This input contains the weight of each instrument
          in computing the objective function for the conjugate gradient
          optimization. By default the weights are set to be the inverse of
          maturities.
        curve_tolerance: Optional positive scalar `Tensor` of same dtype as
          elements of `bond_cashflows`. The absolute tolerance for terminating the
          iterations used to fit the rate curve. The iterations are stopped when the
          estimated discounts at the expiry times of the bond_cashflows change by a
          amount smaller than `discount_tolerance` in an iteration.
          Default value: 1e-8.
        maximum_iterations: Optional positive integer `Tensor`. The maximum number
          of iterations permitted when fitting the curve.
          Default value: 50.
        dtype: `tf.Dtype`. If supplied the dtype for the (elements of)
          `float_leg_start_times`, and `fixed_leg_start_times`.
          Default value: None which maps to the default dtype inferred by
          TensorFlow.
        name: Python str. The name to give to the ops created by this function.
          Default value: `None` which maps to 'swap_curve'.
  
      Returns:
        curve_builder_result: An instance of `SwapCurveBuilderResult` containing the
          following attributes.
          times: Rank 1 real `Tensor`. Times for the computed discount rates. These
            are chosen to be the expiry times of the supplied cashflows.
          discount_rates: Rank 1 `Tensor` of the same dtype as `times`.
            The inferred discount rates.
          discount_factor: Rank 1 `Tensor` of the same dtype as `times`.
            The inferred discount factors.
          initial_discount_rates: Rank 1 `Tensor` of the same dtype as `times`. The
            initial guess for the discount rates.
          converged: Scalar boolean `Tensor`. Whether the procedure converged.
            The procedure is said to have converged when the maximum absolute
            difference in the discount factors from one iteration to the next falls
            below the `discount_tolerance`.
          failed: Scalar boolean `Tensor`. Whether the procedure failed. Procedure
            may fail either because a NaN value was encountered for the discount
            rates or the discount factors.
          iterations: Scalar int32 `Tensor`. Number of iterations performed.
          objective_value: Scalar real `Tensor`. The value of the ibjective function
            evaluated using the fitted swap curve.
  
      Raises:
        ValueError: If the initial state of the curve is not
        supplied to the function.
  
      """
  
      with tf.name_scope(name or "swap_curve"):
          if optimizer is None:
              optimizer = optimizers.conjugate_gradient_minimize
  
          present_values = _convert_to_tensors(
              dtype, present_values, "present_values"
          )
          dtype = present_values[0].dtype
          if present_values_settlement_times is None:
              pv_settlement_times = [
                  tf.zeros([], dtype=dtype) for pv in present_values
              ]
          else:
              pv_settlement_times = _convert_to_tensors(
                  dtype,
                  present_values_settlement_times,
                  "pv_settlement_times",
              )
  
          float_leg_start_times = _convert_to_tensors(
              dtype, float_leg_start_times, "float_leg_start_times"
          )
          float_leg_end_times = _convert_to_tensors(
              dtype, float_leg_end_times, "float_leg_end_times"
          )
          float_leg_daycount_fractions = _convert_to_tensors(
              dtype,
              float_leg_daycount_fractions,
              "float_leg_daycount_fractions",
          )
          fixed_leg_start_times = _convert_to_tensors(
              dtype, fixed_leg_start_times, "fixed_leg_start_times"
          )
          fixed_leg_end_times = _convert_to_tensors(
              dtype, fixed_leg_end_times, "fixed_leg_end_times"
          )
          fixed_leg_daycount_fractions = _convert_to_tensors(
              dtype,
              fixed_leg_daycount_fractions,
              "fixed_leg_daycount_fractions",
          )
          fixed_leg_cashflows = _convert_to_tensors(
              dtype, fixed_leg_cashflows, "fixed_leg_cashflows"
          )
  
          present_values = tf.stack(present_values, axis=-1)
          if instrument_weights is None:
              instrument_weights = _initialize_instrument_weights(
                  float_leg_end_times, fixed_leg_end_times, dtype=dtype
              )
          else:
              instrument_weights = _convert_to_tensors(
                  dtype, instrument_weights, "instrument_weights"
              )
  
          if curve_interpolator is None:
  
              def default_interpolator(xi, x, y):
                  return linear.interpolate(xi, x, y, dtype=dtype)
  
              curve_interpolator = default_interpolator
          self_discounting_float_leg = False
          self_discounting_fixed_leg = False
          # Determine how the floating and fixed leg will be discounted. If separate
          # discount curves for each leg are not specified, the curve will be self
          # discounted using the swap curve.
          if (
              float_leg_discount_rates is None
              and fixed_leg_discount_rates is None
          ):
              self_discounting_float_leg = True
              self_discounting_fixed_leg = True
              float_leg_discount_rates = [0.0]
              float_leg_discount_times = [0.0]
              fixed_leg_discount_rates = [0.0]
              fixed_leg_discount_times = [0.0]
          elif fixed_leg_discount_rates is None:
              fixed_leg_discount_rates = float_leg_discount_rates
              fixed_leg_discount_times = float_leg_discount_times
          elif float_leg_discount_rates is None:
              self_discounting_float_leg = True
              float_leg_discount_rates = [0.0]
              float_leg_discount_times = [0.0]
  
          # Create tensors for discounting curves
          float_leg_discount_rates = _convert_to_tensors(
              dtype, float_leg_discount_rates, "float_disc_rates"
          )
          float_leg_discount_rates = tf.stack(
              float_leg_discount_rates, axis=-1
          )
          float_leg_discount_times = _convert_to_tensors(
              dtype, float_leg_discount_times, "float_disc_times"
          )
          float_leg_discount_times = tf.stack(
              float_leg_discount_times, axis=-1
          )
          fixed_leg_discount_rates = _convert_to_tensors(
              dtype, fixed_leg_discount_rates, "fixed_disc_rates"
          )
          fixed_leg_discount_rates = tf.stack(
              fixed_leg_discount_rates, axis=-1
          )
          fixed_leg_discount_times = _convert_to_tensors(
              dtype, fixed_leg_discount_times, "fixed_disc_times"
          )
          fixed_leg_discount_times = tf.stack(
              fixed_leg_discount_times, axis=-1
          )
  
          if initial_curve_rates is not None:
              initial_rates = tf.convert_to_tensor(
                  initial_curve_rates, dtype=dtype, name="initial_rates"
              )
          else:
              # TODO(b/144600429): Create a logic for a meaningful initial state of the
              # curve
              raise ValueError(
                  "Initial state of the curve is not specified."
              )
  
          return _build_swap_curve(
              float_leg_start_times,
              float_leg_end_times,
              float_leg_daycount_fractions,
              fixed_leg_start_times,
              fixed_leg_end_times,
              fixed_leg_cashflows,
              fixed_leg_daycount_fractions,
              float_leg_discount_rates,
              float_leg_discount_times,
              fixed_leg_discount_rates,
              fixed_leg_discount_times,
              self_discounting_float_leg,
              self_discounting_fixed_leg,
              present_values,
              pv_settlement_times,
              optimizer,
              curve_interpolator,
              initial_rates,
              instrument_weights,
              curve_tolerance,
              maximum_iterations,
          )
  
file_path: tf-quant-finance/tf_quant_finance/rates/swap_curve_fit.py
imports: from typing import List, Callable, Any
  import tensorflow.compat.v2
  from tf_quant_finance import types
  from tf_quant_finance import utils
  from tf_quant_finance.math import make_val_and_grad_fn
  from tf_quant_finance.math import optimizer
  from tf_quant_finance.math.interpolation import linear
  from tf_quant_finance.rates import swap_curve_common
label_desc: Use image node_id 1 for calling a global function with example usage: swap_curve_fit(float_leg_start_times, float_leg_end_times, float_leg_daycount_fractions, fixed_leg_start_times, fixed_leg_end_times, fixed_leg_daycount_fractions, fixed_leg_cashflows, present_values, initial_curve_rates, present_values_settlement_times, float_leg_discount_rates, float_leg_discount_times, fixed_leg_discount_rates, fixed_leg_discount_times, optimizer, curve_interpolator, instrument_weights, curve_tolerance, maximum_iterations, dtype, name) and returns: _build_swap_curve, linear