code: def sample(
      dim: int,
      num_results: types.IntTensor = None,
      sequence_indices: types.IntTensor = None,
      randomized: bool = True,
      randomization_params=None,
      seed: types.IntTensor = None,
      validate_args: bool = False,
      dtype: tf.DType = None,
      name: str = None,
  ) -> types.RealTensor:
      r"""Returns a sample from the `dim` dimensional Halton sequence.
  
      Warning: The sequence elements take values only between 0 and 1. Care must be
      taken to appropriately transform the domain of a function if it differs from
      the unit cube before evaluating integrals using Halton samples. It is also
      important to remember that quasi-random numbers without randomization are not
      a replacement for pseudo-random numbers in every context. Quasi random numbers
      are completely deterministic and typically have significant negative
      autocorrelation unless randomization is used.
  
      Computes the members of the low discrepancy Halton sequence in dimension
      `dim`. The `dim`-dimensional sequence takes values in the unit hypercube in
      `dim` dimensions. Currently, only dimensions up to 1000 are supported. The
      prime base for the k-th axes is the k-th prime starting from 2. For example,
      if `dim` = 3, then the bases will be [2, 3, 5] respectively and the first
      element of the non-randomized sequence will be: [0.5, 0.333, 0.2]. For a more
      complete description of the Halton sequences see
      [here](https://en.wikipedia.org/wiki/Halton_sequence). For low discrepancy
      sequences and their applications see
      [here](https://en.wikipedia.org/wiki/Low-discrepancy_sequence).
  
      If `randomized` is true, this function produces a scrambled version of the
      Halton sequence introduced by [Owen (2017)][1]. For the advantages of
      randomization of low discrepancy sequences see [here](
      https://en.wikipedia.org/wiki/Quasi-Monte_Carlo_method#Randomization_of_quasi-Monte_Carlo).
  
      The number of samples produced is controlled by the `num_results` and
      `sequence_indices` parameters. The user must supply either `num_results` or
      `sequence_indices` but not both.
      The former is the number of samples to produce starting from the first
      element. If `sequence_indices` is given instead, the specified elements of
      the sequence are generated. For example, sequence_indices=tf.range(10) is
      equivalent to specifying n=10.
  
      #### Examples
  
      ```python
      import tensorflow.compat.v2 as tf
      import tensorflow_probability as tfp
  
      # Produce the first 1000 members of the Halton sequence in 3 dimensions.
      num_results = 1000
      dim = 3
      sample, params = qmc.halton.sample(
        dim,
        num_results=num_results,
        seed=127)
  
      # Evaluate the integral of x_1 * x_2^2 * x_3^3  over the three dimensional
      # hypercube.
      powers = tf.range(1.0, limit=dim + 1)
      integral = tf.reduce_mean(tf.reduce_prod(sample ** powers, axis=-1))
      true_value = 1.0 / tf.reduce_prod(powers + 1.0)
      with tf.Session() as session:
        values = session.run((integral, true_value))
  
      # Produces a relative absolute error of 1.7%.
      print ("Estimated: %f, True Value: %f" % values)
  
      # Now skip the first 1000 samples and recompute the integral with the next
      # thousand samples. The sequence_indices argument can be used to do this.
  
  
      sequence_indices = tf.range(start=1000, limit=1000 + num_results,
                                  dtype=tf.int32)
      sample_leaped, _ = qmc.halton.sample(
          dim,
          sequence_indices=sequence_indices,
          randomization_params=params)
  
      integral_leaped = tf.reduce_mean(tf.reduce_prod(sample_leaped ** powers,
                                                      axis=-1))
      with tf.Session() as session:
        values = session.run((integral_leaped, true_value))
      # Now produces a relative absolute error of 0.05%.
      print ("Leaped Estimated: %f, True Value: %f" % values)
      ```
  
      Args:
        dim: Positive Python `int` representing each sample's `event_size.` Must not
          be greater than 1000.
        num_results: (Optional) Positive scalar `Tensor` of dtype int32. The number
          of samples to generate. Either this parameter or sequence_indices must be
          specified but not both. If this parameter is None, then the behaviour is
          determined by the `sequence_indices`.
          Default value: `None`.
        sequence_indices: (Optional) `Tensor` of dtype int32 and rank 1. The
          elements of the sequence to compute specified by their position in the
          sequence. The entries index into the Halton sequence starting with 0 and
          hence, must be whole numbers. For example, sequence_indices=[0, 5, 6] will
          produce the first, sixth and seventh elements of the sequence. If this
          parameter is None, then the `num_results` parameter must be specified
          which gives the number of desired samples starting from the first sample.
          Default value: `None`.
        randomized: (Optional) bool indicating whether to produce a randomized
          Halton sequence. If True, applies the randomization described in [Owen
          (2017)][1]. If True, either seed or randomization_params must be
          specified. This is because the randomization uses stateless random number
          generation which requires an explicitly specified seed.
          Default value: `True`.
        randomization_params: (Optional) Instance of `HaltonParams` that fully
          describes the randomization behavior. If provided and randomized is True,
          seed will be ignored and these will be used instead of computing them from
          scratch. If randomized is False, this parameter has no effect.
          Default value: `None`. In this case with randomized = True, the necessary
            randomization parameters will be computed from scratch.
        seed: (Optional) Python integer to seed the random number generator. Must be
          specified if `randomized` is True and randomization_params is not
          specified. Ignored if randomized is False or randomization_params is
          specified.
          Default value: `None`.
        validate_args: If True, checks that maximum index is not exceeded and that
          the dimension `dim` is less than 1 or greater than 1000.
          Default value: `False`.
        dtype: Optional `dtype`. The dtype of the output `Tensor` (either `float32`
        or `float64`).
          Default value: `None` which maps to the `float32`.
        name:  (Optional) Python `str` describing ops managed by this function. If
          not supplied the name of this function is used.
          Default value: "halton_sample".
  
      Returns:
        halton_elements: Elements of the Halton sequence. `Tensor` of supplied dtype
          and `shape` `[num_results, dim]` if `num_results` was specified or shape
          `[s, dim]` where s is the size of `sequence_indices` if `sequence_indices`
          were specified.
        randomization_params: None if randomized is False. If randomized is True
          and randomization_params was supplied as an argument, returns that.
          Otherwise returns the computed randomization_params, an instance of
          `HaltonParams` that fully describes the randomization behavior.
  
      Raises:
        ValueError: if both `sequence_indices` and `num_results` were specified.
        ValueError: if `randomization` is True but `seed` is not specified.
        InvalidArgumentError: if `validate_args` is True and the maximum supported
          sequence index is exceeded.
  
      #### References
  
      [1]: Art B. Owen. A randomized Halton algorithm in R. _arXiv preprint
           arXiv:1706.02808_, 2017. https://arxiv.org/abs/1706.02808
      """
      if (num_results is None) == (sequence_indices is None):
          raise ValueError(
              "Either `num_results` or `sequence_indices` must be"
              " specified but not both."
          )
      dtype = dtype or tf.float32
  
      with tf.compat.v1.name_scope(
          name, "halton_sample", values=[num_results, sequence_indices]
      ):
          # Here and in the following, the shape layout is as follows:
          # [sample dimension, event dimension, coefficient dimension].
          # The coefficient dimension is an intermediate axes which will hold the
          # weights of the starting integer when expressed in the (prime) base for
          # an event dimension.
          if num_results is not None:
              num_results = tf.convert_to_tensor(
                  value=num_results, dtype=tf.int32, name="name_results"
              )
          if sequence_indices is not None:
              sequence_indices = tf.convert_to_tensor(
                  value=sequence_indices,
                  dtype=tf.int32,
                  name="sequence_indices",
              )
          indices = _get_indices(num_results, sequence_indices, dtype)
  
          runtime_assertions = []
          if validate_args:
              runtime_assertions.append(
                  tf.compat.v1.assert_less_equal(
                      tf.reduce_max(indices),
                      tf.constant(
                          _MAX_INDEX_BY_DTYPE[dtype], dtype=dtype
                      ),
                      message=(
                          "Maximum sequence index exceeded. Maximum index for dtype %s "
                          "is %d." % (dtype, _MAX_INDEX_BY_DTYPE[dtype])
                      ),
                  )
              )
              runtime_assertions.append(
                  tf.compat.v1.assert_greater_equal(
                      dim, 1, message="`dim` should be greater than 1"
                  )
              )
              runtime_assertions.append(
                  tf.compat.v1.assert_less_equal(
                      dim,
                      _MAX_DIMENSION,
                      message="`dim` should be less or equal than %d"
                      % _MAX_DIMENSION,
                  )
              )
  
          with tf.compat.v1.control_dependencies(runtime_assertions):
              radixes = tf.convert_to_tensor(
                  _PRIMES, dtype=dtype, name="radixes"
              )
              radixes = tf.reshape(radixes[0:dim], shape=[dim, 1])
  
              max_sizes_by_axes = tf.convert_to_tensor(
                  _MAX_SIZES_BY_AXES[dtype],
                  dtype=dtype,
                  name="max_sizes_by_axes",
              )[:dim]
              max_size = tf.reduce_max(max_sizes_by_axes)
  
              # The powers of the radixes that we will need. Note that there is a bit
              # of an excess here. Suppose we need the place value coefficients of 7
              # in base 2 and 3. For 2, we will have 3 digits but we only need 2 digits
              # for base 3. However, we can only create rectangular tensors so we
              # store both expansions in a [2, 3] tensor. This leads to the problem that
              # we might end up attempting to raise large numbers to large powers. For
              # example, base 2 expansion of 1024 has 10 digits. If we were in 10
              # dimensions, then the 10th prime (29) we will end up computing 29^10 even
              # though we don't need it. We avoid this by setting the exponents for each
              # axes to 0 beyond the maximum value needed for that dimension.
              exponents_by_axes = tf.tile(
                  [tf.range(max_size, dtype=dtype)], [dim, 1]
              )
  
              # The mask is true for those coefficients that are irrelevant.
              weight_mask = exponents_by_axes >= max_sizes_by_axes
              capped_exponents = tf.where(
                  weight_mask,
                  tf.zeros_like(exponents_by_axes),
                  exponents_by_axes,
              )
              # Round to nearest integer to correct small errors when applying floating-
              # point pow(radixes, capped_exponents).
              weights = tf.compat.v1.round(radixes**capped_exponents)
              # The following computes the base b expansion of the indices. Suppose,
              # x = a0 + a1*b + a2*b^2 + ... Then, performing a floor div of x with
              # the vector (1, b, b^2, b^3, ...) will produce
              # (a0 + s1 * b, a1 + s2 * b, ...) where s_i are coefficients we don't care
              # about. Noting that all a_i < b by definition of place value expansion,
              # we see that taking the elements mod b of the above vector produces the
              # place value expansion coefficients.
              coeffs = tf.compat.v1.floor_div(indices, weights)
              coeffs *= 1.0 - tf.cast(weight_mask, dtype)
              coeffs %= radixes
              if not randomized:
                  coeffs /= radixes
                  return (
                      tf.reduce_sum(
                          input_tensor=coeffs / weights, axis=-1
                      ),
                      None,
                  )
  
              if randomization_params is None:
                  perms, zero_correction = None, None
              else:
                  perms, zero_correction = randomization_params
              coeffs, perms = _randomize(
                  coeffs, radixes, seed, perms=perms
              )
              # Remove the contribution from randomizing the trailing zero for the
              # axes where max_size_by_axes < max_size. This will be accounted
              # for separately below (using zero_correction).
              coeffs *= 1.0 - tf.cast(weight_mask, dtype)
              coeffs /= radixes
              base_values = tf.reduce_sum(
                  input_tensor=coeffs / weights, axis=-1
              )
  
              # The randomization used in Owen (2017) does not leave 0 invariant. While
              # we have accounted for the randomization of the first `max_size_by_axes`
              # coefficients, we still need to correct for the trailing zeros. Luckily,
              # this is equivalent to adding a uniform random value scaled so the first
              # `max_size_by_axes` coefficients are zero. The following statements
              # perform this correction.
              if zero_correction is None:
                  if seed is None:
                      zero_correction = tf.random.uniform(
                          [dim, 1], dtype=dtype
                      )
                  else:
                      zero_correction = tf.random.stateless_uniform(
                          [dim, 1], seed=(seed, seed), dtype=dtype
                      )
                  zero_correction /= radixes**max_sizes_by_axes
                  zero_correction = tf.reshape(zero_correction, [-1])
  
              return base_values + zero_correction, HaltonParams(
                  perms, zero_correction
              )
  
file_path: tf-quant-finance/tf_quant_finance/math/random_ops/halton/halton_impl.py
imports: import numpy
  import tensorflow.compat.v2
  from tf_quant_finance import types
  from tf_quant_finance import utils
  from tf_quant_finance.math.random_ops import stateless
label_desc: Use image node_id 1 for calling a global function with example usage: sample(dim, num_results, sequence_indices, randomized, randomization_params, seed, validate_args, dtype, name) and returns: unknown,  HaltonParams, tf,  None