code: def _dupire_local_volatility_iv_precomputed(
      initial_spot_price: types.RealTensor,
      implied_volatility_surface: Any,
      discount_factor_fn: Callable[..., types.RealTensor],
      dividend_yield: Callable[..., types.RealTensor],
      times_grid: types.RealTensor,
      spot_grid: types.RealTensor,
      dim: int,
      dtype: tf.DType,
  ) -> Callable[..., types.RealTensor]:
      """Constructs local volatility function using Dupire's formula.
  
      Returns a function similar to _dupire_local_volatility_iv using precomputed
      spline coefficients for IV.
  
      Args:
        initial_spot_price: A real `Tensor` specifying the underlying spot price at
          t=0.
        implied_volatility_surface: A Python callable which implements the
          interpolation of market implied volatilities. The callable should have the
          interface `implied_volatility_surface(strike, expiry_times)` which takes
          real `Tensor`s corresponding to option strikes and time to expiry and
          returns a real `Tensor` containing the corresponding market implied
          volatility. The shape of `strike` is `(n,dim)` where `dim` is the
          dimensionality of the local volatility process and `t` is a scalar tensor.
          The output from the callable is a `Tensor` of shape `(n,dim)` containing
          the interpolated implied volatilties.
        discount_factor_fn: A python callable accepting one real `Tensor` argument
          time t. It should return a `Tensor` specifying the discount factor to time
          t.
        dividend_yield: A real `Tensor` of shape compatible with `spot_price`
          specifying the (continuously compounded) dividend yield.
        times_grid: A `Tensor` of shape `[num_time_samples]`. The grid on which to
          do interpolation over time.
        spot_grid: A `Tensor` of shape `[num_spot_samples]`. The grid on which to do
          interpolation over spots.
        dim: An int. The model dimension.
        dtype: The default dtype to use when converting values to `Tensor`s.
  
      Returns:
        A python callable f(spot_price,time) returning a real `Tensor` of same shape
        as `spot_price` containing the local volatility computed at
        `(spot_price,time)` using Dupire's construction of local volatility.
      """
      times_grid = tf.convert_to_tensor(times_grid, dtype=dtype)
      spot_grid = tf.convert_to_tensor(spot_grid, dtype=dtype)
  
      # Add batch dim.
      times_grid = tf.expand_dims(times_grid, 0)
      spot_grid = tf.expand_dims(spot_grid, 0)
  
      # Pre-compute IV.
      def map_times(times):
          def wrap_implied_vol(time):
              spots = tf.transpose(spot_grid)
              # TODO(b/229480163): Batch this.
              return implied_volatility_surface(
                  strike=spots, expiry_times=time
              )
  
          return tf.vectorized_map(
              wrap_implied_vol, tf.transpose(times)
          )
  
      implied_vol_grid = map_times(times_grid)
      implied_vol_grid = tf.transpose(implied_vol_grid, [0, 2, 1])
  
      # Pre-compute gradients using spline for dTheta/dt.
      def map_times_grad(times):
          def wrap_implied_vol(time):
              spots = tf.transpose(spot_grid)
              # TODO(b/229480163): Batch this.
              return implied_volatility_surface(
                  strike=spots, expiry_times=time
              )
  
          fn_grad = lambda time: math.fwd_gradient(
              wrap_implied_vol, time
          )
          return tf.vectorized_map(fn_grad, tf.transpose(times))
  
      grad_implied_vol_grid = map_times_grad(times_grid)
      grad_implied_vol_grid = tf.transpose(
          grad_implied_vol_grid, [0, 2, 1]
      )
  
      # Set up grids for interpolation.
      times_grid = tf.squeeze(times_grid)
      spot_grid = tf.squeeze(spot_grid)
      spot_grid_2d = tf.broadcast_to(
          spot_grid, [times_grid.shape[0], dim, spot_grid.shape[0]]
      )
      spline_info = cubic.build_spline(
          spot_grid_2d,
          implied_vol_grid,
          name="spline_spots",
          validate_args=True,
      )
  
      jump_locations = tf.slice(
          times_grid, [1], [times_grid.shape[0] - 1]
      )
      spline_coeffs_fn = piecewise.PiecewiseConstantFunc(
          jump_locations, spline_info.spline_coeffs
      )
      spot_grid_2d_fn = piecewise.PiecewiseConstantFunc(
          jump_locations, spot_grid_2d, dtype=dtype
      )
      implied_vol_grid_fn = piecewise.PiecewiseConstantFunc(
          jump_locations, implied_vol_grid, dtype=dtype
      )
      spline_grad_info = cubic.build_spline(
          spot_grid_2d,
          grad_implied_vol_grid,
          name="spline_grad_spots",
          validate_args=True,
      )
  
      grad_implied_vol_grid_fn = piecewise.PiecewiseConstantFunc(
          jump_locations, grad_implied_vol_grid, dtype=dtype
      )
      spline_grad_coeffs_fn = piecewise.PiecewiseConstantFunc(
          jump_locations, spline_grad_info.spline_coeffs
      )
  
      def local_variance(time, spot_price):
          risk_free_rate_fn = _get_risk_free_rate_from_discount_factor(
              discount_factor_fn
          )
          risk_free_rate = tf.convert_to_tensor(
              risk_free_rate_fn(time), dtype=dtype
          )
  
          # Setup to compute IV and gradients.
          spot_grid_2d = tf.squeeze(spot_grid_2d_fn([time]), 0)
          implied_vol_grid = tf.squeeze(implied_vol_grid_fn([time]), 0)
          spline_coeffs = tf.squeeze(spline_coeffs_fn([time]), 0)
          spline = math.interpolation.cubic.SplineParameters(
              spot_grid_2d, implied_vol_grid, spline_coeffs
          )
  
          def theta_fn(spot):
              return tf.transpose(
                  math.interpolation.cubic.interpolate(
                      tf.transpose(spot), spline, dtype=dtype
                  )
              )
  
          def grad_spots_fn(spot):
              return math.fwd_gradient(
                  theta_fn,
                  spot,
                  unconnected_gradients=tf.UnconnectedGradients.ZERO,
              )
  
          theta = theta_fn(spot_price)
  
          # Compute gradient of `theta` wrt `time`
          grad_implied_vol_grid = tf.squeeze(
              grad_implied_vol_grid_fn([time]), 0
          )
          spline_grad_coeffs = tf.squeeze(
              spline_grad_coeffs_fn([time]), 0
          )
  
          spline_grad = math.interpolation.cubic.SplineParameters(
              spot_grid_2d, grad_implied_vol_grid, spline_grad_coeffs
          )
  
          grad_times = tf.transpose(
              math.interpolation.cubic.interpolate(
                  tf.transpose(spot_price), spline_grad, dtype=dtype
              )
          )
  
          # Then set up the rest of Dupire as usual.
          d1 = tf.math.divide_no_nan(
              (
                  tf.math.log(
                      tf.math.divide_no_nan(
                          initial_spot_price, spot_price
                      )
                  )
                  + (risk_free_rate - dividend_yield + 0.5 * theta**2)
                  * time
              )
              / theta,
              tf.math.sqrt(time),
          )
  
          spots_t = spot_price
          # Gradient of `theta` wrt `spots`
          grad_spots = grad_spots_fn(spots_t)
          # Second gradient of `theta` wrt `spots`
          grad_grad_spots = math.fwd_gradient(
              grad_spots_fn,
              spots_t,
              unconnected_gradients=tf.UnconnectedGradients.ZERO,
          )
  
          # Dupire formula
          local_var = (
              theta**2
              + 2 * time * theta * grad_times
              + 2
              * (risk_free_rate - dividend_yield)
              * spots_t
              * time
              * theta
              * grad_spots
          ) / (
              (1 + spots_t * d1 * time * grad_spots) ** 2
              + spots_t**2
              * time
              * theta
              * (grad_grad_spots - d1 * time * grad_spots**2)
          )
          local_var = tf.nn.relu(local_var)
          return tf.math.sqrt(local_var)
  
      return local_variance
  
imports: import functools
  from typing import Any, Callable, List, Optional, Union
  import tensorflow.compat.v2
  from tf_quant_finance import black_scholes
  from tf_quant_finance import datetime
  from tf_quant_finance import math
  from tf_quant_finance import types
  from tf_quant_finance.experimental.pricing_platform.framework.market_data import volatility_surface
  from tf_quant_finance.math import interpolation
  from tf_quant_finance.math import piecewise
  from tf_quant_finance.math import random
  from tf_quant_finance.models import generic_ito_process
label_desc: Use image node_id 3 for calling a global function with example usage: _dupire_local_volatility_iv_precomputed(initial_spot_price, implied_volatility_surface, discount_factor_fn, dividend_yield, times_grid, spot_grid, dim, dtype) and returns: local_variance, tf, tf, tf, implied_volatility_surface, implied_volatility_surface, tf, math