class_docstr: Implements the SABR model defined by the following equations.
  
  ```
    dF_t = v_t * F_t ^ beta * dW_{F,t}
    dv_t = volvol * v_t * dW_{v,t}
    dW_{F,t} * dW_{v,t} = rho * dt
  ```
  
  `F_t` is the forward. `v_t` is volatility. `beta` is the CEV parameter.
  `volvol` is volatility of volatility. `W_{F,t}` and `W_{v,t}` are two
  correlated Wiener processes with instantaneous correlation `rho`.
  
  This model supports time dependent parameters. In other words, `beta`,
  `volvol`, and `rho` can be functions of time. When all of these parameters are
  constants, `beta` != 1, and `enable_unbiased_sampling` is True, the almost
  exact sampling procedure described in Ref [1] will be used. Otherwise it will
  default to Euler sampling.
  
  ### Example. Simple example with time independent params.
  
  ```none
    process = sabr.SabrModel(beta=0.5, volvol=1, rho=0.5, dtype=tf.float32)
    paths = process.sample_paths(
        initial_forward=100,
        initial_volatility=0.05,
        times=[1,2,5],
        time_step=0.01,
        num_samples=10000)
  ```
  
  ### Example 2. Callable volvol and correlation coefficient.
  
  ```none
    volvol_fn = lambda t: tf.where(t < 2, 0.5, 1.0)
    rho_fn = lambda t: tf.where(t < 1, 0., 0.5)
  
    process = sabr.SabrModel(
        beta=0.5, volvol=volvol_fn, rho=rho_fn, dtype=tf.float32)
  
    # Any time where parameters vary drastically (e.g. t=2 above) should be
    # added to `times` to reduce numerical error.
    paths = process.sample_paths(
        initial_forward=100,
        initial_volatility=0.05,
        times=[1,2,5],
        time_step=0.01,
        num_samples=10000)
  ```
  
  ### References:
  [1]: Chen B, Oosterlee CW, Van Der Weide H. Efficient unbiased simulation
  scheme for the SABR stochastic volatility model. 2011
  Link: http://ta.twi.tudelft.nl/mf/users/oosterle/oosterlee/SABRMC.pdf
  [2]: Andersen, Leif B.G., Efficient Simulation of the Heston Stochastic
  Volatility Model (January 23, 2007). Available at SSRN:
  https://ssrn.com/abstract=946405 or http://dx.doi.org/10.2139/ssrn.946405
class_docstr_tok: ["Implements","the","SABR","model","defined","by","the","following","equations",".","``","`","dF_t","=","v_t","*","F_t","^","beta","*","dW_","{","F",",","t","}","dv_t","=","volvol","*","v_t","*","dW_","{","v",",","t","}","dW_","{","F",",","t","}","*","dW_","{","v",",","t","}","=","rho","*","dt","``","`","`","F_t","`","is","the","forward",".","`","v_t","`","is","volatility",".","`","beta","`","is","the","CEV","parameter",".","`","volvol","`","is","volatility","of","volatility",".","`","W_","{","F",",","t","}","`","and","`","W_","{","v",",","t","}","`","are","two","correlated","Wiener","processes","with","instantaneous","correlation","`","rho","`",".","This","model","supports","time","dependent","parameters",".","In","other","words",",","`","beta","`",",","`","volvol","`",",","and","`","rho","`","can","be","functions","of","time",".","When","all","of","these","parameters","are","constants",",","`","beta","`","!","=","1",",","and","`","enable_unbiased_sampling","`","is","True",",","the","almost","exact","sampling","procedure","described","in","Ref","[","1","]","will","be","used",".","Otherwise","it","will","default","to","Euler","sampling",".","#","#","#","Example",".","Simple","example","with","time","independent","params",".","``","`","none","process","=","sabr.SabrModel","(","beta=0.5",",","volvol=1",",","rho=0.5",",","dtype=tf.float32",")","paths","=","process.sample_paths","(","initial_forward=100",",","initial_volatility=0.05",",","times=","[","1,2,5","]",",","time_step=0.01",",","num_samples=10000",")","``","`","#","#","#","Example","2",".","Callable","volvol","and","correlation","coefficient",".","``","`","none","volvol_fn","=","lambda","t",":","tf.where","(","t","<","2",",","0.5",",","1.0",")","rho_fn","=","lambda","t",":","tf.where","(","t","<","1",",","0.",",","0.5",")","process","=","sabr.SabrModel","(","beta=0.5",",","volvol=volvol_fn",",","rho=rho_fn",",","dtype=tf.float32",")","#","Any","time","where","parameters","vary","drastically","(","e.g",".","t=2","above",")","should","be","#","added","to","`","times","`","to","reduce","numerical","error",".","paths","=","process.sample_paths","(","initial_forward=100",",","initial_volatility=0.05",",","times=","[","1,2,5","]",",","time_step=0.01",",","num_samples=10000",")","``","`","#","#","#","References",":","[","1","]",":","Chen","B",",","Oosterlee","CW",",","Van","Der","Weide","H.","Efficient","unbiased","simulation","scheme","for","the","SABR","stochastic","volatility","model",".","2011","Link",":","http",":","\/\/ta.twi.tudelft.nl\/mf\/users\/oosterle\/oosterlee\/SABRMC.pdf","[","2","]",":","Andersen",",","Leif","B.G.",",","Efficient","Simulation","of","the","Heston","Stochastic","Volatility","Model","(","January","23",",","2007",")",".","Available","at","SSRN",":","https",":","\/\/ssrn.com\/abstract=946405","or","http",":","\/\/dx.doi.org\/10.2139\/ssrn.946405"]
docstr: Returns a sample of paths from the process.
docstr_tok: ["Returns","a","sample","of","paths","from","the","process","."]
code: def _sabr_sample_paths(
      self,
      initial_forward,
      initial_volatility,
      times,
      time_step,
      num_samples,
      random_type,
      seed,
      precompute_normal_draws,
      skip,
  ):
      """Returns a sample of paths from the process."""
      num_requested_times = tff_utils.get_shape(times)[0]
      # Prepare results format
      forward = (
          tf.zeros(shape=(num_samples,), dtype=self._dtype)
          + initial_forward
      )
      vol = (
          tf.zeros(shape=(num_samples,), dtype=self._dtype)
          + initial_volatility
      )
      if (
          isinstance(num_requested_times, int)
          and num_requested_times == 1
      ):
          record_samples = False
          forward_paths = forward
          vol_paths = vol
      else:
          # If more than one sample has to be recorded, create a TensorArray
          record_samples = True
          element_shape = forward.shape
          forward_paths = tf.TensorArray(
              dtype=times.dtype,
              size=num_requested_times,
              element_shape=element_shape,
              clear_after_read=False,
          )
          vol_paths = tf.TensorArray(
              dtype=times.dtype,
              size=num_requested_times,
              element_shape=element_shape,
              clear_after_read=False,
          )
      # Define sampling while_loop body function
      cond_fn = lambda index, *args: index < tf.size(times)
  
      # In order to use low-discrepancy random_type we need to generate the
      # sequence of independent random normals upfront. We also precompute random
      # numbers for stateless random type in order to ensure independent samples
      # for multiple function calls with different seeds.
      if precompute_normal_draws or random_type in (
          random.RandomType.SOBOL,
          random.RandomType.HALTON,
          random.RandomType.HALTON_RANDOMIZED,
          random.RandomType.STATELESS,
          random.RandomType.STATELESS_ANTITHETIC,
      ):
          num_time_steps = (
              tf.cast(
                  tf.math.ceil(tf.math.divide(times[-1], time_step)),
                  dtype=tf.int32,
              )
              + times.shape[0]
          )
          # We need a [3] + initial_forward.shape tensor of random draws.
          # This will be accessed by normal_draws_index.
          num_normal_draws = 3 * tf.size(initial_forward)
          normal_draws = utils.generate_mc_normal_draws(
              num_normal_draws=num_normal_draws,
              num_time_steps=num_time_steps,
              num_sample_paths=num_samples,
              random_type=random_type,
              seed=seed,
              skip=skip,
              dtype=self._dtype,
          )
      else:
          normal_draws = None
  
      def body_fn(
          index,
          current_time,
          forward,
          vol,
          forward_paths,
          vol_paths,
          normal_draws_index,
      ):
          """Simulate Sabr process to the next time point."""
          forward, vol, normal_draws_index = self._propagate_to_time(
              forward,
              vol,
              current_time,
              times[index],
              time_step,
              random_type,
              seed,
              normal_draws,
              normal_draws_index,
              num_time_steps,
          )
          # Always update paths in outer loop.
          if record_samples:
              # Update volatility paths
              vol_paths = vol_paths.write(index, vol)
              # Update forward paths
              forward_paths = forward_paths.write(index, forward)
          else:
              vol_paths = vol
              forward_paths = forward
          return (
              index + 1,
              times[index],
              forward,
              vol,
              forward_paths,
              vol_paths,
              normal_draws_index,
          )
  
      start_time = tf.constant(0, dtype=self._dtype)
      # Sample paths
      _, _, _, _, forward_paths, vol_paths, _ = tf.while_loop(
          cond_fn,
          body_fn,
          (0, start_time, forward, vol, forward_paths, vol_paths, 0),
          maximum_iterations=tf.size(times),
      )
      if not record_samples:
          # shape [num_samples, 1]
          vol_paths = tf.expand_dims(vol_paths, axis=-1)
          forward_paths = tf.expand_dims(forward_paths, axis=-1)
          # shape [num_samples, 1, 1]
          return tf.stack([forward_paths, vol_paths], -1)
      # Shape [num_time_points] + [num_samples]
      vol_paths = vol_paths.stack()
      forward_paths = forward_paths.stack()
      # transpose to shape [num_samples, num_time_points]
      vol_paths = tf.transpose(vol_paths)
      forward_paths = tf.transpose(forward_paths)
      # Shape [num_samples, num_time_points, 2]
      return tf.stack([forward_paths, vol_paths], -1)
  
file_path: tf-quant-finance/tf_quant_finance/models/sabr/sabr_model.py
imports: from typing import Optional
  import tensorflow.compat.v2
  from tf_quant_finance import types
  from tf_quant_finance import utils
  from tf_quant_finance.math import random_ops
  from tf_quant_finance.math.root_search.newton import root_finder
  from tf_quant_finance.models import generic_ito_process
  from tf_quant_finance.models import utils
label_desc: Use image node_id 3 for calling the SabrModel obj's underlying member method code with example usage: obj._sabr_sample_paths(initial_forward, initial_volatility, times, time_step, num_samples, random_type, seed, precompute_normal_draws, skip) and returns: tf, unknown,  times,  forward,  vol,  forward_paths,  vol_paths,  normal_draws_index, tf