Total Complexity | 57 |
Total Lines | 595 |
Duplicated Lines | 3.03 % |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like NiaPy.algorithms.basic.es often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | # encoding=utf8 |
||
2 | import logging |
||
3 | from math import ceil |
||
4 | |||
5 | from numpy import argmin, argsort, log, sum, fmax, sqrt, full, exp, eye, diag, apply_along_axis, round, any, asarray, dot, random as rand, tile, inf, where, append |
||
6 | from numpy.linalg import norm, cholesky as chol, eig, solve, lstsq |
||
7 | |||
8 | from NiaPy.algorithms.algorithm import Algorithm, Individual, defaultIndividualInit |
||
9 | from NiaPy.util.utility import objects2array |
||
10 | |||
11 | logging.basicConfig() |
||
12 | logger = logging.getLogger('NiaPy.algorithms.basic') |
||
13 | logger.setLevel('INFO') |
||
14 | |||
15 | __all__ = ['EvolutionStrategy1p1', 'EvolutionStrategyMp1', 'EvolutionStrategyMpL', 'EvolutionStrategyML', 'CovarianceMatrixAdaptionEvolutionStrategy'] |
||
16 | |||
17 | class IndividualES(Individual): |
||
18 | r"""Individual for Evolution Strategies. |
||
19 | |||
20 | See Also: |
||
21 | * :class:`NiaPy.algorithms.Individual` |
||
22 | """ |
||
23 | def __init__(self, **kwargs): |
||
24 | r"""Initialize individual. |
||
25 | |||
26 | Args: |
||
27 | kwargs (Dict[str, Any]): Additional arguments. |
||
28 | |||
29 | See Also: |
||
30 | * :func:`NiaPy.algorithms.Individual.__init__` |
||
31 | """ |
||
32 | Individual.__init__(self, **kwargs) |
||
33 | self.rho = kwargs.get('rho', 1) |
||
34 | |||
35 | class EvolutionStrategy1p1(Algorithm): |
||
36 | r"""Implementation of (1 + 1) evolution strategy algorithm. Uses just one individual. |
||
37 | |||
38 | Algorithm: |
||
39 | (1 + 1) Evolution Strategy Algorithm |
||
40 | |||
41 | Date: |
||
42 | 2018 |
||
43 | |||
44 | Authors: |
||
45 | Klemen Berkovič |
||
46 | |||
47 | License: |
||
48 | MIT |
||
49 | |||
50 | Reference URL: |
||
51 | |||
52 | Reference paper: |
||
53 | |||
54 | Attributes: |
||
55 | Name (List[str]): List of strings representing algorithm names. |
||
56 | mu (int): Number of parents. |
||
57 | k (int): Number of iterations before checking and fixing rho. |
||
58 | c_a (float): Search range amplification factor. |
||
59 | c_r (float): Search range reduction factor. |
||
60 | |||
61 | See Also: |
||
62 | * :class:`NiaPy.algorithms.Algorithm` |
||
63 | """ |
||
64 | Name = ['EvolutionStrategy1p1', 'EvolutionStrategy(1+1)', 'ES(1+1)'] |
||
65 | |||
66 | @staticmethod |
||
67 | def algorithmInfo(): |
||
68 | r"""Get algorithms information. |
||
69 | |||
70 | Returns: |
||
71 | str: Algorithm information. |
||
72 | |||
73 | See Also: |
||
74 | * :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
||
75 | """ |
||
76 | return r"""TODO""" |
||
77 | |||
78 | View Code Duplication | @staticmethod |
|
|
|||
79 | def typeParameters(): |
||
80 | r"""Get dictionary with functions for checking values of parameters. |
||
81 | |||
82 | Returns: |
||
83 | Dict[str, Callable]: |
||
84 | * mu (Callable[[int], bool]) |
||
85 | * k (Callable[[int], bool]) |
||
86 | * c_a (Callable[[Union[float, int]], bool]) |
||
87 | * c_r (Callable[[Union[float, int]], bool]) |
||
88 | * epsilon (Callable[[float], bool]) |
||
89 | """ |
||
90 | return { |
||
91 | 'mu': lambda x: isinstance(x, int) and x > 0, |
||
92 | 'k': lambda x: isinstance(x, int) and x > 0, |
||
93 | 'c_a': lambda x: isinstance(x, (float, int)) and x > 1, |
||
94 | 'c_r': lambda x: isinstance(x, (float, int)) and 0 < x < 1, |
||
95 | 'epsilon': lambda x: isinstance(x, float) and 0 < x < 1 |
||
96 | } |
||
97 | |||
98 | def setParameters(self, mu=1, k=10, c_a=1.1, c_r=0.5, epsilon=1e-20, **ukwargs): |
||
99 | r"""Set the arguments of an algorithm. |
||
100 | |||
101 | Arguments: |
||
102 | mu (Optional[int]): Number of parents |
||
103 | k (Optional[int]): Number of iterations before checking and fixing rho |
||
104 | c_a (Optional[float]): Search range amplification factor |
||
105 | c_r (Optional[float]): Search range reduction factor |
||
106 | |||
107 | See Also: |
||
108 | * :func:`NiaPy.algorithms.Algorithm.setParameters` |
||
109 | """ |
||
110 | Algorithm.setParameters(self, NP=mu, itype=ukwargs.pop('itype', IndividualES), **ukwargs) |
||
111 | self.mu, self.k, self.c_a, self.c_r, self.epsilon = mu, k, c_a, c_r, epsilon |
||
112 | |||
113 | def mutate(self, x, rho): |
||
114 | r"""Mutate individual. |
||
115 | |||
116 | Args: |
||
117 | x (Individual): Current individual. |
||
118 | rho (float): Current standard deviation. |
||
119 | |||
120 | Returns: |
||
121 | Individual: Mutated individual. |
||
122 | """ |
||
123 | return x + self.normal(0, rho, len(x)) |
||
124 | |||
125 | def updateRho(self, rho, k): |
||
126 | r"""Update standard deviation. |
||
127 | |||
128 | Args: |
||
129 | rho (float): Current standard deviation. |
||
130 | k (int): Number of succesfull mutations. |
||
131 | |||
132 | Returns: |
||
133 | float: New standard deviation. |
||
134 | """ |
||
135 | phi = k / self.k |
||
136 | if phi < 0.2: return self.c_r * rho if rho > self.epsilon else 1 |
||
137 | elif phi > 0.2: return self.c_a * rho if rho > self.epsilon else 1 |
||
138 | else: return rho |
||
139 | |||
140 | def initPopulation(self, task): |
||
141 | r"""Initialize starting individual. |
||
142 | |||
143 | Args: |
||
144 | task (Task): Optimization task. |
||
145 | |||
146 | Returns: |
||
147 | Tuple[Individual, float, Dict[str, Any]]: |
||
148 | 1, Initialized individual. |
||
149 | 2, Initialized individual fitness/function value. |
||
150 | 3. Additional arguments: |
||
151 | * ki (int): Number of successful rho update. |
||
152 | """ |
||
153 | c, ki = IndividualES(task=task, rnd=self.Rand), 0 |
||
154 | return c, c.f, {'ki': ki} |
||
155 | |||
156 | def runIteration(self, task, c, fpop, xb, fxb, ki, **dparams): |
||
157 | r"""Core function of EvolutionStrategy(1+1) algorithm. |
||
158 | |||
159 | Args: |
||
160 | task (Task): Optimization task. |
||
161 | pop (Individual): Current position. |
||
162 | fpop (float): Current position function/fitness value. |
||
163 | xb (Individual): Global best position. |
||
164 | fxb (float): Global best function/fitness value. |
||
165 | ki (int): Number of successful updates before rho update. |
||
166 | **dparams (Dict[str, Any]): Additional arguments. |
||
167 | |||
168 | Returns: |
||
169 | Tuple[Individual, float, Individual, float, Dict[str, Any]]: |
||
170 | 1, Initialized individual. |
||
171 | 2, Initialized individual fitness/function value. |
||
172 | 3. New global best solution. |
||
173 | 4. New global best soluitons fitness/objective value. |
||
174 | 5. Additional arguments: |
||
175 | * ki (int): Number of successful rho update. |
||
176 | """ |
||
177 | if task.Iters % self.k == 0: c.rho, ki = self.updateRho(c.rho, ki), 0 |
||
178 | cn = objects2array([task.repair(self.mutate(c.x, c.rho), self.Rand) for _i in range(self.mu)]) |
||
179 | cn_f = asarray([task.eval(cn[i]) for i in range(len(cn))]) |
||
180 | ib = argmin(cn_f) |
||
181 | if cn_f[ib] < c.f: |
||
182 | c.x, c.f, ki = cn[ib], cn_f[ib], ki + 1 |
||
183 | if cn_f[ib] < fxb: xb, fxb = self.getBest(cn[ib], cn_f[ib], xb, fxb) |
||
184 | return c, c.f, xb, fxb, {'ki': ki} |
||
185 | |||
186 | class EvolutionStrategyMp1(EvolutionStrategy1p1): |
||
187 | r"""Implementation of (mu + 1) evolution strategy algorithm. Algorithm creates mu mutants but into new generation goes only one individual. |
||
188 | |||
189 | Algorithm: |
||
190 | (:math:`\mu + 1`) Evolution Strategy Algorithm |
||
191 | |||
192 | Date: |
||
193 | 2018 |
||
194 | |||
195 | Authors: |
||
196 | Klemen Berkovič |
||
197 | |||
198 | License: |
||
199 | MIT |
||
200 | |||
201 | Reference URL: |
||
202 | |||
203 | Reference paper: |
||
204 | |||
205 | Attributes: |
||
206 | Name (List[str]): List of strings representing algorithm names. |
||
207 | |||
208 | See Also: |
||
209 | * :class:`NiaPy.algorithms.basic.EvolutionStrategy1p1` |
||
210 | """ |
||
211 | Name = ['EvolutionStrategyMp1', 'EvolutionStrategy(mu+1)', 'ES(m+1)'] |
||
212 | |||
213 | @staticmethod |
||
214 | def algorithmInfo(): |
||
215 | r"""Get algorithms information. |
||
216 | |||
217 | Returns: |
||
218 | str: Algorithm information. |
||
219 | |||
220 | See Also: |
||
221 | * :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
||
222 | """ |
||
223 | return r"""TODO""" |
||
224 | |||
225 | def setParameters(self, **kwargs): |
||
226 | r"""Set core parameters of EvolutionStrategy(mu+1) algorithm. |
||
227 | |||
228 | Args: |
||
229 | **kwargs (Dict[str, Any]): |
||
230 | |||
231 | See Also: |
||
232 | * :func:`NiaPy.algorithms.basic.EvolutionStrategy1p1.setParameters` |
||
233 | """ |
||
234 | mu = kwargs.pop('mu', 40) |
||
235 | EvolutionStrategy1p1.setParameters(self, mu=mu, **kwargs) |
||
236 | |||
237 | class EvolutionStrategyMpL(EvolutionStrategy1p1): |
||
238 | r"""Implementation of (mu + lambda) evolution strategy algorithm. Mulation creates lambda individual. Lambda individual compete with mu individuals for survival, so only mu individual go to new generation. |
||
239 | |||
240 | Algorithm: |
||
241 | (:math:`\mu + \lambda`) Evolution Strategy Algorithm |
||
242 | |||
243 | Date: |
||
244 | 2018 |
||
245 | |||
246 | Authors: |
||
247 | Klemen Berkovič |
||
248 | |||
249 | License: |
||
250 | MIT |
||
251 | |||
252 | Reference URL: |
||
253 | |||
254 | Reference paper: |
||
255 | |||
256 | Attributes: |
||
257 | Name (List[str]): List of strings representing algorithm names |
||
258 | lam (int): TODO |
||
259 | |||
260 | See Also: |
||
261 | * :class:`NiaPy.algorithms.basic.EvolutionStrategy1p1` |
||
262 | """ |
||
263 | Name = ['EvolutionStrategyMpL', 'EvolutionStrategy(mu+lambda)', 'ES(m+l)'] |
||
264 | |||
265 | @staticmethod |
||
266 | def algorithmInfo(): |
||
267 | r"""Get algorithms information. |
||
268 | |||
269 | Returns: |
||
270 | str: Algorithm information. |
||
271 | |||
272 | See Also: |
||
273 | * :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
||
274 | """ |
||
275 | return r"""TODO""" |
||
276 | |||
277 | @staticmethod |
||
278 | def typeParameters(): |
||
279 | r"""TODO. |
||
280 | |||
281 | Returns: |
||
282 | Dict[str, Any]: |
||
283 | * lam (Callable[[int], bool]): TODO. |
||
284 | |||
285 | See Also: |
||
286 | * :func:`NiaPy.algorithms.basic.EvolutionStrategy1p1` |
||
287 | """ |
||
288 | d = EvolutionStrategy1p1.typeParameters() |
||
289 | d['lam'] = lambda x: isinstance(x, int) and x > 0 |
||
290 | return d |
||
291 | |||
292 | def setParameters(self, lam=45, **ukwargs): |
||
293 | r"""Set the arguments of an algorithm. |
||
294 | |||
295 | Arguments: |
||
296 | lam (int): Number of new individual generated by mutation. |
||
297 | |||
298 | See Also: |
||
299 | * :func:`NiaPy.algorithms.basic.es.EvolutionStrategy1p1.setParameters` |
||
300 | """ |
||
301 | EvolutionStrategy1p1.setParameters(self, InitPopFunc=defaultIndividualInit, **ukwargs) |
||
302 | self.lam = lam |
||
303 | |||
304 | def updateRho(self, pop, k): |
||
305 | r"""Update standard deviation for population. |
||
306 | |||
307 | Args: |
||
308 | pop (numpy.ndarray[Individual]): Current population. |
||
309 | k (int): Number of successful mutations. |
||
310 | """ |
||
311 | phi = k / self.k |
||
312 | if phi < 0.2: |
||
313 | for i in pop: i.rho = self.c_r * i.rho |
||
314 | elif phi > 0.2: |
||
315 | for i in pop: i.rho = self.c_a * i.rho |
||
316 | |||
317 | def changeCount(self, c, cn): |
||
318 | r"""Update number of successful mutations for population. |
||
319 | |||
320 | Args: |
||
321 | c (numpy.ndarray[Individual]): Current population. |
||
322 | cn (numpy.ndarray[Individual]): New population. |
||
323 | |||
324 | Returns: |
||
325 | int: Number of successful mutations. |
||
326 | """ |
||
327 | k = 0 |
||
328 | for e in cn: |
||
329 | if e not in c: k += 1 |
||
330 | return k |
||
331 | |||
332 | def mutateRand(self, pop, task): |
||
333 | r"""Mutate random individual form population. |
||
334 | |||
335 | Args: |
||
336 | pop (numpy.ndarray[Individual]): Current population. |
||
337 | task (Task): Optimization task. |
||
338 | |||
339 | Returns: |
||
340 | numpy.ndarray: Random individual from population that was mutated. |
||
341 | """ |
||
342 | i = self.randint(self.mu) |
||
343 | return task.repair(self.mutate(pop[i].x, pop[i].rho), rnd=self.Rand) |
||
344 | |||
345 | def initPopulation(self, task): |
||
346 | r"""Initialize starting population. |
||
347 | |||
348 | Args: |
||
349 | task (Task): Optimization task. |
||
350 | |||
351 | Returns: |
||
352 | Tuple[numpy.ndarray[Individual], numpy.ndarray[float], Dict[str, Any]]: |
||
353 | 1. Initialized populaiton. |
||
354 | 2. Initialized populations function/fitness values. |
||
355 | 3. Additional arguments: |
||
356 | * ki (int): Number of successful mutations. |
||
357 | |||
358 | See Also: |
||
359 | * :func:`NiaPy.algorithms.algorithm.Algorithm.initPopulation` |
||
360 | """ |
||
361 | c, fc, d = Algorithm.initPopulation(self, task) |
||
362 | d.update({'ki': 0}) |
||
363 | return c, fc, d |
||
364 | |||
365 | def runIteration(self, task, c, fpop, xb, fxb, ki, **dparams): |
||
366 | r"""Core function of EvolutionStrategyMpL algorithm. |
||
367 | |||
368 | Args: |
||
369 | task (Task): Optimization task. |
||
370 | c (numpy.ndarray): Current population. |
||
371 | fpop (numpy.ndarray): Current populations fitness/function values. |
||
372 | xb (numpy.ndarray): Global best individual. |
||
373 | fxb (float): Global best individuals fitness/function value. |
||
374 | ki (int): Number of successful mutations. |
||
375 | **dparams (Dict[str, Any]): Additional arguments. |
||
376 | |||
377 | Returns: |
||
378 | Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, Dict[str, Any]]: |
||
379 | 1. New population. |
||
380 | 2. New populations function/fitness values. |
||
381 | 3. New global best solution. |
||
382 | 4. New global best solutions fitness/objective value. |
||
383 | 5. Additional arguments: |
||
384 | * ki (int): Number of successful mutations. |
||
385 | """ |
||
386 | if task.Iters % self.k == 0: _, ki = self.updateRho(c, ki), 0 |
||
387 | cn = objects2array([IndividualES(x=self.mutateRand(c, task), task=task, rnd=self.Rand) for _ in range(self.lam)]) |
||
388 | cn = append(cn, c) |
||
389 | cn = objects2array([cn[i] for i in argsort([i.f for i in cn])[:self.mu]]) |
||
390 | ki += self.changeCount(c, cn) |
||
391 | fcn = asarray([x.f for x in cn]) |
||
392 | xb, fxb = self.getBest(cn, fcn, xb, fxb) |
||
393 | return cn, fcn, xb, fxb, {'ki': ki} |
||
394 | |||
395 | class EvolutionStrategyML(EvolutionStrategyMpL): |
||
396 | r"""Implementation of (mu, lambda) evolution strategy algorithm. Algorithm is good for dynamic environments. Mu individual create lambda chields. Only best mu chields go to new generation. Mu parents are discarded. |
||
397 | |||
398 | Algorithm: |
||
399 | (:math:`\mu + \lambda`) Evolution Strategy Algorithm |
||
400 | |||
401 | Date: |
||
402 | 2018 |
||
403 | |||
404 | Authors: |
||
405 | Klemen Berkovič |
||
406 | |||
407 | License: |
||
408 | MIT |
||
409 | |||
410 | Reference URL: |
||
411 | |||
412 | Reference paper: |
||
413 | |||
414 | Attributes: |
||
415 | Name (List[str]): List of strings representing algorithm names |
||
416 | |||
417 | See Also: |
||
418 | * :class:`NiaPy.algorithm.basic.es.EvolutionStrategyMpL` |
||
419 | """ |
||
420 | Name = ['EvolutionStrategyML', 'EvolutionStrategy(mu,lambda)', 'ES(m,l)'] |
||
421 | |||
422 | @staticmethod |
||
423 | def algorithmInfo(): |
||
424 | r"""Get algorithms information. |
||
425 | |||
426 | Returns: |
||
427 | str: Algorithm information. |
||
428 | |||
429 | See Also: |
||
430 | * :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
||
431 | """ |
||
432 | return r"""TODO""" |
||
433 | |||
434 | def newPop(self, pop): |
||
435 | r"""Return new population. |
||
436 | |||
437 | Args: |
||
438 | pop (numpy.ndarray): Current population. |
||
439 | |||
440 | Returns: |
||
441 | numpy.ndarray: New population. |
||
442 | """ |
||
443 | pop_s = argsort([i.f for i in pop]) |
||
444 | if self.mu < self.lam: return objects2array([pop[i] for i in pop_s[:self.mu]]) |
||
445 | npop = list() |
||
446 | for i in range(int(ceil(float(self.mu) / self.lam))): npop.extend(pop[:self.lam if (self.mu - i * self.lam) >= self.lam else self.mu - i * self.lam]) |
||
447 | return objects2array(npop) |
||
448 | |||
449 | def initPopulation(self, task): |
||
450 | r"""Initialize starting population. |
||
451 | |||
452 | Args: |
||
453 | task (Task): Optimization task. |
||
454 | |||
455 | Returns: |
||
456 | Tuple[numpy.ndarray[Individual], numpy.ndarray[float], Dict[str, Any]]: |
||
457 | 1. Initialized population. |
||
458 | 2. Initialized populations fitness/function values. |
||
459 | 2. Additional arguments. |
||
460 | |||
461 | See Also: |
||
462 | * :func:`NiaPy.algorithm.basic.es.EvolutionStrategyMpL.initPopulation` |
||
463 | """ |
||
464 | c, fc, _ = EvolutionStrategyMpL.initPopulation(self, task) |
||
465 | return c, fc, {} |
||
466 | |||
467 | def runIteration(self, task, c, fpop, xb, fxb, **dparams): |
||
468 | r"""Core function of EvolutionStrategyML algorithm. |
||
469 | |||
470 | Args: |
||
471 | task (Task): Optimization task. |
||
472 | c (numpy.ndarray): Current population. |
||
473 | fpop (numpy.ndarray): Current population fitness/function values. |
||
474 | xb (numpy.ndarray): Global best individual. |
||
475 | fxb (float): Global best individuals fitness/function value. |
||
476 | **dparams Dict[str, Any]: Additional arguments. |
||
477 | |||
478 | Returns: |
||
479 | Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, Dict[str, Any]]: |
||
480 | 1. New population. |
||
481 | 2. New populations fitness/function values. |
||
482 | 3. New global best solution. |
||
483 | 4. New global best solutions fitness/objective value. |
||
484 | 5. Additional arguments. |
||
485 | """ |
||
486 | cn = objects2array([IndividualES(x=self.mutateRand(c, task), task=task, rand=self.Rand) for _ in range(self.lam)]) |
||
487 | c = self.newPop(cn) |
||
488 | fc = asarray([x.f for x in c]) |
||
489 | xb, fxb = self.getBest(c, fc, xb, fxb) |
||
490 | return c, fc, xb, fxb, {} |
||
491 | |||
492 | def CovarianceMaatrixAdaptionEvolutionStrategyF(task, epsilon=1e-20, rnd=rand): |
||
493 | lam, alpha_mu, hs, sigma0 = (4 + round(3 * log(task.D))) * 10, 2, 0, 0.3 * task.bcRange() |
||
494 | mu = int(round(lam / 2)) |
||
495 | w = log(mu + 0.5) - log(range(1, mu + 1)) |
||
496 | w = w / sum(w) |
||
497 | mueff = 1 / sum(w ** 2) |
||
498 | cs = (mueff + 2) / (task.D + mueff + 5) |
||
499 | ds = 1 + cs + 2 * max(sqrt((mueff - 1) / (task.D + 1)) - 1, 0) |
||
500 | ENN = sqrt(task.D) * (1 - 1 / (4 * task.D) + 1 / (21 * task.D ** 2)) |
||
501 | cc, c1 = (4 + mueff / task.D) / (4 + task.D + 2 * mueff / task.D), 2 / ((task.D + 1.3) ** 2 + mueff) |
||
502 | cmu, hth = min(1 - c1, alpha_mu * (mueff - 2 + 1 / mueff) / ((task.D + 2) ** 2 + alpha_mu * mueff / 2)), (1.4 + 2 / (task.D + 1)) * ENN |
||
503 | ps, pc, C, sigma, M = full(task.D, 0.0), full(task.D, 0.0), eye(task.D), sigma0, full(task.D, 0.0) |
||
504 | x = rnd.uniform(task.bcLower(), task.bcUpper()) |
||
505 | x_f = task.eval(x) |
||
506 | while not task.stopCondI(): |
||
507 | pop_step = asarray([rnd.multivariate_normal(full(task.D, 0.0), C) for _ in range(int(lam))]) |
||
508 | pop = asarray([task.repair(x + sigma * ps, rnd) for ps in pop_step]) |
||
509 | pop_f = apply_along_axis(task.eval, 1, pop) |
||
510 | isort = argsort(pop_f) |
||
511 | pop, pop_f, pop_step = pop[isort[:mu]], pop_f[isort[:mu]], pop_step[isort[:mu]] |
||
512 | if pop_f[0] < x_f: x, x_f = pop[0], pop_f[0] |
||
513 | M = sum(w * pop_step.T, axis=1) |
||
514 | ps = solve(chol(C).conj() + epsilon, ((1 - cs) * ps + sqrt(cs * (2 - cs) * mueff) * M + epsilon).T)[0].T |
||
515 | sigma *= exp(cs / ds * (norm(ps) / ENN - 1)) ** 0.3 |
||
516 | ifix = where(sigma == inf) |
||
517 | if any(ifix): sigma[ifix] = sigma0 |
||
518 | if norm(ps) / sqrt(1 - (1 - cs) ** (2 * (task.Iters + 1))) < hth: hs = 1 |
||
519 | else: hs = 0 |
||
520 | delta = (1 - hs) * cc * (2 - cc) |
||
521 | pc = (1 - cc) * pc + hs * sqrt(cc * (2 - cc) * mueff) * M |
||
522 | C = (1 - c1 - cmu) * C + c1 * (tile(pc, [len(pc), 1]) * tile(pc.reshape([len(pc), 1]), [1, len(pc)]) + delta * C) |
||
523 | for i in range(mu): C += cmu * w[i] * tile(pop_step[i], [len(pop_step[i]), 1]) * tile(pop_step[i].reshape([len(pop_step[i]), 1]), [1, len(pop_step[i])]) |
||
524 | E, V = eig(C) |
||
525 | if any(E < epsilon): |
||
526 | E = fmax(E, 0) |
||
527 | C = lstsq(V.T, dot(V, diag(E)).T, rcond=None)[0].T |
||
528 | return x, x_f |
||
529 | |||
530 | class CovarianceMatrixAdaptionEvolutionStrategy(Algorithm): |
||
531 | r"""Implementation of (mu, lambda) evolution strategy algorithm. Algorithm is good for dynamic environments. Mu individual create lambda chields. Only best mu chields go to new generation. Mu parents are discarded. |
||
532 | |||
533 | Algorithm: |
||
534 | (:math:`\mu + \lambda`) Evolution Strategy Algorithm |
||
535 | |||
536 | Date: |
||
537 | 2018 |
||
538 | |||
539 | Authors: |
||
540 | Klemen Berkovič |
||
541 | |||
542 | License: |
||
543 | MIT |
||
544 | |||
545 | Reference URL: |
||
546 | https://arxiv.org/abs/1604.00772 |
||
547 | |||
548 | Reference paper: |
||
549 | Hansen, Nikolaus. "The CMA evolution strategy: A tutorial." arXiv preprint arXiv:1604.00772 (2016). |
||
550 | |||
551 | Attributes: |
||
552 | Name (List[str]): List of names representing algorithm names |
||
553 | epsilon (float): TODO |
||
554 | """ |
||
555 | Name = ['CovarianceMatrixAdaptionEvolutionStrategy', 'CMA-ES', 'CMAES'] |
||
556 | epsilon = 1e-20 |
||
557 | |||
558 | @staticmethod |
||
559 | def algorithmInfo(): |
||
560 | r"""Get algorithms information. |
||
561 | |||
562 | Returns: |
||
563 | str: Algorithm information. |
||
564 | |||
565 | See Also: |
||
566 | * :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
||
567 | """ |
||
568 | return r"""TODO""" |
||
569 | |||
570 | @staticmethod |
||
571 | def typeParameters(): return { |
||
572 | 'epsilon': lambda x: isinstance(x, (float, int)) and 0 < x < 1 |
||
573 | } |
||
574 | |||
575 | def setParameters(self, epsilon=1e-20, **ukwargs): |
||
576 | r"""Set core parameters of CovarianceMatrixAdaptionEvolutionStrategy algorithm. |
||
577 | |||
578 | Args: |
||
579 | epsilon (float): Small number. |
||
580 | **ukwargs (Dict[str, Any]): Additional arguments. |
||
581 | """ |
||
582 | Algorithm.setParameters(self, **ukwargs) |
||
583 | self.epsilon = epsilon |
||
584 | |||
585 | def runTask(self, task): |
||
586 | r"""TODO. |
||
587 | |||
588 | Args: |
||
589 | task (Task): Optimization task. |
||
590 | |||
591 | Returns: |
||
592 | TODO. |
||
593 | """ |
||
594 | return CovarianceMaatrixAdaptionEvolutionStrategyF(task, self.epsilon, rnd=self.Rand) |
||
595 | |||
597 |