1
|
|
|
# encoding=utf8 |
2
|
|
|
import logging |
3
|
|
|
|
4
|
|
|
from NiaPy.algorithms.algorithm import Individual |
5
|
|
|
from NiaPy.algorithms.basic.de import DifferentialEvolution, CrossBest1, CrossRand1, CrossCurr2Best1, CrossBest2, CrossCurr2Rand1, proportional, multiMutations, DynNpDifferentialEvolution |
6
|
|
|
from NiaPy.util.utility import objects2array |
7
|
|
|
|
8
|
|
|
logging.basicConfig() |
9
|
|
|
logger = logging.getLogger('NiaPy.algorithms.modified') |
10
|
|
|
logger.setLevel('INFO') |
11
|
|
|
|
12
|
|
|
__all__ = [ |
13
|
|
|
'SelfAdaptiveDifferentialEvolution', |
14
|
|
|
'DynNpSelfAdaptiveDifferentialEvolutionAlgorithm', |
15
|
|
|
'AgingSelfAdaptiveDifferentialEvolution', |
16
|
|
|
'MultiStrategySelfAdaptiveDifferentialEvolution', |
17
|
|
|
'DynNpMultiStrategySelfAdaptiveDifferentialEvolution' |
18
|
|
|
] |
19
|
|
|
|
20
|
|
|
class SolutionjDE(Individual): |
21
|
|
|
r"""Individual for jDE algorithm. |
22
|
|
|
|
23
|
|
|
Attributes: |
24
|
|
|
F (float): Scale factor. |
25
|
|
|
CR (float): Crossover probability. |
26
|
|
|
|
27
|
|
|
See Also: |
28
|
|
|
:class:`NiaPy.algorithms.Individual` |
29
|
|
|
""" |
30
|
|
|
def __init__(self, F=2, CR=0.5, **kwargs): |
31
|
|
|
r"""Initialize SolutionjDE. |
32
|
|
|
|
33
|
|
|
Attributes: |
34
|
|
|
F (float): Scale factor. |
35
|
|
|
CR (float): Crossover probability. |
36
|
|
|
|
37
|
|
|
See Also: |
38
|
|
|
:func:`NiaPy.algorithm.Individual.__init__` |
39
|
|
|
""" |
40
|
|
|
Individual.__init__(self, **kwargs) |
41
|
|
|
self.F, self.CR = F, CR |
42
|
|
|
|
43
|
|
|
class SelfAdaptiveDifferentialEvolution(DifferentialEvolution): |
44
|
|
|
r"""Implementation of Self-adaptive differential evolution algorithm. |
45
|
|
|
|
46
|
|
|
Algorithm: |
47
|
|
|
Self-adaptive differential evolution algorithm |
48
|
|
|
|
49
|
|
|
Date: |
50
|
|
|
2018 |
51
|
|
|
|
52
|
|
|
Author: |
53
|
|
|
Uros Mlakar and Klemen Berkovič |
54
|
|
|
|
55
|
|
|
License: |
56
|
|
|
MIT |
57
|
|
|
|
58
|
|
|
Reference paper: |
59
|
|
|
Brest, J., Greiner, S., Boskovic, B., Mernik, M., Zumer, V. Self-adapting control parameters in differential evolution: A comparative study on numerical benchmark problems. IEEE transactions on evolutionary computation, 10(6), 646-657, 2006. |
60
|
|
|
|
61
|
|
|
Attributes: |
62
|
|
|
Name (List[str]): List of strings representing algorithm name |
63
|
|
|
F_l (float): Scaling factor lower limit. |
64
|
|
|
F_u (float): Scaling factor upper limit. |
65
|
|
|
Tao1 (float): Change rate for F parameter update. |
66
|
|
|
Tao2 (float): Change rate for CR parameter update. |
67
|
|
|
|
68
|
|
|
See Also: |
69
|
|
|
* :class:`NiaPy.algorithms.basic.DifferentialEvolution` |
70
|
|
|
""" |
71
|
|
|
Name = ['SelfAdaptiveDifferentialEvolution', 'jDE'] |
72
|
|
|
|
73
|
|
|
@staticmethod |
74
|
|
|
def algorithmInfo(): |
75
|
|
|
r"""Get algorithm information. |
76
|
|
|
|
77
|
|
|
Returns: |
78
|
|
|
str: Algorithm information. |
79
|
|
|
|
80
|
|
|
See Also: |
81
|
|
|
* :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
82
|
|
|
""" |
83
|
|
|
return r"""Brest, J., Greiner, S., Boskovic, B., Mernik, M., Zumer, V. Self-adapting control parameters in differential evolution: A comparative study on numerical benchmark problems. IEEE transactions on evolutionary computation, 10(6), 646-657, 2006.""" |
84
|
|
|
|
85
|
|
View Code Duplication |
@staticmethod |
|
|
|
|
86
|
|
|
def typeParameters(): |
87
|
|
|
r"""Get dictionary with functions for checking values of parameters. |
88
|
|
|
|
89
|
|
|
Returns: |
90
|
|
|
Dict[str, Callable]: |
91
|
|
|
* F_l (Callable[[Union[float, int]], bool]) |
92
|
|
|
* F_u (Callable[[Union[float, int]], bool]) |
93
|
|
|
* Tao1 (Callable[[Union[float, int]], bool]) |
94
|
|
|
* Tao2 (Callable[[Union[float, int]], bool]) |
95
|
|
|
|
96
|
|
|
See Also: |
97
|
|
|
* :func:`NiaPy.algorithms.basic.DifferentialEvolution.typeParameters` |
98
|
|
|
""" |
99
|
|
|
d = DifferentialEvolution.typeParameters() |
100
|
|
|
d['F_l'] = lambda x: isinstance(x, (float, int)) and x > 0 |
101
|
|
|
d['F_u'] = lambda x: isinstance(x, (float, int)) and x > 0 |
102
|
|
|
d['Tao1'] = lambda x: isinstance(x, (float, int)) and 0 <= x <= 1 |
103
|
|
|
d['Tao2'] = lambda x: isinstance(x, (float, int)) and 0 <= x <= 1 |
104
|
|
|
return d |
105
|
|
|
|
106
|
|
|
def setParameters(self, F_l=0.0, F_u=1.0, Tao1=0.4, Tao2=0.2, **ukwargs): |
107
|
|
|
r"""Set the parameters of an algorithm. |
108
|
|
|
|
109
|
|
|
Arguments: |
110
|
|
|
F_l (Optional[float]): Scaling factor lower limit. |
111
|
|
|
F_u (Optional[float]): Scaling factor upper limit. |
112
|
|
|
Tao1 (Optional[float]): Change rate for F parameter update. |
113
|
|
|
Tao2 (Optional[float]): Change rate for CR parameter update. |
114
|
|
|
|
115
|
|
|
See Also: |
116
|
|
|
* :func:`NiaPy.algorithms.basic.DifferentialEvolution.setParameters` |
117
|
|
|
""" |
118
|
|
|
DifferentialEvolution.setParameters(self, itype=ukwargs.pop('itype', SolutionjDE), **ukwargs) |
119
|
|
|
self.F_l, self.F_u, self.Tao1, self.Tao2 = F_l, F_u, Tao1, Tao2 |
120
|
|
|
|
121
|
|
|
def getParameters(self): |
122
|
|
|
r"""TODO. |
123
|
|
|
|
124
|
|
|
Returns: |
125
|
|
|
Dict[str, Any]: TODO. |
126
|
|
|
""" |
127
|
|
|
d = DifferentialEvolution.getParameters(self) |
128
|
|
|
d.update({ |
129
|
|
|
'F_l': self.F_l, |
130
|
|
|
'F_u': self.F_u, |
131
|
|
|
'Tao1': self.Tao1, |
132
|
|
|
'Tao2': self.Tao2 |
133
|
|
|
}) |
134
|
|
|
return d |
135
|
|
|
|
136
|
|
|
def AdaptiveGen(self, x): |
137
|
|
|
r"""Adaptive update scale factor in crossover probability. |
138
|
|
|
|
139
|
|
|
Args: |
140
|
|
|
x (Individual): Individual to apply function on. |
141
|
|
|
|
142
|
|
|
Returns: |
143
|
|
|
Individual: New individual with new parameters |
144
|
|
|
""" |
145
|
|
|
f = self.F_l + self.rand() * (self.F_u - self.F_l) if self.rand() < self.Tao1 else x.F |
146
|
|
|
cr = self.rand() if self.rand() < self.Tao2 else x.CR |
147
|
|
|
return self.itype(x=x.x, F=f, CR=cr, e=False) |
148
|
|
|
|
149
|
|
|
def evolve(self, pop, xb, task, **ukwargs): |
150
|
|
|
r"""Evolve current population. |
151
|
|
|
|
152
|
|
|
Args: |
153
|
|
|
pop (numpy.ndarray[Individual]): Current population. |
154
|
|
|
xb (Individual): Global best individual. |
155
|
|
|
task (Task): Optimization task. |
156
|
|
|
ukwargs (Dict[str, Any]): Additional arguments. |
157
|
|
|
|
158
|
|
|
Returns: |
159
|
|
|
numpy.ndarray: New population. |
160
|
|
|
""" |
161
|
|
|
npop = objects2array([self.AdaptiveGen(e) for e in pop]) |
162
|
|
|
for i, e in enumerate(npop): npop[i].x = self.CrossMutt(npop, i, xb, e.F, e.CR, rnd=self.Rand) |
163
|
|
|
for e in npop: e.evaluate(task, rnd=self.rand) |
164
|
|
|
return npop |
165
|
|
|
|
166
|
|
|
class AgingIndividualJDE(SolutionjDE): |
167
|
|
|
r"""Individual with age. |
168
|
|
|
|
169
|
|
|
Attributes: |
170
|
|
|
age (int): Age of individual. |
171
|
|
|
|
172
|
|
|
See Also: |
173
|
|
|
* :func:`NiaPy.algorithms.modified.SolutionjDE` |
174
|
|
|
""" |
175
|
|
|
def __init__(self, **kwargs): |
176
|
|
|
r"""Initialize aging individual for jDE algorithm. |
177
|
|
|
|
178
|
|
|
Args: |
179
|
|
|
**kwargs (Dict[str, Any]): Additional arguments. |
180
|
|
|
|
181
|
|
|
See Also: |
182
|
|
|
* :func:`NiaPy.algorithms.modified.SolutionjDE.__init__` |
183
|
|
|
""" |
184
|
|
|
SolutionjDE.__init__(self, **kwargs) |
185
|
|
|
self.age = 0 |
186
|
|
|
|
187
|
|
|
class AgingSelfAdaptiveDifferentialEvolution(SelfAdaptiveDifferentialEvolution): |
188
|
|
|
r"""Implementation of Dynamic population size with aging self-adaptive differential evolution algorithm. |
189
|
|
|
|
190
|
|
|
Algorithm: |
191
|
|
|
Dynamic population size with aging self-adaptive self adaptive differential evolution algorithm |
192
|
|
|
|
193
|
|
|
Date: |
194
|
|
|
2018 |
195
|
|
|
|
196
|
|
|
Author: |
197
|
|
|
Jan Popič and Klemen Berkovič |
198
|
|
|
|
199
|
|
|
License: |
200
|
|
|
MIT |
201
|
|
|
|
202
|
|
|
Reference URL: |
203
|
|
|
https://link.springer.com/article/10.1007/s10489-007-0091-x |
204
|
|
|
|
205
|
|
|
Reference paper: |
206
|
|
|
Brest, Janez, and Mirjam Sepesy Maučec. Population size reduction for the differential evolution algorithm. Applied Intelligence 29.3 (2008): 228-247. |
207
|
|
|
|
208
|
|
|
Attributes: |
209
|
|
|
Name (List[str]): List of strings representing algorithm name. |
210
|
|
|
""" |
211
|
|
|
Name = ['AgingSelfAdaptiveDifferentialEvolution', 'ANpjDE'] |
212
|
|
|
|
213
|
|
|
@staticmethod |
214
|
|
|
def algorithmInfo(): |
215
|
|
|
r"""Get basic information about the algorithm. |
216
|
|
|
|
217
|
|
|
Returns: |
218
|
|
|
str: Basic information. |
219
|
|
|
|
220
|
|
|
See Also: |
221
|
|
|
* :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
222
|
|
|
""" |
223
|
|
|
return r"""Brest, Janez, and Mirjam Sepesy Maučec. Population size reduction for the differential evolution algorithm. Applied Intelligence 29.3 (2008): 228-247.""" |
224
|
|
|
|
225
|
|
|
@staticmethod |
226
|
|
|
def typeParameters(): |
227
|
|
|
d = SelfAdaptiveDifferentialEvolution.typeParameters() |
228
|
|
|
# TODO |
229
|
|
|
return d |
230
|
|
|
|
231
|
|
|
def setParameters(self, LT_min=1, LT_max=7, age=proportional, **ukwargs): |
232
|
|
|
r"""Set core parameters of AgingSelfAdaptiveDifferentialEvolution algorithm. |
233
|
|
|
|
234
|
|
|
Args: |
235
|
|
|
LT_min (Optional[int]): Minimum age. |
236
|
|
|
LT_max (Optional[int]): Maximum age. |
237
|
|
|
age (Optional[Callable[[], int]]): Function for calculating age of individual. |
238
|
|
|
**ukwargs (Dict[str, Any]): Additional arguments. |
239
|
|
|
|
240
|
|
|
See Also: |
241
|
|
|
* :func:`SelfAdaptiveDifferentialEvolution.setParameters` |
242
|
|
|
""" |
243
|
|
|
SelfAdaptiveDifferentialEvolution.setParameters(self, **ukwargs) |
244
|
|
|
self.LT_min, self.LT_max, self.age = LT_min, LT_max, age |
245
|
|
|
self.mu = abs(self.LT_max - self.LT_min) / 2 |
246
|
|
|
|
247
|
|
|
class DynNpSelfAdaptiveDifferentialEvolutionAlgorithm(SelfAdaptiveDifferentialEvolution, DynNpDifferentialEvolution): |
248
|
|
|
r"""Implementation of Dynamic population size self-adaptive differential evolution algorithm. |
249
|
|
|
|
250
|
|
|
Algorithm: |
251
|
|
|
Dynamic population size self-adaptive differential evolution algorithm |
252
|
|
|
|
253
|
|
|
Date: |
254
|
|
|
2018 |
255
|
|
|
|
256
|
|
|
Author: |
257
|
|
|
Jan Popič and Klemen Berkovič |
258
|
|
|
|
259
|
|
|
License: |
260
|
|
|
MIT |
261
|
|
|
|
262
|
|
|
Reference URL: |
263
|
|
|
https://link.springer.com/article/10.1007/s10489-007-0091-x |
264
|
|
|
|
265
|
|
|
Reference paper: |
266
|
|
|
Brest, Janez, and Mirjam Sepesy Maučec. Population size reduction for the differential evolution algorithm. Applied Intelligence 29.3 (2008): 228-247. |
267
|
|
|
|
268
|
|
|
Attributes: |
269
|
|
|
Name (List[str]): List of strings representing algorithm name. |
270
|
|
|
rp (int): Small non-negative number which is added to value of generations. |
271
|
|
|
pmax (int): Number of population reductions. |
272
|
|
|
|
273
|
|
|
See Also: |
274
|
|
|
* :class:`NiaPy.algorithms.modified.SelfAdaptiveDifferentialEvolution` |
275
|
|
|
""" |
276
|
|
|
Name = ['DynNpSelfAdaptiveDifferentialEvolutionAlgorithm', 'dynNPjDE'] |
277
|
|
|
|
278
|
|
|
@staticmethod |
279
|
|
|
def algorithmInfo(): |
280
|
|
|
r"""Get basic information about the algorithm. |
281
|
|
|
|
282
|
|
|
Returns: |
283
|
|
|
str: Basic information. |
284
|
|
|
|
285
|
|
|
See Also: |
286
|
|
|
* :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
287
|
|
|
""" |
288
|
|
|
return r"""Brest, Janez, and Mirjam Sepesy Maučec. Population size reduction for the differential evolution algorithm. Applied Intelligence 29.3 (2008): 228-247.""" |
289
|
|
|
|
290
|
|
|
@staticmethod |
291
|
|
|
def typeParameters(): |
292
|
|
|
r"""Get basic information of algorithm. |
293
|
|
|
|
294
|
|
|
Returns: |
295
|
|
|
str: Basic information of algorithm. |
296
|
|
|
|
297
|
|
|
See Also: |
298
|
|
|
* :func:`NiaPy.algorithms.Algorithm.algorithmInfo` |
299
|
|
|
""" |
300
|
|
|
d = SelfAdaptiveDifferentialEvolution.typeParameters() |
301
|
|
|
d['rp'] = lambda x: isinstance(x, (float, int)) and x > 0 |
302
|
|
|
d['pmax'] = lambda x: isinstance(x, int) and x > 0 |
303
|
|
|
return d |
304
|
|
|
|
305
|
|
|
def setParameters(self, rp=0, pmax=10, **ukwargs): |
306
|
|
|
r"""Set the parameters of an algorithm. |
307
|
|
|
|
308
|
|
|
Arguments: |
309
|
|
|
rp (Optional[int]): Small non-negative number which is added to value of genp (if it's not divisible). |
310
|
|
|
pmax (Optional[int]): Number of population reductions. |
311
|
|
|
|
312
|
|
|
See Also: |
313
|
|
|
* :func:`NiaPy.algorithms.modified.SelfAdaptiveDifferentialEvolution.setParameters` |
314
|
|
|
""" |
315
|
|
|
DynNpDifferentialEvolution.setParameters(self, rp=rp, pmax=pmax, **ukwargs) |
316
|
|
|
SelfAdaptiveDifferentialEvolution.setParameters(self, **ukwargs) |
317
|
|
|
|
318
|
|
|
def postSelection(self, pop, task, **kwargs): |
319
|
|
|
r"""Post selection operator. |
320
|
|
|
|
321
|
|
|
Args: |
322
|
|
|
pop (numpy.ndarray[Individual]): Current population. |
323
|
|
|
task (Task): Optimization task. |
324
|
|
|
|
325
|
|
|
Returns: |
326
|
|
|
numpy.ndarray[Individual]: New population. |
327
|
|
|
""" |
328
|
|
|
return DynNpDifferentialEvolution.postSelection(self, pop, task, **kwargs) |
329
|
|
|
|
330
|
|
|
class MultiStrategySelfAdaptiveDifferentialEvolution(SelfAdaptiveDifferentialEvolution): |
331
|
|
|
r"""Implementation of self-adaptive differential evolution algorithm with multiple mutation strategys. |
332
|
|
|
|
333
|
|
|
Algorithm: |
334
|
|
|
Self-adaptive differential evolution algorithm with multiple mutation strategys |
335
|
|
|
|
336
|
|
|
Date: |
337
|
|
|
2018 |
338
|
|
|
|
339
|
|
|
Author: |
340
|
|
|
Klemen Berkovič |
341
|
|
|
|
342
|
|
|
License: |
343
|
|
|
MIT |
344
|
|
|
|
345
|
|
|
Attributes: |
346
|
|
|
Name (List[str]): List of strings representing algorithm name |
347
|
|
|
|
348
|
|
|
See Also: |
349
|
|
|
* :class:`NiaPy.algorithms.modified.SelfAdaptiveDifferentialEvolution` |
350
|
|
|
""" |
351
|
|
|
Name = ['MultiStrategySelfAdaptiveDifferentialEvolution', 'MsjDE'] |
352
|
|
|
|
353
|
|
|
def setParameters(self, strategies=(CrossCurr2Rand1, CrossCurr2Best1, CrossRand1, CrossBest1, CrossBest2), **kwargs): |
354
|
|
|
r"""Set core parameters of MultiStrategySelfAdaptiveDifferentialEvolution algorithm. |
355
|
|
|
|
356
|
|
|
Args: |
357
|
|
|
strategys (Optional[Iterable[Callable]]): Mutations strategies to use in algorithm. |
358
|
|
|
**kwargs: |
359
|
|
|
|
360
|
|
|
See Also: |
361
|
|
|
* :func:`NiaPy.algorithms.modified.SelfAdaptiveDifferentialEvolution.setParameters` |
362
|
|
|
""" |
363
|
|
|
SelfAdaptiveDifferentialEvolution.setParameters(self, CrossMutt=kwargs.pop('CrossMutt', multiMutations), **kwargs) |
364
|
|
|
self.strategies = strategies |
365
|
|
|
|
366
|
|
View Code Duplication |
def evolve(self, pop, xb, task, **kwargs): |
|
|
|
|
367
|
|
|
r"""Evolve population with the help multiple mutation strategies. |
368
|
|
|
|
369
|
|
|
Args: |
370
|
|
|
pop (numpy.ndarray[Individual]): Current population. |
371
|
|
|
xb (Individual): Current best individual. |
372
|
|
|
task (Task): Optimization task. |
373
|
|
|
**kwargs (Dict[str, Any]): Additional arguments. |
374
|
|
|
|
375
|
|
|
Returns: |
376
|
|
|
numpy.ndarray[Individual]: New population of individuals. |
377
|
|
|
""" |
378
|
|
|
return objects2array([self.CrossMutt(pop, i, xb, self.F, self.CR, self.Rand, task, self.itype, self.strategies) for i in range(len(pop))]) |
379
|
|
|
|
380
|
|
|
class DynNpMultiStrategySelfAdaptiveDifferentialEvolution(MultiStrategySelfAdaptiveDifferentialEvolution, DynNpSelfAdaptiveDifferentialEvolutionAlgorithm): |
381
|
|
|
r"""Implementation of Dynamic population size self-adaptive differential evolution algorithm with multiple mutation strategies. |
382
|
|
|
|
383
|
|
|
Algorithm: |
384
|
|
|
Dynamic population size self-adaptive differential evolution algorithm with multiple mutation strategies |
385
|
|
|
|
386
|
|
|
Date: |
387
|
|
|
2018 |
388
|
|
|
|
389
|
|
|
Author: |
390
|
|
|
Klemen Berkovič |
391
|
|
|
|
392
|
|
|
License: |
393
|
|
|
MIT |
394
|
|
|
|
395
|
|
|
Attributes: |
396
|
|
|
Name (List[str]): List of strings representing algorithm name. |
397
|
|
|
|
398
|
|
|
See Also: |
399
|
|
|
* :class:`NiaPy.algorithms.modified.MultiStrategySelfAdaptiveDifferentialEvolution` |
400
|
|
|
* :class:`NiaPy.algorithms.modified.DynNpSelfAdaptiveDifferentialEvolutionAlgorithm` |
401
|
|
|
""" |
402
|
|
|
Name = ['DynNpMultiStrategySelfAdaptiveDifferentialEvolution', 'dynNpMsjDE'] |
403
|
|
|
|
404
|
|
|
def setParameters(self, pmax=10, rp=5, **kwargs): |
405
|
|
|
r"""Set core parameters for algorithm instance. |
406
|
|
|
|
407
|
|
|
Args: |
408
|
|
|
pmax (Optional[int]): |
409
|
|
|
rp (Optional[int]): |
410
|
|
|
**kwargs (Dict[str, Any]): |
411
|
|
|
|
412
|
|
|
See Also: |
413
|
|
|
* :func:`NiaPy.algorithms.modified.MultiStrategySelfAdaptiveDifferentialEvolution.setParameters` |
414
|
|
|
""" |
415
|
|
|
MultiStrategySelfAdaptiveDifferentialEvolution.setParameters(self, **kwargs) |
416
|
|
|
self.pmax, self.rp = pmax, rp |
417
|
|
|
|
418
|
|
|
def postSelection(self, pop, task, **kwargs): |
419
|
|
|
return DynNpSelfAdaptiveDifferentialEvolutionAlgorithm.postSelection(self, pop, task) |
420
|
|
|
|
421
|
|
|
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3 |
422
|
|
|
|