code: def andersen_lake(
      *,
      volatilities: types.RealTensor,
      strikes: types.RealTensor,
      expiries: types.RealTensor,
      spots: types.RealTensor = None,
      forwards: types.RealTensor = None,
      discount_rates: types.RealTensor = None,
      discount_factors: types.RealTensor = None,
      dividend_rates: types.RealTensor = None,
      is_call_options: types.BoolTensor = None,
      grid_num_points: int = 10,
      integration_num_points_kronrod: int = 31,
      integration_num_points_legendre: int = 32,
      max_iterations_exercise_boundary: int = 30,
      max_depth_kronrod: int = 30,
      tolerance_exercise_boundary: types.RealTensor = 1e-8,
      tolerance_kronrod: types.RealTensor = 1e-8,
      dtype: tf.DType = None,
      name: str = None,
  ) -> types.RealTensor:
      """Computes American option prices using the Andersen-Lake approximation.
  
      #### Example
  
      ```python
      volatilities = [0.1, 0.15]
      strikes = [3, 2]
      expiries = [1, 2]
      spots = [8.0, 9.0]
      discount_rates = [0.01, 0.02]
      dividend_rates = [0.01, 0.02]
      is_call_options = [True, False]
      grid_num_points = 40
      integration_num_points_kronrod = 31
      integration_num_points_legendre = 32
      max_iterations_exercise_boundary = 500
      max_depth_kronrod = 50
      tolerance_exercise_boundary = 1e-11
      tolerance_kronrod = 1e-11
      computed_prices = andersen_lake(
          volatilities=volatilities,
          strikes=strikes,
          expiries=expiries,
          spots=spots,
          discount_rates=discount_rates,
          dividend_rates=dividend_rates,
          is_call_options=is_call_options,
          grid_num_points=grid_num_points,
          integration_num_points_kronrod=integration_num_points_kronrod,
          integration_num_points_legendre=integration_num_points_legendre,
          max_iterations_exercise_boundary=max_iterations_exercise_boundary,
          max_depth_kronrod=max_depth_kronrod,
          tolerance_exercise_boundary=tolerance_exercise_boundary,
          tolerance_kronrod=tolerance_kronrod
          dtype=tf.float64)
      # Expected print output of computed prices:
      # [4.950249e+00, 7.768513e-14]
      ```
  
      #### References:
      [1] Leif Andersen, Mark Lake and Dimitri Offengenden. High-performance
      American option pricing. 2015
      https://engineering.nyu.edu/sites/default/files/2019-03/Carr-adjusting-exponential-levy-models.pdf#page=46
  
      Args:
        volatilities: Real `Tensor` of any real dtype and shape `[num_options]`.
          The volatilities to expiry of the options to price.
        strikes: A real `Tensor` of the same dtype and same shape as `volatilities`.
          The strikes of the options to be priced.
        expiries: A real `Tensor` of same dtype and same shape as `volatilities`.
          The expiry of each option. The units should be such that
          `expiry * volatility**2` is dimensionless.
        spots: A real `Tensor` of same shape as `volatilities`. The current spot
          price of the underlying. Either this argument or the `forwards` (but not
          both) must be supplied.
        forwards: A real `Tensor` of same shape as `volatilities`. The forwards to
          maturity. Either this argument or the `spots` must be supplied but both
          must not be supplied.
        discount_rates: An optional real `Tensor` of same shape and dtype as the
          `volatilities`. If not `None`, discount factors are calculated as e^(-rT),
          where r are the discount rates, or risk free rates.
          Default value: `None`, which maps to `-log(discount_factors) / expiries`
            if `discount_factors` is not `None`, or maps to `0` when
            `discount_factors` is also `None`.
        discount_factors: An optional real `Tensor` of same shape and dtype as the
          `volatilities`. If not `None`, these are the discount factors to expiry
          (i.e. e^(-rT)). Mutually exclusive with `discount_rate`. If neither is
          given, no discounting is applied (i.e. the undiscounted option price is
          returned). If `spots` is supplied and `discount_factors` is not `None`
          then this is also used to compute the forwards to expiry.
          Default value: `None`.
        dividend_rates: An optional real `Tensor` of same shape and dtype as the
          `volatilities`. The continuous dividend rate on the underliers. May be
          negative (to indicate costs of holding the underlier).
          Default value: `None`, equivalent to zero dividends.
        is_call_options: A boolean `Tensor` of a shape compatible with
          `volatilities`. Indicates whether the option is a call (if True) or a put
          (if False). If not supplied, call options are assumed.
        grid_num_points: positive `int`. The number of equidistant points to divide
          the values given in `expiries` into in the grid of `tau_grid`.
          Default value: 10.
        integration_num_points_kronrod: positive `int`. The number of points used in
          the Gauss-Kronrod integration approximation method used for
          calculating the option prices.
          Default value: 31.
        integration_num_points_legendre: positive `int`. The number of points used
          in the Gauss-Legendre integration approximation method used for
          calculating the exercise boundary function used for pricing the options.
          Default value: 32.
        max_iterations_exercise_boundary: positive `int`. Maximum number of
          iterations for calculating the exercise boundary if it doesn't converge
          earlier.
          Default value: 30.
        max_depth_kronrod: positive `int`. Maximum number of iterations for
          calculating the Gauss-Kronrod integration approximation.
          Default value: 30.
        tolerance_exercise_boundary: Positive scalar `Tensor`. The tolerance for the
          convergence of calculating the exercise boundary function.
          Default value: 1e-8.
        tolerance_kronrod: Positive scalar `Tensor`. The tolerance for the
          convergence of calculating the Gauss-Kronrod integration approximation.
          Default value: 1e-8.
        dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion
          of any supplied non-`Tensor` arguments to `Tensor`.
          Default value: None which maps to the default dtype inferred by
            TensorFlow.
        name: str. The name for the ops created by this function.
          Default value: None which is mapped to the default name `andersen_lake`.
  
      Returns:
        `Tensor` of shape `[num_options]`, containing the calculated American option
        prices.
  
      Raises:
        ValueError:
          (a) If both `forwards` and `spots` are supplied or if neither is supplied.
      """
      if (spots is None) == (forwards is None):
          raise ValueError(
              "Either spots or forwards must be supplied but not both."
          )
      if (discount_rates is not None) and (
          discount_factors is not None
      ):
          raise ValueError(
              "At most one of discount_rates and discount_factors may "
              "be supplied"
          )
      with tf.name_scope(name or "andersen_lake"):
          volatilities = tf.convert_to_tensor(
              volatilities, dtype=dtype, name="volatilities"
          )
          dtype = (
              volatilities.dtype
          )  # This dtype should be common for all inputs
          strikes = tf.convert_to_tensor(
              strikes, dtype=dtype, name="strikes"
          )
          expiries = tf.convert_to_tensor(
              expiries, dtype=dtype, name="expiries"
          )
          if discount_rates is not None:
              discount_rates = tf.convert_to_tensor(
                  discount_rates, dtype=dtype, name="discount_rates"
              )
          elif discount_factors is not None:
              discount_factors = tf.convert_to_tensor(
                  discount_factors, dtype=dtype, name="discount_factors"
              )
              # For expiries == 0 discount_rates is irrelevant for the option price,
              # so we can set it to 0.
              discount_rates = tf.math.divide_no_nan(
                  -tf.math.log(discount_factors), expiries
              )
          else:
              discount_rates = tf.constant(
                  [0.0], dtype=dtype, name="discount_rates"
              )
  
          if dividend_rates is not None:
              dividend_rates = tf.convert_to_tensor(
                  dividend_rates, dtype=dtype, name="dividend_rates"
              )
          else:
              dividend_rates = tf.constant(
                  [0.0], dtype=dtype, name="dividend_rates"
              )
          # Set forwards and spots
          if forwards is not None:
              spots = tf.convert_to_tensor(
                  forwards
                  * tf.exp(
                      -(discount_rates - dividend_rates) * expiries
                  ),
                  dtype=dtype,
                  name="spots",
              )
          else:
              spots = tf.convert_to_tensor(
                  spots, dtype=dtype, name="spots"
              )
          if is_call_options is not None:
              is_call_options = tf.convert_to_tensor(
                  is_call_options, dtype=tf.bool, name="is_call_options"
              )
          else:
              is_call_options = tf.constant(
                  True, name="is_call_options"
              )
  
          # Shape [num_options]
          am_prices = _andersen_lake(
              sigma=volatilities,
              k_temp=strikes,
              tau=expiries,
              s_temp=spots,
              r_temp=discount_rates,
              q_temp=dividend_rates,
              is_call_options=is_call_options,
              grid_num_points=grid_num_points,
              integration_num_points_kronrod=integration_num_points_kronrod,
              integration_num_points_legendre=integration_num_points_legendre,
              max_iterations_exercise_boundary=max_iterations_exercise_boundary,
              max_depth_kronrod=max_depth_kronrod,
              tolerance_exercise_boundary=tolerance_exercise_boundary,
              tolerance_kronrod=tolerance_kronrod,
              dtype=dtype,
          )
          # Shape [num_options]
          return am_prices
  
file_path: tf-quant-finance/tf_quant_finance/experimental/american_option_pricing/andersen_lake.py
imports: import tensorflow.compat.v2
  from tf_quant_finance import types
  from tf_quant_finance import utils
  from tf_quant_finance.black_scholes import vanilla_prices
  from tf_quant_finance.experimental.american_option_pricing import common
  from tf_quant_finance.experimental.american_option_pricing import exercise_boundary
  from tf_quant_finance.math.integration import gauss_kronrod
label_desc: Use image node_id 1 for calling a global function with example usage: andersen_lake() and returns: am_prices