class_docstr: Base class for Ito processes.
  
    Represents a general Ito process:
  
    ```None
      dX_i = a_i(t, X) dt + Sum(S_{ij}(t, X) dW_j for 1 <= j <= n), 1 <= i <= n
    ```
  
  The vector coefficient `a_i` is referred to as the drift of the process and
  the matrix `S_{ij}` as the volatility of the process. For the process to be
  well defined, these coefficients need to satisfy certain technical conditions
  which may be found in Ref. [1]. The vector `dW_j` represents independent
  Brownian increments.
  
  #### Example. 2-dimensional Ito process of the form
  
  ```none
  dX_1 = mu_1 * sqrt(t) dt + s11 * dW_1 + s12 * dW_2
  dX_2 = mu_2 * sqrt(t) dt + s21 * dW_1 + s22 * dW_2
  ```
  
  class SimpleItoProcess(ito_process.ItoProcess):
    def __init__(self, dim, drift_fn, vol_fn, dtype=tf.float64):
      self._dim = dim
      self._drift_fn = drift_fn
      self._vol_fn = vol_fn
      self._dtype = dtype
  
    def dim(self):
      return self._dim
  
    def drift_fn(self):
      return self._drift_fn
  
    def volatility_fn(self):
      return self._vol_fn
  
    def dtype(self):
      return self._dtype
  
    def name(self):
      return 'simple_ito_process'
  
  mu = np.array([0.2, 0.7])
  s = np.array([[0.3, 0.1], [0.1, 0.3]])
  num_samples = 10000
  dim = 2
  dtype=tf.float64
  
  # Define drift and volatility functions
  def drift_fn(t, x):
    return mu * tf.sqrt(t) * tf.ones([num_samples, dim], dtype=dtype)
  
  def vol_fn(t, x):
    return s * tf.ones([num_samples, dim, dim], dtype=dtype)
  
  # Initialize `SimpleItoProcess`
  process = SimpleItoProcess(dim=2, drift_fn=drift_fn, vol_fn=vol_fn,
                             dtype=dtype)
  # Set starting location
  x0 = np.array([0.1, -1.1])
  # Sample `num_samples` paths at specified `times` locations using built-in
  # Euler scheme.
  times = [0.1, 1.0, 2.0]
  paths = process.sample_paths(
            times,
            num_samples=num_samples,
            initial_state=x0,
            grid_step=0.01,
            seed=42)
  
  #### References
  [1]: Brent Oksendal. Stochastic Differential Equations: An Introduction with
    Applications. Springer. 2010.
docstr: Returns a sample of paths from the process.
docstr_tok: ["Returns","a","sample","of","paths","from","the","process","."]
code: def _sample_paths(
      self,
      times,
      grid_step,
      keep_mask,
      num_requested_times,
      num_samples,
      initial_state,
      random_type,
      seed,
      swap_memory,
  ):
      """Returns a sample of paths from the process."""
      dt = times[1:] - times[:-1]
      sqrt_dt = tf.sqrt(dt)
      current_state = initial_state + tf.zeros(
          [num_samples, self.dim()], dtype=initial_state.dtype
      )
      steps_num = tf.shape(dt)[-1]
      wiener_mean = tf.zeros((self.dim(), 1), dtype=self._dtype)
  
      cond_fn = lambda i, *args: i < steps_num
  
      def step_fn(i, written_count, current_state, result):
          """Performs one step of Euler scheme."""
          current_time = times[i + 1]
          dw = random_ops.mv_normal_sample(
              (num_samples,),
              mean=wiener_mean,
              random_type=random_type,
              seed=seed,
          )
          dw = dw * sqrt_dt[i]
          dt_inc = dt[i] * self.drift_fn()(
              current_time, current_state
          )  # pylint: disable=not-callable
          dw_inc = tf.squeeze(
              tf.matmul(
                  self.volatility_fn()(current_time, current_state), dw
              ),
              -1,
          )  # pylint: disable=not-callable
          next_state = current_state + dt_inc + dw_inc
  
          def write_next_state_to_result():
              # Replace result[:, written_count, :] with next_state.
              one_hot = tf.one_hot(
                  written_count, depth=num_requested_times
              )
              mask = tf.expand_dims(one_hot > 0, axis=-1)
              return tf.where(
                  mask, tf.expand_dims(next_state, axis=1), result
              )
  
          # Keep only states for times requested by user.
          result = tf.cond(
              keep_mask[i + 1],
              write_next_state_to_result,
              lambda: result,
          )
          written_count += tf.cast(keep_mask[i + 1], dtype=tf.int32)
          return i + 1, written_count, next_state, result
  
      # Maximum number iterations is passed to the while loop below. It improves
      # performance of the while loop on a GPU and is needed for XLA-compilation
      # comptatiblity
      maximum_iterations = tf.cast(
          1.0 / grid_step, dtype=tf.int32
      ) + tf.size(times)
      result = tf.zeros((num_samples, num_requested_times, self.dim()))
      _, _, _, result = tf.compat.v1.while_loop(
          cond_fn,
          step_fn,
          (0, 0, current_state, result),
          maximum_iterations=maximum_iterations,
          swap_memory=swap_memory,
      )
  
      return result
  
file_path: tf-quant-finance/tf_quant_finance/models/legacy/ito_process.py
imports: import abc
  import six
  import tensorflow.compat.v2
  from tf_quant_finance.math import random_ops
label_desc: Use image node_id 8 for calling the ItoProcess obj's underlying member method code with example usage: obj._sample_paths(times, grid_step, keep_mask, num_requested_times, num_samples, initial_state, random_type, seed, swap_memory) and returns: result, unknown,  written_count,  next_state,  result, tf