Sampling Sequences of Dominated and Nondominated Points#

This example illustrates how to sample sequences of multi-dimensional points with various dominance properties using generate_sequence().

First we define a few functions useful for plotting.

import matplotlib.pyplot as plt
import numpy as np
from _utils import plot_sequence_2d, plotly_3d, plotly_3d_side_by_side

import moocore


def plotly_generate_sequence_3d(what, n, method, seed, show_index=False):
    """Generate points with moocore.generate_sequence() and plot them with plotly_3d()."""
    return plotly_3d(
        what,
        moocore.generate_sequence(n, 3, method, seed=seed),
        title=f'method="{method}"',
        rank=True,
        show_index=show_index,
    )

Sequences in 2D#

First, we plot completely ordered sequences. We use different seeds to get different sequences. Points are colored according to their Pareto rank, with lower ranks having darker colors. In these two sequences, each point has a different color (rank) from the rest.

n = 10
fig, axes = plt.subplots(1, 2, figsize=(8, 4), sharex=True, sharey=True)
for ax, method, seed in zip(
    axes, ["each-dominates-previous", "each-dominates-next"], [42, 43]
):
    points = moocore.generate_sequence(n, 2, method=method, seed=seed)
    plot_sequence_2d(points, title=f'method="{method}"', ax=ax)

fig.tight_layout()
plt.show()
method=

Random sequences sampled in the unit hypercube or the unit hypersphere.

n = 10
for method in ["cube", "sphere"]:
    fig, axes = plt.subplots(1, 3, figsize=(12, 4), sharex=True, sharey=True)
    show_circle = method == "sphere"
    for ax, ndsort in zip(axes, [1, 0, -1]):
        points = moocore.generate_sequence(
            n, 2, method=method, ndsort=ndsort, seed=42
        )
        plot_sequence_2d(
            points,
            title=f'method="{method}", ndsort={ndsort}',
            ax=ax,
            show_circle=show_circle,
        )

    fig.tight_layout()
    plt.show()
  • method=
  • method=

Naive sampling within the hypersphere produces a bias towards the origin.

n = 200
method = "sphere"
fig, axes = plt.subplots(1, 2, figsize=(8, 4), sharex=True, sharey=True)
points = moocore.generate_sequence(n, 2, method=method, seed=42)
plot_sequence_2d(
    points,
    title=f'method="{method}"',
    ax=axes[0],
    show_circle=True,
    show_index=False,
)

# Naive
rng = np.random.default_rng(42)
points = np.abs(rng.normal(size=(n, 2)))
points /= np.linalg.norm(points, axis=1, keepdims=True)
points *= rng.uniform(0, 1, size=(n, 1))
plot_sequence_2d(
    points, title="Naive", ax=axes[1], show_circle=True, show_index=False
)
fig.tight_layout()
plt.show()
method=

Generate the analytic sequence proposed by Glasmachers[1].

n = 15
method = "glas2017"
fig, axes = plt.subplots(1, 3, figsize=(12, 4), sharex=True, sharey=True)
for ax, c_value in zip(axes, [0.5, 1, 2]):
    points = moocore.generate_sequence(
        n, 2, method=method, c_value=c_value, seed=42
    )
    plot_sequence_2d(
        points, title=f'method="{method}", c_value={c_value}', ax=ax
    )

fig.tight_layout()
plt.show()
method=

Sequences in integer space#

We can also generate points in integer space.

n = 10
fig, axes = plt.subplots(1, 2, figsize=(8, 4), sharex=True, sharey=True)
for ax, method, seed in zip(
    axes, ["each-dominates-previous", "each-dominates-next"], [42, 43]
):
    points = moocore.generate_sequence(
        n, 2, method=method, seed=seed, integer=True
    )
    plot_sequence_2d(points, title=f'method="{method}"', ax=ax)

fig.tight_layout()
plt.show()

for method in ["cube", "sphere"]:
    fig, axes = plt.subplots(1, 3, figsize=(12, 4), sharex=True, sharey=True)
    show_circle = method == "sphere"
    for ax, ndsort in zip(axes, [1, 0, -1]):
        points = moocore.generate_sequence(
            n, 2, method=method, ndsort=ndsort, seed=42, integer=True
        )
        plot_sequence_2d(
            points,
            title=f'method="{method}", ndsort={ndsort}',
            ax=ax,
            show_circle=show_circle,
        )

    fig.tight_layout()
    plt.show()

n = 15
method = "glas2017"
fig, axes = plt.subplots(1, 3, figsize=(12, 4), sharex=True, sharey=True)
for ax, c_value in zip(axes, [0.5, 1, 2]):
    points = moocore.generate_sequence(
        n, 2, method=method, c_value=c_value, seed=42, integer=True
    )
    plot_sequence_2d(
        points, title=f'method="{method}", c_value={c_value}', ax=ax
    )

fig.tight_layout()
plt.show()
  • method=
  • method=
  • method=
  • method=

Sequences in 3D#

Completely ordered sequences. We use different seeds to get different sequences. Points are colored according to their Pareto rank, with lower ranks having darker colors. In these two sequences, each point has a different color (rank) from the rest.

n = 10
fig1 = plotly_generate_sequence_3d(
    "simplex", n, method="each-dominates-previous", seed=42, show_index=True
)
fig2 = plotly_generate_sequence_3d(
    "simplex", n, method="each-dominates-next", seed=43, show_index=True
)
plotly_3d_side_by_side(fig1, fig2)


Random sequences sampled in the unit hypercube or the unit hypersphere. If you hover over a point, a tooltip shows the coordinates and the index of the point in the sequence.

n = 100
fig1 = plotly_generate_sequence_3d("concave", n, method="cube", seed=42)
fig2 = plotly_generate_sequence_3d("concave", n, method="sphere", seed=42)
plotly_3d_side_by_side(fig1, fig2)


Generate the analytic sequence proposed by Glasmachers[1].

n = 100
method = "glas2017"
c_value = 0.5
fig1 = plotly_3d(
    "simplex",
    moocore.generate_sequence(n, 3, method, seed=42, c_value=c_value),
    title=f'method="{method}", c_value={c_value}',
    rank=True,
)
c_value = 1.5
fig2 = plotly_3d(
    "simplex",
    moocore.generate_sequence(n, 3, method, seed=42, c_value=c_value),
    title=f'method="{method}", c_value={c_value}',
    rank=True,
)

plotly_3d_side_by_side(fig1, fig2)


References#

Related examples

Sampling Random Nondominated Sets

Sampling Random Nondominated Sets

Total running time of the script: (0 minutes 2.941 seconds)

Gallery generated by Sphinx-Gallery