class scipy.stats.qmc.QMCEngine(d, *, optimization=None, seed=None)[source]#

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.


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.

New in version 1.10.0.

seed{None, int, numpy.random.Generator}, optional

If seed is an int or None, a new numpy.random.Generator is created using np.random.default_rng(seed). If seed is already a Generator instance, then the provided instance is used.


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 (used for the seed).


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

  • __init__(d, seed=None): at least fix the dimension. If the sampler does not take advantage of a seed (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.


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, seed=None):
...         super().__init__(d=d, seed=seed)
...     def _random(self, n=1, *, workers=1):
...         return self.rng.random((n, self.d))
...     def reset(self):
...         super().__init__(d=self.d, seed=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]])



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 the engine to base state.