Skip to content

Commit

Permalink
Merge pull request #20 from IOHprofiler/vectorized-boundary-control
Browse files Browse the repository at this point in the history
fix unit test, vectorized boundary control
  • Loading branch information
jacobdenobel authored Jan 16, 2021
2 parents 883659b + 7a3022a commit 6fa874d
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 54 deletions.
42 changes: 28 additions & 14 deletions modcma/modularcmaes.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,34 @@ def mutate(self) -> None:

n_offspring = int(self.parameters.lambda_ - (2 * perform_tpa))

if not self.parameters.sequential and not self.parameters.bound_correction:
if not self.parameters.sequential:
z = np.hstack(tuple(islice(self.parameters.sampler, n_offspring)))
if self.parameters.threshold_convergence:
z = scale_with_threshold(z, self.parameters.threshold)

y = np.dot(self.parameters.B, self.parameters.D * z)
x = self.parameters.m + (self.parameters.sigma * y)

x, n_out_of_bounds = correct_bounds(x,
self.parameters.ub,
self.parameters.lb,
self.parameters.bound_correction
)
self.parameters.n_out_of_bounds += n_out_of_bounds

f = np.array(tuple(map(self.fitness_func, x.T)))

else:
x, y, f = [], [], []
for i in range(1, n_offspring + 1):
zi = next(self.parameters.sampler)

if self.parameters.threshold_convergence:
zi = scale_with_threshold(zi, self.parameters.threshold)
# TODO: clean this up this was the old code non vectorized
length = np.linalg.norm(zi)
if length < self.parameters.threshold:
new_length = self.parameters.threshold + (self.parameters.threshold - length)
zi *= new_length / length

yi = np.dot(self.parameters.B, self.parameters.D * zi)
xi = self.parameters.m + (self.parameters.sigma * yi)
Expand Down Expand Up @@ -335,10 +348,9 @@ def scale_with_threshold(z: np.ndarray, threshold: float) -> np.ndarray:
a scaled version of z
"""
length = np.linalg.norm(z)
if length < threshold:
new_length = threshold + (threshold - length)
z *= new_length / length
length = np.linalg.norm(z, axis=0)
mask = length < threshold
z[:, mask] *= (threshold + (threshold - length[mask])) / length[mask]
return z


Expand Down Expand Up @@ -382,13 +394,15 @@ def correct_bounds(
"""
out_of_bounds = np.logical_or(x > ub, x < lb)
if not any(out_of_bounds):
return x, False

if not correction_method:
return x, True

ub, lb = ub[out_of_bounds].copy(), lb[out_of_bounds].copy()
n_out_of_bounds = out_of_bounds.max(axis=0).sum()
if n_out_of_bounds == 0 or correction_method == None:
return x, n_out_of_bounds

try:
_, n = x.shape
except ValueError:
n = 1
ub, lb = np.tile(ub, n)[out_of_bounds], np.tile(lb, n)[out_of_bounds]
y = (x[out_of_bounds] - lb) / (ub - lb)

if correction_method == "mirror":
Expand All @@ -407,7 +421,7 @@ def correct_bounds(
x[out_of_bounds] = lb + (ub - lb) * np.abs(y - np.floor(y))
else:
raise ValueError(f"Unknown argument: {correction_method} for correction_method")
return x, True
return x, n_out_of_bounds


@timeit
Expand Down
52 changes: 26 additions & 26 deletions tests/expected.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
45.175034363167605,
-52.01531942754774,
1017.3030673363197,
71.43871188992895,
3.146564668875037,
-8.279403543275532,
79.03702012530019,
11.753343447706664,
131.38805502911111,
-102.10176326857986,
-543.6999174336394,
42.700744146686965,
-999.9997057338787,
13.04988097465894,
8.695689533892846,
117.29640024093563,
],
"base_sampler_gaussian": [
Expand Down Expand Up @@ -496,30 +496,30 @@
117.28401550404162,
],
"threshold_convergence_True": [
79.60197400323416,
9075.81294241299,
-443.0425148340509,
-449.63233155751726,
15.221583968074889,
1938.1349061808248,
79.5493946792015,
-205.8874080989055,
-440.3860520213715,
-454.59404450938604,
11.02595182176956,
747.5617626591987,
93.54091559010935,
149.27592202799931,
123.88066647543144,
7116.932319384926,
335648.9894252748,
1407321.3639251885,
149.20184452013788,
125.29702895733809,
9842.867547245534,
25856.991912239057,
15020.589468025295,
43.368771569040824,
-52.116212719435566,
1017.7040292314994,
72.00354123874057,
7.140121147903702,
34.24774851152607,
-102.24646124346252,
-543.698445859984,
42.700744146686965,
-999.8961680110624,
13.582863728801364,
116.76955516252966,
-52.317831132167846,
1025.8209383489839,
75.65775413626635,
-15.694063684846274,
-6.053852018150245,
-101.94712477091193,
-544.8856238640917,
42.68657509138354,
-999.9820990897024,
11.66582534228891,
117.58369741868964,
],
"weights_option_1/2^lambda": [
79.5630351924981,
Expand Down
31 changes: 17 additions & 14 deletions tests/test_modularcmaes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,33 @@ class TestModularCMAESMeta(type):
def __new__(cls, name, bases, clsdict):
"""Method for generating new classes."""

def generate_tests(module, value):
return dict(
{
def make_test_fid(module, value, fid):
return {
f"test_{module}_{module}_f{fid}": lambda self: self.run_bbob_function(
module, value, fid
)
}

def make_test_option(module, value):
return {
f"test_{module}_{module}": lambda self: self.run_module(
module, value
)
},
**{
f"test_{module}_{module}_f{fid}": lambda self: self.run_bbob_function(
module, value, fid
)
for fid in range(1, 25)
},
)
}

for module in parameters.Parameters.__modules__:
m = getattr(parameters.Parameters, module)
if type(m) == utils.AnyOf:
for o in filter(None, m.options):
clsdict.update(generate_tests(module, o))
for fid in range(1, 25):
clsdict.update(make_test_fid(module, o, fid))
clsdict.update(make_test_option(module, o))

elif type(m) == utils.InstanceOf:
clsdict.update(generate_tests(module, True))
for fid in range(1, 25):
clsdict.update(make_test_fid(module, True, fid))

clsdict.update(make_test_option(module, True))

return super().__new__(cls, name, bases, clsdict)

Expand All @@ -68,7 +72,6 @@ def run_bbob_function(self, module, value, fid):
self._dim, budget=self._budget, **{module: value}
)
self.c = modularcmaes.ModularCMAES(f, parameters=self.p).run()

self.assertAlmostEqual(
self.c.parameters.fopt,
BBOB_2D_PER_MODULE_20_ITER[f"{module}_{value}"][fid - 1],
Expand Down

0 comments on commit 6fa874d

Please sign in to comment.