Latin Hypercube Generator Example¶
This notebook demonstrates basic use of the latin hypercube generator. This generator is a wrapper for the scipy latin hypercube method and allows users to efficiently sample functions (eg for surrogate models). Because the distribution of points depends on the number of sample requested, internally the xopt routine stores a batch of samples. The batch size is specified as an argument to the object's constructor. All other parameters to the scipy function are broken out this way and for a detailed explanation of what they do, the scipy documentation should be consulted.
from copy import deepcopy
from xopt import Xopt, Evaluator
from xopt.generators.scipy.latin_hypercube import LatinHypercubeGenerator
from xopt.resources.test_functions.tnk import evaluate_TNK, tnk_vocs
import matplotlib.pyplot as plt
import numpy as np
# Create the test problem
vocs = deepcopy(tnk_vocs)
vocs.objectives = {}
vocs.observables = ["y1"]
evaluator = Evaluator(function=evaluate_TNK)
# Create the generator and xopt object. Note: the samples are generated in
# batches and the batch size determines the arrangement of points to cover
# the bounded region of the variables.
generator = LatinHypercubeGenerator(vocs=vocs, batch_size=1024)
X = Xopt(generator=generator, evaluator=evaluator, vocs=vocs)
X
Xopt
________________________________
Version: 2.6.7.dev55+g7aa2f3618.d20250930
Data size: 0
Config as YAML:
dump_file: null
evaluator:
function: xopt.resources.test_functions.tnk.evaluate_TNK
function_kwargs:
raise_probability: 0
random_sleep: 0
sleep: 0
max_workers: 1
vectorized: false
generator:
batch_size: 1024
name: latin_hypercube
optimization: random-cd
scramble: true
seed: null
strength: 1
supports_batch_generation: true
supports_constraints: true
supports_multi_objective: true
supports_single_objective: true
max_evaluations: null
serialize_inline: false
serialize_torch: false
strict: true
vocs:
constants:
a: dummy_constant
constraints:
c1:
- GREATER_THAN
- 0.0
c2:
- LESS_THAN
- 0.5
objectives: {}
observables:
- y1
variables:
x1:
- 0.0
- 3.14159
x2:
- 0.0
- 3.14159
# Sample the function a number of times using latin hypercube points
for _ in range(1024):
X.step()
X.data.head()
| x1 | x2 | a | y1 | y2 | c1 | c2 | xopt_runtime | xopt_error | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 2.477865 | 1.224613 | dummy_constant | 2.477865 | 1.224613 | 6.590693 | 4.437012 | 0.000159 | False |
| 1 | 2.168116 | 1.424585 | dummy_constant | 2.168116 | 1.424585 | 5.829406 | 3.637468 | 0.000143 | False |
| 2 | 1.874122 | 0.790835 | dummy_constant | 1.874122 | 0.790835 | 3.038314 | 1.972798 | 0.000142 | False |
| 3 | 1.508534 | 2.518006 | dummy_constant | 1.508534 | 2.518006 | 7.686505 | 5.089487 | 0.000142 | False |
| 4 | 1.209860 | 2.105481 | dummy_constant | 1.209860 | 2.105481 | 4.943949 | 3.081471 | 0.000142 | False |
# Plot the data
plt.scatter(X.data["x1"], X.data["x2"], c=X.data["y1"])
plt.xlabel("x1")
plt.ylabel("x2")
plt.colorbar(label="y1")
<matplotlib.colorbar.Colorbar at 0x7f86fbf57b60>
Distribution of Latin Hypercube points¶
Points in latin hypercube sampling are arranged in a grid such that none occupy the same row or column. That is, in chess it is similar to having n rooks on the board which cannot take each other. We can demonstrate this in the sampler by turning off the "scramble" feature (turned on by default).
n = 16
generator = LatinHypercubeGenerator(vocs=vocs, batch_size=n, scramble=False, seed=0)
X = Xopt(generator=generator, evaluator=evaluator, vocs=vocs)
for _ in range(n):
X.step()
plt.scatter(X.data["x1"], X.data["x2"], c=X.data["y1"])
plt.xlabel("x1")
plt.ylabel("x2")
plt.colorbar(label="y1")
plt.hlines(np.linspace(0, 3.1416, n + 1), 0, 3.1416, color="k")
plt.vlines(np.linspace(0, 3.1416, n + 1), 0, 3.1416, color="k")
<matplotlib.collections.LineCollection at 0x7f86fbc974d0>
The scramble feature will randomize the location of the points within each square while still maintaining the latin hypercube style cells.
n = 16
generator = LatinHypercubeGenerator(vocs=vocs, batch_size=n, scramble=True, seed=0)
X = Xopt(generator=generator, evaluator=evaluator, vocs=vocs)
for _ in range(n):
X.step()
plt.scatter(X.data["x1"], X.data["x2"], c=X.data["y1"])
plt.xlabel("x1")
plt.ylabel("x2")
plt.colorbar(label="y1")
plt.hlines(np.linspace(0, 3.1416, n + 1), 0, 3.1416, color="k")
plt.vlines(np.linspace(0, 3.1416, n + 1), 0, 3.1416, color="k")
<matplotlib.collections.LineCollection at 0x7f86f8b956d0>