Passed
Pull Request — master (#202)
by Grega
01:02
created

MonkeyKingEvolutionV3.algorithmInfo()   A

Complexity

Conditions 1

Size

Total Lines 11
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 0
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
# encoding=utf8
2
# pylint: disable=mixed-indentation, trailing-whitespace, multiple-statements, attribute-defined-outside-init, logging-not-lazy, no-self-use, len-as-condition, singleton-comparison, arguments-differ, bad-continuation
3
import logging
4
from math import ceil
5
6
from numpy import apply_along_axis, vectorize, argmin, argmax, full, tril
7
8
from NiaPy.algorithms.algorithm import Algorithm, Individual, defaultIndividualInit, defaultNumPyInit
9
10
logging.basicConfig()
11
logger = logging.getLogger('NiaPy.algorithms.basic')
12
logger.setLevel('INFO')
13
14
__all__ = ['MonkeyKingEvolutionV1', 'MonkeyKingEvolutionV2', 'MonkeyKingEvolutionV3']
15
16
class MkeSolution(Individual):
17
	r"""Implementation of Monkey King Evolution individual.
18
19
	Data:
20
		2018
21
22
	Authors:
23
		Klemen Berkovič
24
25
	License:
26
		MIT
27
28
	Attributes:
29
		x_pb (array of (float or int)): Personal best position of Monkey particle.
30
		f_pb (float): Personal best fitness/function value.
31
		MonkeyKing (bool): Boolean value indicating if particle is Monkey King particle.
32
33
	See Also:
34
		* :class:`NiaPy.algorithms.Individual`
35
	"""
36
	def __init__(self, **kwargs):
37
		r"""Initialize Monkey particle.
38
39
		Args:
40
			**kwargs: Additional arguments
41
42
		See Also:
43
			* :class:`NiaPy.algorithms.Individual.__init__()`
44
		"""
45
		Individual.__init__(self, **kwargs)
46
		self.f_pb, self.x_pb = self.f, self.x
47
		self.MonkeyKing = False
48
49
	def uPersonalBest(self):
50
		r"""Update presonal best position of particle."""
51
		if self.f < self.f_pb: self.x_pb, self.f_pb = self.x, self.f
52
53
class MonkeyKingEvolutionV1(Algorithm):
54
	r"""Implementation of monkey king evolution algorithm version 1.
55
56
	Algorithm:
57
		Monkey King Evolution version 1
58
59
	Date:
60
		2018
61
62
	Authors:
63
		Klemen Berkovič
64
65
	License:
66
		MIT
67
68
	Reference URL:
69
		https://www.sciencedirect.com/science/article/pii/S0950705116000198
70
71
	Reference paper:
72
		Zhenyu Meng, Jeng-Shyang Pan, Monkey King Evolution: A new memetic evolutionary algorithm and its application in vehicle fuel consumption optimization, Knowledge-Based Systems, Volume 97, 2016, Pages 144-157, ISSN 0950-7051, https://doi.org/10.1016/j.knosys.2016.01.009.
73
74
	Attributes:
75
		Name (List[str]): List of strings representing algorithm names.
76
		F (float): Scale factor for normal particles.
77
		R (float): TODO.
78
		C (int): Number of new particles generated by Monkey King particle.
79
		FC (float): Scale factor for Monkey King particles.
80
81
	See Also:
82
		* :class:`NiaPy.algorithms.algorithm.Algorithm`
83
	"""
84
	Name = ['MonkeyKingEvolutionV1', 'MKEv1']
85
86
	@staticmethod
87
	def algorithmInfo():
88
		r"""Get basic information of algorithm.
89
90
		Returns:
91
			str: Basic information.
92
93
		See Also:
94
			* :func:`NiaPy.algorithms.Algorithm.algorithmInfo`
95
		"""
96
		return r"""Zhenyu Meng, Jeng-Shyang Pan, Monkey King Evolution: A new memetic evolutionary algorithm and its application in vehicle fuel consumption optimization, Knowledge-Based Systems, Volume 97, 2016, Pages 144-157, ISSN 0950-7051, https://doi.org/10.1016/j.knosys.2016.01.009."""
97
98 View Code Duplication
	@staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
99
	def typeParameters():
100
		r"""Get dictionary with functions for checking values of parameters.
101
102
		Returns:
103
			Dict[str, Callable]:
104
				* F (Callable[[int], bool])
105
				* R (Callable[[Union[int, float]], bool])
106
				* C (Callable[[Union[int, float]], bool])
107
				* FC (Callable[[Union[int, float]], bool])
108
		"""
109
		d = Algorithm.typeParameters()
110
		d.update({
111
			'NP': lambda x: isinstance(x, int) and x > 0,
112
			'F': lambda x: isinstance(x, (float, int)) and x > 0,
113
			'R': lambda x: isinstance(x, (float, int)) and x > 0,
114
			'C': lambda x: isinstance(x, int) and x > 0,
115
			'FC': lambda x: isinstance(x, (float, int)) and x > 0
116
		})
117
		return d
118
119
	def setParameters(self, NP=40, F=0.7, R=0.3, C=3, FC=0.5, **ukwargs):
120
		r"""Set Monkey King Evolution v1 algorithms static parameters.
121
122
		Args:
123
			NP (int): Population size.
124
			F (float): Scale factor for normal particle.
125
			R (float): Procentual value of now many new particle Monkey King particle creates. Value in rage [0, 1].
126
			C (int): Number of new particles generated by Monkey King particle.
127
			FC (float): Scale factor for Monkey King particles.
128
			**ukwargs (Dict[str, Any]): Additional arguments.
129
130
		See Also:
131
			* :func:`NiaPy.algorithms.algorithm.Algorithm.setParameters`
132
		"""
133
		Algorithm.setParameters(self, NP=NP, itype=ukwargs.pop('itype', MkeSolution), InitPopFunc=ukwargs.pop('InitPopFunc', defaultIndividualInit), **ukwargs)
134
		self.F, self.R, self.C, self.FC = F, R, C, FC
135
		if ukwargs: logger.info('Unused arguments: %s' % (ukwargs))
136
137
	def moveP(self, x, x_pb, x_b, task):
138
		r"""Move normal particle in search space.
139
140
		For moving particles algorithm uses next formula:
141
		:math:`\mathbf{x_{pb} - \mathit{F} \odot \mathbf{r} \odot (\mathbf{x_b} - \mathbf{x})`
142
		where
143
		:math:`\mathbf{r}` is one dimension array with `D` components. Components in this vector are in range [0, 1].
144
145
		Args:
146
			x (numpy.ndarray): Paticle position.
147
			x_pb (numpy.ndarray): Particle best position.
148
			x_b (numpy.ndarray): Best particle position.
149
			task (Task): Optimization task.
150
151
		Returns:
152
			numpy.ndarray: Particle new position.
153
		"""
154
		return x_pb + self.F * self.rand(task.D) * (x_b - x)
155
156
	def moveMK(self, x, task):
157
		r"""Move Mokey King paticle.
158
159
		For moving Monkey King particles algorithm uses next formula:
160
		:math:`\mathbf{x} + \mathit{FC} \odot \mathbf{R} \odot \mathbf{x}`
161
		where
162
		:math:`\mathbf{R}` is two dimensional array with shape `{C * D, D}`. Componentes of this array are in range [0, 1]
163
164
		Args:
165
			x (numpy.ndarray): Monkey King patricle position.
166
			task (Task): Optimization task.
167
168
		Returns:
169
			numpy.ndarray: New particles generated by Monkey King particle.
170
		"""
171
		return x + self.FC * self.rand([int(self.C * task.D), task.D]) * x
172
173
	def movePartice(self, p, p_b, task):
174
		r"""Move patricles.
175
176
		Args:
177
			p (MkeSolution): Monke particle.
178
			p_b (MkeSolution): Population best particle.
179
			task (Task): Optimization task.
180
		"""
181
		p.x = self.moveP(p.x, p.x_pb, p_b.x, task)
182
		p.evaluate(task, rnd=self.Rand)
183
184
	def moveMokeyKingPartice(self, p, task):
185
		r"""Move Monky King Particles.
186
187
		Args:
188
			p (MkeSolution): Monkey King particle to apply this function on.
189
			task (Task): Optimization task
190
		"""
191
		p.MonkeyKing = False
192
		A = apply_along_axis(task.repair, 1, self.moveMK(p.x, task), self.Rand)
193
		A_f = apply_along_axis(task.eval, 1, A)
194
		ib = argmin(A_f)
195
		p.x, p.f = A[ib], A_f[ib]
196
197
	def movePopulation(self, pop, xb, task):
198
		r"""Move population.
199
200
		Args:
201
			pop (numpy.ndarray[MkeSolution]): Current population.
202
			xb (MkeSolution): Current best solution.
203
			task (Task): Optimization task.
204
205
		Returns:
206
			numpy.ndarray[MkeSolution]: New particles.
207
		"""
208
		for p in pop:
209
			if p.MonkeyKing: self.moveMokeyKingPartice(p, task)
210
			else: self.movePartice(p, xb, task)
211
			p.uPersonalBest()
212
		return pop
213
214
	def initPopulation(self, task):
215
		r"""Init population.
216
217
		Args:
218
			task (Task): Optimization task
219
220
		Returns:
221
			Tuple(numpy.ndarray[MkeSolution], numpy.ndarray[float], Dict[str, Any]]:
222
				1. Initialized solutions
223
				2. Fitness/function values of solution
224
				3. Additional arguments
225
		"""
226
		pop, fpop, _ = Algorithm.initPopulation(self, task)
227
		for i in self.Rand.choice(self.NP, int(self.R * len(pop)), replace=False): pop[i].MonkeyKing = True
228
		return pop, fpop, {}
229
230
	def runIteration(self, task, pop, fpop, xb, fxb, **dparams):
231
		r"""Core function of Monkey King Evolution v1 algorithm.
232
233
		Args:
234
			task (Task): Optimization task
235
			pop (numpy.ndarray[MkeSolution]): Current population
236
			fpop (numpy.ndarray[float]): Current population fitness/function values
237
			xb (MkeSolution): Current best solution.
238
			fxb (float): Current best solutions function/fitness value.
239
			**dparams (Dict[str, Any]): Additional arguments.
240
241
		Returns:
242
			Tuple(numpy.ndarray[MkeSolution], numpy.ndarray[float], Dict[str, Any]]:
243
				1. Initialized solutions.
244
				2. Fitness/function values of solution.
245
				3. Additional arguments.
246
		"""
247
		pop = self.movePopulation(pop, xb, task)
248
		for i in self.Rand.choice(self.NP, int(self.R * len(pop)), replace=False): pop[i].MonkeyKing = True
249
		return pop, [m.f for m in pop], {}
250
251
class MonkeyKingEvolutionV2(MonkeyKingEvolutionV1):
252
	r"""Implementation of monkey king evolution algorithm version 2.
253
254
	Algorithm:
255
		Monkey King Evolution version 2
256
257
	Date:
258
		2018
259
260
	Authors:
261
		Klemen Berkovič
262
263
	License:
264
		MIT
265
266
	Reference URL:
267
		https://www.sciencedirect.com/science/article/pii/S0950705116000198
268
269
	Reference paper:
270
		Zhenyu Meng, Jeng-Shyang Pan, Monkey King Evolution: A new memetic evolutionary algorithm and its application in vehicle fuel consumption optimization, Knowledge-Based Systems, Volume 97, 2016, Pages 144-157, ISSN 0950-7051, https://doi.org/10.1016/j.knosys.2016.01.009.
271
272
	Attributes:
273
		Name (List[str]): List of strings representing algorithm names.
274
275
	See Also:
276
		* :class:`NiaPy.algorithms.basic.mke.MonkeyKingEvolutionV1`
277
	"""
278
	Name = ['MonkeyKingEvolutionV2', 'MKEv2']
279
280
	@staticmethod
281
	def algorithmInfo():
282
		r"""Get basic information of algorithm.
283
284
		Returns:
285
			str: Basic information.
286
287
		See Also:
288
			* :func:`NiaPy.algorithms.Algorithm.algorithmInfo`
289
		"""
290
		return r"""Zhenyu Meng, Jeng-Shyang Pan, Monkey King Evolution: A new memetic evolutionary algorithm and its application in vehicle fuel consumption optimization, Knowledge-Based Systems, Volume 97, 2016, Pages 144-157, ISSN 0950-7051, https://doi.org/10.1016/j.knosys.2016.01.009."""
291
292
	def moveMK(self, x, dx, task):
293
		r"""Move Monkey King particle.
294
295
		For movment of particles algorithm uses next formula:
296
		:math:`\mathbf{x} - \mathit{FC} \odot \mathbf{dx}`
297
298
		Args:
299
			x (numpy.ndarray): Particle to apply movment on.
300
			dx (numpy.ndarray): Difference between to random paricles in population.
301
			task (Task): Optimization task.
302
303
		Returns:
304
			numpy.ndarray: Moved particles.
305
		"""
306
		return x - self.FC * dx
307
308
	def moveMokeyKingPartice(self, p, pop, task):
309
		r"""Move Monkey King particles.
310
311
		Args:
312
			p (MkeSolution): Monkey King particle to move.
313
			pop (numpy.ndarray[MkeSolution]): Current population.
314
			task (Task): Optimization task.
315
		"""
316
		p.MonkeyKing = False
317
		p_b, p_f = p.x, p.f
318
		for _i in range(int(self.C * self.NP)):
319
			r = self.Rand.choice(self.NP, 2, replace=False)
320
			a = task.repair(self.moveMK(p.x, pop[r[0]].x - pop[r[1]].x, task), self.Rand)
321
			a_f = task.eval(a)
322
			if a_f < p_f: p_b, p_f = a, a_f
323
		p.x, p.f = p_b, p_f
324
325
	def movePopulation(self, pop, xb, task):
326
		r"""Move population.
327
328
		Args:
329
			pop (numpy.ndarray[MkeSolution]): Current population.
330
			xb (MkeSolution): Current best solution.
331
			task (Task): Optimization task.
332
333
		Returns:
334
			numpy.ndarray[MkeSolution]: Moved population.
335
		"""
336
		for p in pop:
337
			if p.MonkeyKing: self.moveMokeyKingPartice(p, pop, task)
338
			else: self.movePartice(p, xb, task)
339
			p.uPersonalBest()
340
		return pop
341
342
class MonkeyKingEvolutionV3(MonkeyKingEvolutionV1):
343
	r"""Implementation of monkey king evolution algorithm version 3.
344
345
	Algorithm:
346
		Monkey King Evolution version 3
347
348
	Date:
349
		2018
350
351
	Authors:
352
		Klemen Berkovič
353
354
	License:
355
		MIT
356
357
	Reference URL:
358
		https://www.sciencedirect.com/science/article/pii/S0950705116000198
359
360
	Reference paper:
361
		Zhenyu Meng, Jeng-Shyang Pan, Monkey King Evolution: A new memetic evolutionary algorithm and its application in vehicle fuel consumption optimization, Knowledge-Based Systems, Volume 97, 2016, Pages 144-157, ISSN 0950-7051, https://doi.org/10.1016/j.knosys.2016.01.009.
362
363
	Attributes:
364
		Name (List[str]): List of strings that represent algorithm names.
365
366
	See Also:
367
		* :class:`NiaPy.algorithms.basic.mke.MonkeyKingEvolutionV1`
368
	"""
369
	Name = ['MonkeyKingEvolutionV3', 'MKEv3']
370
371
	@staticmethod
372
	def algorithmInfo():
373
		r"""Get basic information of algorithm.
374
375
		Returns:
376
			str: Basic information.
377
378
		See Also:
379
			* :func:`NiaPy.algorithms.Algorithm.algorithmInfo`
380
		"""
381
		return r"""Zhenyu Meng, Jeng-Shyang Pan, Monkey King Evolution: A new memetic evolutionary algorithm and its application in vehicle fuel consumption optimization, Knowledge-Based Systems, Volume 97, 2016, Pages 144-157, ISSN 0950-7051, https://doi.org/10.1016/j.knosys.2016.01.009."""
382
383
	def setParameters(self, **ukwargs):
384
		r"""Set core parameters of MonkeyKingEvolutionV3 algorithm.
385
386
		Args:
387
			**ukwargs (Dict[str, Any]): Additional arguments.
388
389
		See Also:
390
			* :func:`NiaPy.algorithms.basic.MonkeyKingEvolutionV1.setParameters`
391
		"""
392
		MonkeyKingEvolutionV1.setParameters(self, itype=ukwargs.pop('itype', None), InitPopFunc=ukwargs.pop('InitPopFunc', defaultNumPyInit), **ukwargs)
393
394
	def neg(self, x):
395
		r"""Transform function.
396
397
		Args:
398
			x (Union[int, float]): Sould be 0 or 1.
399
400
		Returns:
401
			float: If 0 thet 1 else 1 then 0.
402
		"""
403
		return 0.0 if x == 1.0 else 1.0
404
405
	def initPopulation(self, task):
406
		r"""Initialize the population.
407
408
		Args:
409
			task (Task): Optimization task.
410
411
		Returns:
412
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
413
				1. Initialized population.
414
				2. Initialized population function/fitness values.
415
				3. Additional arguments:
416
					* k (int): TODO.
417
					* c (int): TODO.
418
419
		See Also:
420
			* :func:`NiaPy.algorithms.algorithm.Algorithm.initPopulation`
421
		"""
422
		X, X_f, d = Algorithm.initPopulation(self, task)
423
		k, c = int(ceil(self.NP / task.D)), int(ceil(self.C * task.D))
424
		d.update({'k': k, 'c': c})
425
		return X, X_f, d
426
427
	def runIteration(self, task, X, X_f, xb, fxb, k, c, **dparams):
428
		r"""Core funciton of Monkey King Evolution v3 algorithm.
429
430
		Args:
431
			task (Task): Optimization task
432
			X (numpy.ndarray): Current population
433
			X_f (numpy.ndarray[float]): Current population fitness/function values
434
			xb (numpy.ndarray): Current best individual
435
			fxb (float): Current best individual function/fitness value
436
			k (int): TODO
437
			c (int: TODO
438
			**dparams: Additional arguments
439
440
		Returns:
441
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
442
				1. Initialized population.
443
				2. Initialized population function/fitness values.
444
				3. Additional arguments:
445
					* k (int): TODO.
446
					* c (int): TODO.
447
		"""
448
		X_gb = apply_along_axis(task.repair, 1, xb + self.FC * X[self.Rand.choice(len(X), c)] - X[self.Rand.choice(len(X), c)], self.Rand)
449
		X_gb_f = apply_along_axis(task.eval, 1, X_gb)
450
		M = full([self.NP, task.D], 1.0)
451
		for i in range(k): M[i * task.D:(i + 1) * task.D] = tril(M[i * task.D:(i + 1) * task.D])
452
		for i in range(self.NP): self.Rand.shuffle(M[i])
453
		X = apply_along_axis(task.repair, 1, M * X + vectorize(self.neg)(M) * xb, self.Rand)
454
		X_f = apply_along_axis(task.eval, 1, X)
455
		iw, ib_gb = argmax(X_f), argmin(X_gb_f)
456
		if X_gb_f[ib_gb] <= X_f[iw]: X[iw], X_f[iw] = X_gb[ib_gb], X_gb_f[ib_gb]
457
		return X, X_f, {'k': k, 'c': c}
458
459
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
460