code: def generate_mc_normal_draws(
      num_normal_draws,
      num_time_steps,
      num_sample_paths,
      random_type,
      batch_shape=None,
      skip=0,
      seed=None,
      dtype=None,
      name=None,
  ):
      """Generates normal random samples to be consumed by a Monte Carlo algorithm.
  
      Many of Monte Carlo (MC) algorithms can be re-written so that all necessary
      random (or quasi-random) variables are drawn in advance as a `Tensor` of
      shape `batch_shape + [num_time_steps, num_samples, num_normal_draws]`, where
      `batch_shape` is the shape of the independent batches of the Monte Carlo
      algorithm, `num_time_steps` is the number of time steps Monte Carlo algorithm
      performs within each batch, `num_sample_paths` is a number of sample paths of
      the Monte Carlo algorithm and `num_normal_draws` is a number of independent
      normal draws per sample path.
      For example, in order to use quasi-random numbers in a Monte Carlo algorithm,
      the samples have to be drawn in advance.
      The function generates a `Tensor`, say, `x` in a format such that for a
      quasi-`random_type` `x[i]` is correspond to different dimensions of the
      quasi-random sequence, so that it can be used in a Monte Carlo algorithm
  
      Args:
        num_normal_draws: A scalar int32 `Tensor`. The number of independent normal
          draws at each time step for each sample path. Should be a graph
          compilation constant.
        num_time_steps: A scalar int32 `Tensor`. The number of time steps at which
          to draw the independent normal samples. Should be a graph compilation
          constant.
        num_sample_paths: A scalar int32 `Tensor`. The number of trajectories (e.g.,
          Monte Carlo paths) for which to draw the independent normal samples.
          Should be a graph compilation constant.
        random_type: Enum value of `tff.math.random.RandomType`. The type of
          (quasi)-random number generator to use to generate the paths.
        batch_shape: This input can be either of type `tf.TensorShape` or a 1-d
          `Tensor` of type `tf.int32` specifying the dimensions of independent
          batches of normal samples to be drawn.
          Default value: `None` which correspond to a single batch of shape
          `tf.TensorShape([])`.
        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`.
          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]`.
            Default value: `None` which means no seed is set.
        dtype: The `dtype` of the output `Tensor`.
          Default value: `None` which maps to `float32`.
        name: Python string. The name to give this op.
          Default value: `None` which maps to `generate_mc_normal_draws`.
  
      Returns:
       A `Tensor` of shape
       `[num_time_steps] + batch_shape + [num_sample_paths, num_normal_draws]`.
      """
      if name is None:
          name = "generate_mc_normal_draws"
      if skip is None:
          skip = 0
      with tf.name_scope(name):
          if dtype is None:
              dtype = tf.float32
          if batch_shape is None:
              batch_shape = tf.TensorShape([])
  
          # In case of quasi-random draws, the total dimension of the draws should be
          # `num_time_steps * dim`
          total_dimension = tf.zeros(
              [num_time_steps * num_normal_draws],
              dtype=dtype,
              name="total_dimension",
          )
          if random_type in [
              random.RandomType.PSEUDO_ANTITHETIC,
              random.RandomType.STATELESS_ANTITHETIC,
          ]:
              # Put `num_sample_paths` to the front for antithetic samplers
              sample_shape = tf.concat(
                  [[num_sample_paths], batch_shape], axis=0
              )
              is_antithetic = True
          else:
              # Note that for QMC sequences `num_sample_paths` should follow
              # `batch_shape`
              sample_shape = tf.concat(
                  [batch_shape, [num_sample_paths]], axis=0
              )
              is_antithetic = False
          normal_draws = random.mv_normal_sample(
              sample_shape,
              mean=total_dimension,
              random_type=random_type,
              seed=seed,
              skip=skip,
          )
          # Reshape and transpose
          normal_draws = tf.reshape(
              normal_draws,
              tf.concat(
                  [sample_shape, [num_time_steps, num_normal_draws]],
                  axis=0,
              ),
          )
          # Shape [steps_num] + batch_shape + [num_samples, dim]
          normal_draws_rank = normal_draws.shape.rank
          if is_antithetic and normal_draws_rank > 3:
              # Permutation for the case when the batch_shape is present
              perm = (
                  [normal_draws_rank - 2]
                  + list(range(1, normal_draws_rank - 2))
                  + [0, normal_draws_rank - 1]
              )
          else:
              perm = (
                  [normal_draws_rank - 2]
                  + list(range(normal_draws_rank - 2))
                  + [normal_draws_rank - 1]
              )
          normal_draws = tf.transpose(normal_draws, perm=perm)
          return normal_draws
  
file_path: tf-quant-finance/tf_quant_finance/models/utils.py
imports: import tensorflow.compat.v2
  from tf_quant_finance.math import random_ops
label_desc: Use image node_id 1 for calling a global function with example usage: generate_mc_normal_draws(num_normal_draws, num_time_steps, num_sample_paths, random_type, batch_shape, skip, seed, dtype, name) and returns: normal_draws