code: def swaption_price(
      *,
      expiries: types.RealTensor,
      floating_leg_start_times: types.RealTensor,
      floating_leg_end_times: types.RealTensor,
      fixed_leg_payment_times: types.RealTensor,
      floating_leg_daycount_fractions: types.RealTensor,
      fixed_leg_daycount_fractions: types.RealTensor,
      fixed_leg_coupon: types.RealTensor,
      reference_rate_fn: Callable[..., types.RealTensor],
      mean_reversion: Union[
          types.RealTensor, Callable[..., types.RealTensor]
      ],
      volatility: Union[
          types.RealTensor, Callable[..., types.RealTensor]
      ],
      notional: types.RealTensor = None,
      is_payer_swaption: types.BoolTensor = True,
      use_analytic_pricing: bool = True,
      num_samples: types.IntTensor = 100,
      random_type: random.RandomType = None,
      seed: types.IntTensor = None,
      skip: types.IntTensor = 0,
      time_step: types.RealTensor = None,
      dtype: tf.DType = None,
      name: str = None,
  ) -> types.RealTensor:
      """Calculates the price of European Swaptions using the Hull-White model.
  
      A European Swaption is a contract that gives the holder an option to enter a
      swap contract at a future date at a prespecified fixed rate. A swaption that
      grants the holder to pay fixed rate and receive floating rate is called a
      payer swaption while the swaption that grants the holder to receive fixed and
      pay floating payments is called the receiver swaption. Typically the start
      date (or the inception date) of the swap concides with the expiry of the
      swaption. Mid-curve swaptions are currently not supported (b/160061740).
  
      Analytic pricing of swaptions is performed using the Jamshidian decomposition
      [1].
  
      #### References:
        [1]: D. Brigo, F. Mercurio. Interest Rate Models-Theory and Practice.
        Second Edition. 2007.
  
      #### Example
      The example shows how value a batch of 1y x 1y and 1y x 2y swaptions using the
      Hull-White model.
  
      ````python
      import numpy as np
      import tensorflow.compat.v2 as tf
      import tf_quant_finance as tff
  
      dtype = tf.float64
  
      expiries = [1.0, 1.0]
      float_leg_start_times = [[1.0, 1.25, 1.5, 1.75, 2.0, 2.0, 2.0, 2.0],
                                [1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75]]
      float_leg_end_times = [[1.25, 1.5, 1.75, 2.0, 2.0, 2.0, 2.0, 2.0],
                              [1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]]
      fixed_leg_payment_times = [[1.25, 1.5, 1.75, 2.0, 2.0, 2.0, 2.0, 2.0],
                              [1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]]
      float_leg_daycount_fractions = [[0.25, 0.25, 0.25, 0.25, 0.0, 0.0, 0.0, 0.0],
                                  [0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25]]
      fixed_leg_daycount_fractions = [[0.25, 0.25, 0.25, 0.25, 0.0, 0.0, 0.0, 0.0],
                                  [0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25]]
      fixed_leg_coupon = [[0.011, 0.011, 0.011, 0.011, 0.0, 0.0, 0.0, 0.0],
                          [0.011, 0.011, 0.011, 0.011, 0.011, 0.011, 0.011, 0.011]]
      zero_rate_fn = lambda x: 0.01 * tf.ones_like(x, dtype=dtype)
      price = tff.models.hull_white.swaption_price(
          expiries=expiries,
          floating_leg_start_times=float_leg_start_times,
          floating_leg_end_times=float_leg_end_times,
          fixed_leg_payment_times=fixed_leg_payment_times,
          floating_leg_daycount_fractions=float_leg_daycount_fractions,
          fixed_leg_daycount_fractions=fixed_leg_daycount_fractions,
          fixed_leg_coupon=fixed_leg_coupon,
          reference_rate_fn=zero_rate_fn,
          notional=100.,
          dim=1,
          mean_reversion=[0.03],
          volatility=[0.02],
          dtype=dtype)
      # Expected value: [0.7163243383624043, 1.4031415262337608] # shape = (2,1)
      ````
  
      Args:
        expiries: A real `Tensor` of any shape and dtype. The time to
          expiration of the swaptions. The shape of this input determines the number
          (and shape) of swaptions to be priced and the shape of the output.
        floating_leg_start_times: A real `Tensor` of the same dtype as `expiries`.
          The times when accrual begins for each payment in the floating leg. The
          shape of this input should be `expiries.shape + [m]` where `m` denotes
          the number of floating payments in each leg.
        floating_leg_end_times: A real `Tensor` of the same dtype as `expiries`.
          The times when accrual ends for each payment in the floating leg. The
          shape of this input should be `expiries.shape + [m]` where `m` denotes
          the number of floating payments in each leg.
        fixed_leg_payment_times: A real `Tensor` of the same dtype as `expiries`.
          The payment times for each payment in the fixed leg. The shape of this
          input should be `expiries.shape + [n]` where `n` denotes the number of
          fixed payments in each leg.
        floating_leg_daycount_fractions: A real `Tensor` of the same dtype and
          compatible shape as `floating_leg_start_times`. The daycount fractions
          for each payment in the floating leg.
        fixed_leg_daycount_fractions: A real `Tensor` of the same dtype and
          compatible shape as `fixed_leg_payment_times`. The daycount fractions
          for each payment in the fixed leg.
        fixed_leg_coupon: A real `Tensor` of the same dtype and compatible shape
          as `fixed_leg_payment_times`. The fixed rate for each payment in the
          fixed leg.
        reference_rate_fn: A Python callable that accepts expiry time as a real
          `Tensor` and returns a `Tensor` of either shape `input_shape` or
          `input_shape`. Returns the continuously compounded zero rate at
          the present time for the input expiry time.
        mean_reversion: A real positive scalar `Tensor` or a Python callable. The
          callable can be one of the following:
          (a) A left-continuous piecewise constant object (e.g.,
          `tff.math.piecewise.PiecewiseConstantFunc`) that has a property
          `is_piecewise_constant` set to `True`. In this case the object should
          have a method `jump_locations(self)` that returns a `Tensor` of shape
          `[num_jumps]`. The return value of `mean_reversion(t)` should return a
          `Tensor` of shape `t.shape`, `t` is a rank 1 `Tensor` of the same `dtype`
          as the output. See example in the class docstring.
          (b) A callable that accepts scalars (stands for time `t`) and returns a
          scalar `Tensor` of the same `dtype` as `strikes`.
          Corresponds to the mean reversion rate.
        volatility: A real positive `Tensor` of the same `dtype` as
          `mean_reversion` or a callable with the same specs as above.
          Corresponds to the long run price variance.
        notional: An optional `Tensor` of same dtype and compatible shape as
          `strikes`specifying the notional amount for the underlying swap.
           Default value: None in which case the notional is set to 1.
        is_payer_swaption: A boolean `Tensor` of a shape compatible with `expiries`.
          Indicates whether the swaption is a payer (if True) or a receiver
          (if False) swaption. If not supplied, payer swaptions are assumed.
        use_analytic_pricing: A Python boolean specifying if analytic valuation
          should be performed. Analytic valuation is only supported for constant
          `mean_reversion` and piecewise constant `volatility`. If the input is
          `False`, then valuation using Monte-Carlo simulations is performed.
          Default value: The default value is `True`.
        num_samples: Positive scalar `int32` `Tensor`. The number of simulation
          paths during Monte-Carlo valuation. This input is ignored during analytic
          valuation.
          Default value: The default value is 1.
        random_type: Enum value of `RandomType`. The type of (quasi)-random
          number generator to use to generate the simulation paths. This input is
          relevant only for Monte-Carlo valuation and ignored during analytic
          valuation.
          Default value: `None` which maps to the standard pseudo-random numbers.
        seed: Seed for the random number generator. The seed is only relevant if
          `random_type` is one of
          `[STATELESS, PSEUDO, HALTON_RANDOMIZED, PSEUDO_ANTITHETIC,
            STATELESS_ANTITHETIC]`. For `PSEUDO`, `PSEUDO_ANTITHETIC` and
          `HALTON_RANDOMIZED` the seed should be an Python integer. For
          `STATELESS` and  `STATELESS_ANTITHETIC `must be supplied as an integer
          `Tensor` of shape `[2]`. This input is relevant only for Monte-Carlo
          valuation and ignored during analytic valuation.
          Default value: `None` which means no seed is set.
        skip: `int32` 0-d `Tensor`. The number of initial points of the Sobol or
          Halton sequence to skip. Used only when `random_type` is 'SOBOL',
          'HALTON', or 'HALTON_RANDOMIZED', otherwise ignored.
          Default value: `0`.
        time_step: Scalar real `Tensor`. Maximal distance between time grid points
          in Euler scheme. Relevant when Euler scheme is used for simulation. This
          input is ignored during analytic valuation.
          Default value: `None`.
        dtype: The default dtype to use when converting values to `Tensor`s.
          Default value: `None` which means that default dtypes inferred by
          TensorFlow are used.
        name: Python string. The name to give to the ops created by this function.
          Default value: `None` which maps to the default name
          `hw_swaption_price`.
  
      Returns:
        A `Tensor` of real dtype and shape  `expiries.shape` containing the
        computed swaption prices. For swaptions that have. reset in the past
        (expiries<0), the function sets the corresponding option prices to 0.0.
      """
      # TODO(b/160061740): Extend the functionality to support mid-curve swaptions.
      name = name or "hw_swaption_price"
      del floating_leg_daycount_fractions
      with tf.name_scope(name):
          expiries = tf.convert_to_tensor(
              expiries, dtype=dtype, name="expiries"
          )
          dtype = dtype or expiries.dtype
          float_leg_start_times = tf.convert_to_tensor(
              floating_leg_start_times,
              dtype=dtype,
              name="float_leg_start_times",
          )
          float_leg_end_times = tf.convert_to_tensor(
              floating_leg_end_times,
              dtype=dtype,
              name="float_leg_end_times",
          )
          fixed_leg_payment_times = tf.convert_to_tensor(
              fixed_leg_payment_times,
              dtype=dtype,
              name="fixed_leg_payment_times",
          )
          fixed_leg_daycount_fractions = tf.convert_to_tensor(
              fixed_leg_daycount_fractions,
              dtype=dtype,
              name="fixed_leg_daycount_fractions",
          )
          fixed_leg_coupon = tf.convert_to_tensor(
              fixed_leg_coupon, dtype=dtype, name="fixed_leg_coupon"
          )
          notional = tf.convert_to_tensor(
              notional, dtype=dtype, name="notional"
          )
          is_payer_swaption = tf.convert_to_tensor(
              is_payer_swaption, dtype=tf.bool, name="is_payer_swaption"
          )
          if (
              expiries.shape.rank
              < fixed_leg_payment_times.shape.rank - 1
          ):
              raise ValueError(
                  "Swaption expiries not specified for all swaptions "
                  "in the batch. Expected rank {} but received {}.".format(
                      fixed_leg_payment_times.shape.rank - 1,
                      expiries.shape.rank,
                  )
              )
          # Add a dimension corresponding to multiple cashflows in a swap
          # Shape batch_shape + [1]
          expiries = tf.expand_dims(expiries, axis=-1)
          # Expected shape: batch_shape + [m], same as fixed_leg_payment_times.shape
          # We need to explicitly use tf.repeat because we need to price
          # batch_shape + [m] bond options with different strikes along the last
          # dimension.
          expiries = tf.repeat(
              expiries, tf.shape(fixed_leg_payment_times)[-1], axis=-1
          )
  
          if use_analytic_pricing:
              return _analytic_valuation(
                  expiries,
                  float_leg_start_times,
                  float_leg_end_times,
                  fixed_leg_payment_times,
                  fixed_leg_daycount_fractions,
                  fixed_leg_coupon,
                  reference_rate_fn,
                  mean_reversion,
                  volatility,
                  notional,
                  is_payer_swaption,
                  dtype,
                  name + "_analytic_valuation",
              )
  
          if time_step is None:
              raise ValueError(
                  "`time_step` must be provided for simulation "
                  "based bond option valuation."
              )
  
          # Monte-Carlo pricing
          model = one_factor.HullWhiteModel1F(
              mean_reversion,
              volatility,
              initial_discount_rate_fn=reference_rate_fn,
              dtype=dtype,
          )
  
          def _sample_discount_curve_path_fn(
              times, curve_times, num_samples
          ):
              p_t_tau, r_t = model.sample_discount_curve_paths(
                  times=times,
                  curve_times=curve_times,
                  num_samples=num_samples,
                  random_type=random_type,
                  seed=seed,
                  skip=skip,
              )
              return p_t_tau, r_t, None
  
          # `sim_times` are times at which we request short rate and spot discount
          # curve simulations. Ideally, we need the simulations only at `expiries`
          # but here we request simulations at a finer time grid because we will be
          # computing path discount factors numerically.
          sim_times, _ = tf.unique(tf.reshape(expiries, shape=[-1]))
          longest_expiry = tf.reduce_max(sim_times)
          sim_times = tf.concat(
              [
                  sim_times,
                  tf.range(time_step, longest_expiry, time_step),
              ],
              axis=0,
          )
          sim_times = tf.sort(sim_times, name="sort_sim_times")
  
          # Shapes batch_shape + [num_samples, num_times, 1]
          (
              payoff_discount_factors,
              payoff_bond_price,
          ) = swaption_util.discount_factors_and_bond_prices_from_samples(
              expiries=expiries,
              payment_times=fixed_leg_payment_times,
              sample_discount_curve_paths_fn=_sample_discount_curve_path_fn,
              num_samples=num_samples,
              times=sim_times,
              dtype=dtype,
          )
          # Add an axis corresponding to `dim`
          fixed_leg_pv = (
              fixed_leg_coupon
              * fixed_leg_daycount_fractions
              * tf.squeeze(payoff_bond_price, axis=-1)
          )
          # Sum fixed coupon payments within each swap.
          # Shape batch_shape + [num_samples]
          fixed_leg_pv = tf.math.reduce_sum(fixed_leg_pv, axis=-1)
          float_leg_pv = (
              1.0 - tf.squeeze(payoff_bond_price, axis=-1)[..., -1]
          )
          payoff_swap = tf.squeeze(payoff_discount_factors, axis=-1)[
              ..., -1
          ] * (float_leg_pv - fixed_leg_pv)
          payoff_swap = tf.where(
              is_payer_swaption, payoff_swap, -1.0 * payoff_swap
          )
          payoff_swaption = tf.math.maximum(payoff_swap, 0.0)
          option_value = tf.math.reduce_mean(payoff_swaption, axis=0)
          return notional * option_value
  
imports: from typing import Callable, Union
  import numpy
  import tensorflow.compat.v2
  from tf_quant_finance import types
  from tf_quant_finance.math import pde
  from tf_quant_finance.math import random
  from tf_quant_finance.math.interpolation import linear
  from tf_quant_finance.math.root_search import brent
  from tf_quant_finance.models import utils
  from tf_quant_finance.models.hjm import swaption_util
  from tf_quant_finance.models.hull_white import one_factor
  from tf_quant_finance.models.hull_white import zero_coupon_bond_option
  from tf_quant_finance.models.longstaff_schwartz import lsm
label_desc: Use image node_id 1 for calling a global function with example usage: swaption_price() and returns: unknown, _analytic_valuation, p_t_tau,  r_t,  None