Skip to content

Commit

Permalink
Clean mixed integer sampling & seeding (#506)
Browse files Browse the repository at this point in the history
* fix sampling (notebook and doc remain to do)

* fix ego seeding

* add _to_seed

* initialize seed in design space
  • Loading branch information
Paul-Saves authored Feb 6, 2024
1 parent 7320305 commit 70ca1ac
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 77 deletions.
15 changes: 11 additions & 4 deletions smt/applications/ego.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

from smt.surrogate_models import KPLS, KRG, KPLSK, MGP, GEKPLS
from smt.applications.application import SurrogateBasedApplication
from smt.applications.mixed_integer import MixedIntegerContext
from smt.applications.mixed_integer import (
MixedIntegerContext,
MixedIntegerSamplingMethod,
)
from smt.utils.design_space import (
BaseDesignSpace,
DesignSpace,
Expand Down Expand Up @@ -271,10 +274,14 @@ def _setup_optimizer(self, fun):

else:
self.mixint = None
self._sampling = lambda n: self.design_space.sample_valid_x(
n,
sampling = MixedIntegerSamplingMethod(
LHS,
self.design_space,
criterion="ese",
random_state=self.options["random_state"],
)[0]
)
self._sampling = lambda n: sampling(n)

self.categorical_kernel = None

# Build DOE
Expand Down
24 changes: 16 additions & 8 deletions smt/applications/mixed_integer.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def __init__(self, sampling_method_class, design_space, **kwargs):
category=DeprecationWarning,
)
self._design_space = design_space
if "random_state" in kwargs:
self._design_space.random_state = kwargs["random_state"]
elif self._design_space.random_state is None:
self._design_space.random_state = 42
self._unfolded_xlimits = design_space.get_unfolded_num_bounds()
self._output_in_folded_space = kwargs.get("output_in_folded_space", True)
kwargs.pop("output_in_folded_space", None)
Expand All @@ -51,16 +55,20 @@ def __init__(self, sampling_method_class, design_space, **kwargs):
)
super().__init__(xlimits=self._unfolded_xlimits)

def _compute(self, nt):
doe = self._sampling_method(nt)
def _compute(self, nt, return_is_acting=False):

x_doe, _ = self._design_space.correct_get_acting(doe)
if self._output_in_folded_space:
x_doe, _ = self._design_space.fold_x(x_doe)
return x_doe
x_doe, is_acting = self._design_space.sample_valid_x(
nt,
unfolded=not self._output_in_folded_space,
random_state=self._design_space.random_state,
)
if return_is_acting:
return x_doe, is_acting
else:
return x_doe

def __call__(self, nt):
return self._compute(nt)
def __call__(self, nt, return_is_acting=False):
return self._compute(nt, return_is_acting)

def expand_lhs(self, x, nt, method="basic"):
doe = self._sampling_method(nt)
Expand Down
79 changes: 41 additions & 38 deletions smt/applications/tests/test_ego.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def test_rosenbrock_2D(self):
xlimits = fun.xlimits
criterion = "LCB" #'EI' or 'SBO' or 'LCB'
random_state = 42
design_space = DesignSpace(xlimits, seed=random_state)
design_space = DesignSpace(xlimits, random_state=random_state)
xdoe = FullFactorial(xlimits=xlimits)(10)
ego = EGO(
n_start=30,
Expand Down Expand Up @@ -164,7 +164,7 @@ def test_rosenbrock_2D_parallel(self):
xlimits = fun.xlimits
criterion = "LCB" #'EI' or 'SBO' or 'LCB'
random_state = 42
design_space = DesignSpace(xlimits, seed=random_state)
design_space = DesignSpace(xlimits, random_state=random_state)

xdoe = FullFactorial(xlimits=xlimits)(10)
qEI = "KB"
Expand Down Expand Up @@ -250,7 +250,7 @@ def test_branin_2D_mixed_parallel(self):
IntegerVariable(*xlimits[0]),
FloatVariable(*xlimits[1]),
],
seed=random_state,
random_state=random_state,
)
sm = KRG(design_space=design_space, print_global=False, n_start=25)
mixint = MixedIntegerContext(design_space)
Expand Down Expand Up @@ -289,7 +289,7 @@ def test_branin_2D_mixed(self):
IntegerVariable(*xlimits[0]),
FloatVariable(*xlimits[1]),
],
seed=random_state,
random_state=random_state,
)
criterion = "EI" #'EI' or 'SBO' or 'LCB'

Expand Down Expand Up @@ -326,7 +326,7 @@ def test_branin_2D_mixed_tunnel(self):
IntegerVariable(*xlimits[0]),
FloatVariable(*xlimits[1]),
],
seed=random_state,
random_state=random_state,
)
criterion = "EI" #'EI' or 'SBO' or 'LCB'

Expand Down Expand Up @@ -381,17 +381,19 @@ def function_test_mixed_integer(X):
def test_ego_mixed_integer(self):
n_iter = 15
n_doe = 5
random_state = 42
design_space = DesignSpace(
[
FloatVariable(-5, 5),
CategoricalVariable(["blue", "red", "green"]),
CategoricalVariable(["large", "small"]),
OrdinalVariable([0, 2, 3]),
],
seed=random_state,
random_state=42,
)
xdoe, _ = design_space.sample_valid_x(n_doe)
samp = MixedIntegerSamplingMethod(
LHS, design_space, criterion="ese", random_state=design_space.random_state
)
xdoe = samp(n_doe)

criterion = "EI" #'EI' or 'SBO' or 'LCB'
ego = EGO(
Expand All @@ -400,7 +402,7 @@ def test_ego_mixed_integer(self):
xdoe=xdoe,
surrogate=KRG(design_space=design_space, print_global=False),
enable_tunneling=False,
random_state=random_state,
random_state=design_space.random_state,
)
_, y_opt, _, _, _ = ego.optimize(fun=TestEGO.function_test_mixed_integer)

Expand All @@ -418,9 +420,12 @@ def test_ego_mixed_integer_gower_distance(self):
CategoricalVariable(["large", "small"]),
IntegerVariable(0, 2),
],
seed=random_state,
random_state=random_state,
)
xdoe, _ = design_space.sample_valid_x(n_doe)
samp = MixedIntegerSamplingMethod(
LHS, design_space, criterion="ese", random_state=design_space.random_state
)
xdoe = samp(n_doe)

criterion = "EI" #'EI' or 'SBO' or 'LCB'
ego = EGO(
Expand All @@ -435,7 +440,7 @@ def test_ego_mixed_integer_gower_distance(self):
print_global=False,
),
enable_tunneling=False,
random_state=random_state,
random_state=design_space.random_state,
)
_, y_opt, _, _, _ = ego.optimize(fun=TestEGO.function_test_mixed_integer)

Expand Down Expand Up @@ -490,15 +495,15 @@ def f_hv(X):
IntegerVariable(0, 5), # x6
IntegerVariable(0, 5), # x7
],
seed=random_state,
random_state=random_state,
)

# x6 is active when x0 >= 2
design_space.declare_decreed_var(decreed_var=6, meta_var=0, meta_value=[2, 3])
# x7 is active when x0 >= 3
design_space.declare_decreed_var(decreed_var=7, meta_var=0, meta_value=3)

n_doe = 4
n_doe = 5

neutral_var_ds = DesignSpace(design_space.design_variables[1:])
sampling = MixedIntegerSamplingMethod(
Expand Down Expand Up @@ -534,7 +539,7 @@ def f_hv(X):
Xt = np.concatenate((xdoe1, xdoe2, xdoe3), axis=0)
# Yt = np.concatenate((ydoe1, ydoe2, ydoe3), axis=0)

n_iter = 6
n_iter = 10
criterion = "EI"

ego = EGO(
Expand All @@ -557,7 +562,7 @@ def f_hv(X):
self.assertAlmostEqual(
f_hv(np.atleast_2d([2, -5, -5, 5, 0, 0, 0, 5])),
float(y_opt),
delta=15,
delta=18,
)

@unittest.skipIf(int(os.getenv("RUN_SLOW", 0)) < 1, "too slow")
Expand Down Expand Up @@ -681,7 +686,7 @@ def f_hv(X):
IntegerVariable(0, 2),
IntegerVariable(0, 2),
],
seed=random_state,
random_state=random_state,
)

# x4 is acting if meta == 1, 3
Expand All @@ -694,8 +699,10 @@ def f_hv(X):
ds.declare_decreed_var(decreed_var=8, meta_var=0, meta_value=[0, 1])

n_doe = 25
ds.seed = random_state
Xt, x_is_active = ds.sample_valid_x(n_doe)
samp = MixedIntegerSamplingMethod(
LHS, ds, criterion="ese", random_state=ds.random_state
)
Xt, x_is_active = samp(n_doe, return_is_acting=True)

n_iter = 10
criterion = "EI"
Expand Down Expand Up @@ -735,7 +742,7 @@ def test_ego_mixed_integer_homo_gaussian(self):
CategoricalVariable(["large", "small"]),
IntegerVariable(0, 2),
],
seed=random_state,
random_state=random_state,
)
n_doe = 5
sampling = MixedIntegerSamplingMethod(
Expand Down Expand Up @@ -775,7 +782,7 @@ def test_ego_mixed_integer_homo_gaussian_pls(self):
CategoricalVariable(["large", "small"]),
IntegerVariable(0, 2),
],
seed=random_state,
random_state=random_state,
)
sampling = MixedIntegerSamplingMethod(
LHS,
Expand Down Expand Up @@ -812,7 +819,7 @@ def test_ydoe_option(self):
xlimits = fun.xlimits
criterion = "LCB" #'EI' or 'SBO' or 'LCB'
random_state = 42
design_space = DesignSpace(xlimits, seed=random_state)
design_space = DesignSpace(xlimits, random_state=random_state)
xdoe = FullFactorial(xlimits=xlimits)(10)
ydoe = fun(xdoe)
ego = EGO(
Expand All @@ -831,7 +838,7 @@ def test_find_best_point(self):
fun = TestEGO.function_test_1d
xlimits = np.array([[0.0, 25.0]])
random_state = 42
design_space = DesignSpace(xlimits, seed=random_state)
design_space = DesignSpace(xlimits, random_state=random_state)
xdoe = FullFactorial(xlimits=xlimits)(3)
ydoe = fun(xdoe)
ego = EGO(
Expand Down Expand Up @@ -867,7 +874,7 @@ def _evaluate(self, x, kx):

fun = TensorProductIndirect(ndim=2, func=func)
random_state = 42
design_space = DesignSpace(fun.xlimits, seed=42)
design_space = DesignSpace(fun.xlimits, random_state=42)

# Construction of the DOE
sampling = LHS(xlimits=fun.xlimits, criterion="m", random_state=random_state)
Expand Down Expand Up @@ -899,7 +906,7 @@ def _evaluate(self, x, kx):

return ego, fun

def test_ego_seeding(self):
def test_ego_random_stateing(self):
def f_obj(X):
"""
s01 objective
Expand Down Expand Up @@ -976,7 +983,7 @@ def f_obj(X):
)

# To define the initial DOE
random_state = 42 # seed value for the sampling
random_state = 42 # random_state value for the sampling
n_doe = 5 # initial doe size
sampling = MixedIntegerSamplingMethod(
LHS, design_space, criterion="ese", random_state=random_state
Expand Down Expand Up @@ -1005,15 +1012,11 @@ def f_obj(X):
)
x_opt, y_opt, dnk, x_data, y_data = ego.optimize(fun=f_obj)
if ds.HAS_CONFIG_SPACE: # results differs wrt config_space impl
if platform.startswith("linux"): # results differs wrt platform
self.assertAlmostEqual(np.sum(y_data), 1.0355815090110578, delta=1e-12)
self.assertAlmostEqual(np.sum(x_data), 38.56885202767958, delta=1e-12)
else:
self.assertAlmostEqual(np.sum(y_data), 0.9606415626557894, delta=1e-12)
self.assertAlmostEqual(np.sum(x_data), 38.23494224077761, delta=1e-12)
self.assertAlmostEqual(np.sum(y_data), 6.846225752638086, delta=1e-9)
self.assertAlmostEqual(np.sum(x_data), 33.81192549170815, delta=1e-9)
else:
self.assertAlmostEqual(np.sum(y_data), 1.8911720770059735, delta=1e-12)
self.assertAlmostEqual(np.sum(x_data), 47.56885202767958, delta=1e-12)
self.assertAlmostEqual(np.sum(y_data), 1.8911720670620835, delta=1e-9)
self.assertAlmostEqual(np.sum(x_data), 47.56885202767958, delta=1e-9)

def test_ego_gek(self):
ego, fun = self.initialize_ego_gek()
Expand All @@ -1036,7 +1039,7 @@ def test_qei_criterion_default(self):
fun = TestEGO.function_test_1d
xlimits = np.array([[0.0, 25.0]])
random_state = 42
design_space = DesignSpace(xlimits, seed=random_state)
design_space = DesignSpace(xlimits, random_state=random_state)
xdoe = FullFactorial(xlimits=xlimits)(3)
ydoe = fun(xdoe)
ego = EGO(
Expand Down Expand Up @@ -1091,7 +1094,7 @@ def function_test_1d(x):
xlimits = np.array([[0.0, 25.0]])

random_state = 42 # for reproducibility
design_space = DesignSpace(xlimits, seed=random_state)
design_space = DesignSpace(xlimits, random_state=random_state)
xdoe = np.atleast_2d([0, 7, 25]).T
n_doe = xdoe.size

Expand Down Expand Up @@ -1210,7 +1213,7 @@ def function_test_mixed_integer(X):
CategoricalVariable(["square", "circle"]),
IntegerVariable(0, 2),
],
seed=random_state,
random_state=random_state,
)

criterion = "EI" #'EI' or 'SBO' or 'LCB'
Expand Down Expand Up @@ -1281,7 +1284,7 @@ def function_test_1d(x):
xlimits = np.array([[0.0, 25.0]])

random_state = 42
design_space = DesignSpace(xlimits, seed=random_state)
design_space = DesignSpace(xlimits, random_state=random_state)
xdoe = np.atleast_2d([0, 7, 25]).T
n_doe = xdoe.size

Expand Down
Loading

0 comments on commit 70ca1ac

Please sign in to comment.