moocore.

generate_sequence#

moocore.generate_sequence(n, d, /, method, *, seed=None, integer=False, n_rep=0, ndsort=0, c_value=0.9, r_min=0.0)[source]#

Generate a sequence of n points of dimension d with the properties defined by method.

When ndsort=1, the points are sorted according to their Pareto rank using pareto_rank(). With ndsort=-1, the order is reversed. The ranking assumes that all dimensions are minimised.

When integer=False (the default), the points are generated within the hypercube \((0,1)^d\), except for method="glas2017", which may generate points outside this range. These points can be scaled to another range using normalise().

When integer=True, points are scaled to the non-negative integers in the range \([0,2^{31}]\), except for method="glas2017", which may generate points outside this range.

Parameters:
  • n (int) – Number of rows in the output.

  • d (int) – Number of columns in the output.

  • method (str) – Method used to generate the point sequence. See the Notes below for more details.

  • seed (int | Generator | None) – Either an integer to seed numpy.random.default_rng(), a Numpy default random number generator (RNG) or an instance of a Numpy-compatible RNG. None uses the equivalent of a random seed, as in numpy.random.default_rng(). (default: None)

  • integer (bool) – If True, return integer-valued points. (default: False)

  • n_rep (int) – If non-zero, then repeat the generated sequence so that the output will have n_rep rows. If 0 < n_rep <= n, raise ValueError. (default: 0)

  • ndsort (int) – Whether points are sorted according to Pareto rank (1), sorted in reverse (-1) or not sorted at all (0). (default: 0)

  • c_value (float) – Parameter of method="glas2017. It controls the probability of a dominated point appearing earlier in the sequence than a nondominated one, with c = 1 giving equal probability, c > 1 increasing the probability of dominated points and c < 1 increasing the probability of nondominated ones. (default: 0.9)

  • r_min (float) – Minimum distance to the origin (method="sphere only). (default: 0.0)

Returns:

ndarray – A numeric matrix of size \(n \times d\) containing a sequence of points.

See also

generate_ndset

Generate a nondominated set.

Notes

The available methods are:

'cube'

Uniformly samples points within the unit hypercube \((0,1)^d\).

'sphere'

Uniformly samples points within the positive orthant of the unit hypersphere.

Each point \(\vec{z} \in (0,1)^d \subset \mathbb{R}^d\) is generated by sampling \(d\) independent and identically distributed values \(\vec{x}=(x_1,x_2, \dots, x_d)\) from the standard normal distribution, then dividing each value by the l2-norm of the vector, \(z_i = \frac{|x_i|}{\|\vec{x}\|_2}\) [1]. The absolute value in the numerator ensures that points are sampled on the surface of the positive orthant of the hypersphere. Then each point is moved into the interior of the hypersphere by sampling \(\vec{u} \in \mathbb{R}^d\), with each component uniformly sampled within the interval \((r_\min^d, 1)\), and returning \(\vec{z}\cdot \sqrt[d]{u}\). The \(d\)-root transformation avoids biasing the distribution towards the origin. Parameter \(r_\min\) (r_min) restricts the minimum distance to the origin.

'each_dominates_previous'|'each_dominates_next'

Each point in the sequence dominates the previous or next one.

A matrix \(n\times d\) is sampled uniformly within \((0,1)\). Then, each column is sorted independently in increasing (each_dominates_next') or decreasing (each_dominates_previous') order. Argument ndsort has no effect for these sequences because they already sorted.

'glas2017'

Generate objective vectors following the analytic sequence model of Section 6.1 in Glasmachers[2].

This model constructs a sequence \(\vec{z}^(k) \in \mathbb{R}^d\) of length \(N\), where \(D=\lfloor fN \rfloor\) points are dominated by another point in the sequence and \(N - D\) are nondominated, and \(f=0.5\) in our implementation. First, points \(\vec{x}^{(k)}\), \(\forall k=1,\dots,N\), are generated by sampling \(N \times d\) independent values from the standard normal distribution. Second, these points are projected onto the \((d-1)\)-dimensional hyperplane that satisfies \(\{\vec{x}\in\mathbb{R}^d\mid \sum_{i=1}^d x_i = 0\}\) by calculating \(\vec{y}^{(k)} = \vec{x}^{(k)} - \bar{x}^{(k)}\), where \(\bar{x} = \frac{1}{d}\sum_{i=1}^d x_i\). Finally, the projected points are shifted by a constant amount in all dimensions \(\vec{z}^{(k)} = \vec{y}^{(k)} + a^{(k)}\), so that exactly \(D\) points become dominated, with

\[\begin{split}a^{(k)}=\begin{cases}\frac{\delta N}{k} & \text{if }D_k = 1,\\ 0 & \text{otherwise}.\end{cases}\end{split}\]

where \(D_k \in \{0,1\}\) determines whether point \(k\) is marked dominated and \(\delta = 1\) in our implementation.

Point \(k\) is marked dominated \((D_k=1)\) with probability \(c\frac{n^\text{dom}_k}{n_k}\), where \(n^\text{dom}_k = D - \sum_{i=1}^{k-1}D_k\), that is, the remaining points needed to reach \(D\) dominated points in the sequence, and \(n_k = N - k + 1\), that is, the remaining points in the sequence. The parameter \(c\) (c_value) controls the probability of having dominated points early in the sequence, with \(c > 1\) increasing this probability and \(c = 1\) giving equal probability to dominated and nondominated points.

The argument ndsort=1 sorts the sequence according to Pareto rank using pareto_rank(), or in reverse order with ndsort=-1. That is, earlier points in the sequence will have a lower (or higher in reverse order) or equal rank than later points. Algorithms that expect points to have increasing quality should perform worse with ndsort=1, whereas algorithms that expect new points to be often dominated by previous ones should perform worse with ndsort=-1.

References

Examples

Points within the unit 2D-sphere, i.e., within the circle:

>>> generate_sequence(5, 2, "sphere", ndsort=0, seed=42)
array([[0.17121976, 0.58436446],
       [0.60040891, 0.75251188],
       [0.66741195, 0.44545079],
       [0.33995168, 0.84094855],
       [0.01311259, 0.66576442]])

Points within the unit 2D-cube, i.e., unit square, sorted by increasing Pareto rank:

>>> generate_sequence(5, 2, "cube", ndsort=1, seed=42)
array([[0.77395605, 0.43887844],
       [0.09417735, 0.97562235],
       [0.12811363, 0.45038594],
       [0.85859792, 0.69736803],
       [0.7611397 , 0.78606431]])

Same points but in different order:

>>> generate_sequence(5, 2, "cube", ndsort=-1, seed=42)
array([[0.85859792, 0.69736803],
       [0.7611397 , 0.78606431],
       [0.77395605, 0.43887844],
       [0.09417735, 0.97562235],
       [0.12811363, 0.45038594]])

We can add duplicated points to the sequence by repeating it:

>>> generate_sequence(5, 2, "cube", ndsort=-1, seed=42, n_rep=11)
array([[0.85859792, 0.69736803],
       [0.7611397 , 0.78606431],
       [0.77395605, 0.43887844],
       [0.09417735, 0.97562235],
       [0.12811363, 0.45038594],
       [0.85859792, 0.69736803],
       [0.7611397 , 0.78606431],
       [0.77395605, 0.43887844],
       [0.09417735, 0.97562235],
       [0.12811363, 0.45038594],
       [0.85859792, 0.69736803]])

These two sequences are already sorted, so ndsort is not needed:

>>> generate_sequence(5, 2, "each_dominates_previous", seed=42)
array([[0.85859792, 0.97562235],
       [0.77395605, 0.78606431],
       [0.7611397 , 0.69736803],
       [0.12811363, 0.45038594],
       [0.09417735, 0.43887844]])
>>> generate_sequence(5, 2, "each_dominates_next", seed=42)
array([[0.09417735, 0.43887844],
       [0.12811363, 0.45038594],
       [0.7611397 , 0.69736803],
       [0.77395605, 0.78606431],
       [0.85859792, 0.97562235]])

A more complicated sequence, not in the unit cube:

>>> generate_sequence(5, 2, "glas2017", seed=42)
array([[-0.32442784,  0.32442784],
       [ 2.7220415 ,  2.2779585 ],
       [ 0.41812139, -0.41812139],
       [ 0.05080302, -0.05080302],
       [ 0.46939475,  1.53060525]])

Instead of floating-point values, we can generate an integer matrix:

>>> generate_sequence(5, 2, "cube", ndsort=1, seed=42, integer=True)
array([[1662057958,  942484272],
       [ 202244314, 2095133046],
       [ 275121931,  967196436],
       [1843824993, 1497586439],
       [1634535063, 1688060241]])
>>> generate_sequence(5, 2, "cube", ndsort=-1, seed=42, integer=True)
array([[1843824993, 1497586439],
       [1634535063, 1688060241],
       [1662057958,  942484272],
       [ 202244314, 2095133046],
       [ 275121931,  967196436]])
>>> generate_sequence(5, 2, "glas2017", seed=42, integer=True)
array([[-696703483,  696703483],
       [5845539605, 4891878634],
       [ 897908837, -897908837],
       [ 109098654, -109098654],
       [1008017539, 3286949756]])