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

MonkeyKingEvolutionV3.runIteration()   A

Complexity

Conditions 4

Size

Total Lines 31
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nop 9
dl 0
loc 31
rs 9.85
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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