Skip to main content
`Ctrl`+`K`
scipy.stats.qmc.

# QMCEngine

class scipy.stats.qmc.QMCEngine(d, *, optimization=None, rng=None)

  A generic Quasi-Monte Carlo sampler class meant for subclassing.

  QMCEngine is a base class to construct a specific Quasi-Monte Carlo sampler. It cannot be used directly as a sampler.

  Parameters:
    d int

      Dimension of the parameter space.

    optimization{None, “random-cd”, “lloyd”}, optional

      Whether to use an optimization scheme to improve the quality after sampling. Note that this is a post-processing step that does not guarantee that all properties of the sample will be conserved. Default is None.

      - `random-cd`: random permutations of coordinates to lower the centered discrepancy. The best sample based on the centered discrepancy is constantly updated. Centered discrepancy-based sampling shows better space-filling robustness toward 2D and 3D subprojections compared to using other discrepancy measures.

      - `lloyd`: Perturb samples using a modified Lloyd-Max algorithm. The process converges to equally spaced samples.

      Added in version 1.10.0.

    rng `numpy.random.Generator`, optional

      Pseudorandom number generator state. When rng is None, a new `numpy.random.Generator` is created using entropy from the operating system. Types other than `numpy.random.Generator` are passed to `numpy.random.default_rng` to instantiate a `Generator`.

      Changed in version 1.15.0: As part of the SPEC-007 transition from use of `numpy.random.RandomState` to `numpy.random.Generator`, this keyword was changed from seed to rng. For an interim period, both keywords will continue to work, although only one may be specified at a time. After the interim period, function calls using the seed keyword will emit warnings. Following a deprecation period, the seed keyword will be removed.

  Methods

  `fast_forward`(n) | Fast-forward the sequence by n positions.
  `integers`(l_bounds, *[, u_bounds, n, ...]) | Draw n integers from l_bounds (inclusive) to u_bounds (exclusive), or if endpoint=True, l_bounds (inclusive) to u_bounds (inclusive).
  `random`([n, workers]) | Draw n in the half-open interval `[0, 1)`.
  `reset`() | Reset the engine to base state.

  Notes

  By convention samples are distributed over the half-open interval `[0, 1)`. Instances of the class can access the attributes: `d` for the dimension; and `rng` for the random number generator.

  Subclassing

  When subclassing `QMCEngine` to create a new sampler, `__init__` and `random` must be redefined.

  - `__init__(d, rng=None)`: at least fix the dimension. If the sampler does not take advantage of a `rng` (deterministic methods like Halton), this parameter can be omitted.

  - `_random(n, *, workers=1)`: draw `n` from the engine. `workers` is used for parallelism. See `Halton` for example.

  Optionally, two other methods can be overwritten by subclasses:

  - `reset`: Reset the engine to its original state.

  - `fast_forward`: If the sequence is deterministic (like Halton sequence), then `fast_forward(n)` is skipping the `n` first draw.

  Examples

  To create a random sampler based on `np.random.random`, we would do the following:

      >>> from scipy.stats import qmc
      >>> class RandomEngine(qmc.QMCEngine):
      ...     def __init__(self, d, rng=None):
      ...         super().__init__(d=d, rng=rng)
      ...
      ...
      ...     def _random(self, n=1, *, workers=1):
      ...         return self.rng.random((n, self.d))
      ...
      ...
      ...     def reset(self):
      ...         super().__init__(d=self.d, rng=self.rng_seed)
      ...         return self
      ...
      ...
      ...     def fast_forward(self, n):
      ...         self.random(n)
      ...         return self

  After subclassing `QMCEngine` to define the sampling strategy we want to use, we can create an instance to sample from.

      >>> engine = RandomEngine(2)
      >>> engine.random(5)
      array([[0.22733602, 0.31675834],  # random
             [0.79736546, 0.67625467],
             [0.39110955, 0.33281393],
             [0.59830875, 0.18673419],
             [0.67275604, 0.94180287]])

  We can also reset the state of the generator and resample again.

      >>> _ = engine.reset()
      >>> engine.random(5)
      array([[0.22733602, 0.31675834],  # random
             [0.79736546, 0.67625467],
             [0.39110955, 0.33281393],
             [0.59830875, 0.18673419],
             [0.67275604, 0.94180287]])