Passed
Pull Request — master (#202)
by
unknown
01:18
created

GlowwormSwarmOptimization.runIteration()   A

Complexity

Conditions 3

Size

Total Lines 32
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nop 10
dl 0
loc 32
rs 9.9
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, line-too-long, multiple-statements, attribute-defined-outside-init, logging-not-lazy, no-self-use, redefined-builtin, singleton-comparison, unused-argument, arguments-differ, no-else-return, bad-continuation
3
import logging
4
5
from scipy.spatial.distance import euclidean
6
from numpy import full, apply_along_axis, copy, sum, fmax, pi, where
7
8
from NiaPy.algorithms.algorithm import Algorithm
9
10
logging.basicConfig()
11
logger = logging.getLogger('NiaPy.algorithms.basic')
12
logger.setLevel('INFO')
13
14
__all__ = ['GlowwormSwarmOptimization', 'GlowwormSwarmOptimizationV1', 'GlowwormSwarmOptimizationV2', 'GlowwormSwarmOptimizationV3']
15
16
class GlowwormSwarmOptimization(Algorithm):
17
	r"""Implementation of glowwarm swarm optimization.
18
19
	Algorithm:
20
		Glowwarm Swarm Optimization Algorithm
21
22
	Date:
23
		2018
24
25
	Authors:
26
		Klemen Berkovič
27
28
	License:
29
		MIT
30
31
	Reference URL:
32
		https://www.springer.com/gp/book/9783319515946
33
34
	Reference paper:
35
		Kaipa, Krishnanand N., and Debasish Ghose. Glowworm swarm optimization: theory, algorithms, and applications. Vol. 698. Springer, 2017.
36
37
	Attributes:
38
		Name (List[str]): List of strings represeinting algorithm name.
39
		l0 (float): Initial luciferin quantity for each glowworm.
40
		nt (float): --
41
		rs (float): Maximum sensing range.
42
		rho (float): Luciferin decay constant.
43
		gamma (float): Luciferin enhancement constant.
44
		beta (float): --
45
		s (float): --
46
		Distance (Callable[[numpy.ndarray, numpy.ndarray], float]]): Measure distance between two individuals.
47
48
	See Also:
49
		* :class:`NiaPy.algorithms.algorithm.Algorithm`
50
	"""
51
	Name = ['GlowwormSwarmOptimization', 'GSO']
52
53
	@staticmethod
54
	def typeParameters():
55
		r"""Get dictionary with functions for checking values of parameters.
56
57
		Returns:
58
			Dict[str, Callable]:
59
				* n (Callable[[int], bool]): TODO
60
				* l0 (Callable[[Union[float, int]], bool]): TODO
61
				* nt (Callable[[Union[float, int]], bool]): TODO
62
				* rho (Callable[[Union[float, int]], bool]): TODO
63
				* gamma (Callable[[float], bool]): TODO
64
				* beta (Callable[[float], bool]): TODO
65
				* s (Callable[[float], bool]): TODO
66
		"""
67
		return {
68
			'n': lambda x: isinstance(x, int) and x > 0,
69
			'l0': lambda x: isinstance(x, (float, int)) and x > 0,
70
			'nt': lambda x: isinstance(x, (float, int)) and x > 0,
71
			'rho': lambda x: isinstance(x, float) and 0 < x < 1,
72
			'gamma': lambda x: isinstance(x, float) and 0 < x < 1,
73
			'beta': lambda x: isinstance(x, float) and x > 0,
74
			's': lambda x: isinstance(x, float) and x > 0
75
		}
76
77
	def setParameters(self, n=25, l0=5, nt=5, rho=0.4, gamma=0.6, beta=0.08, s=0.03, Distance=euclidean, **ukwargs):
78
		r"""Set the arguments of an algorithm.
79
80
		Arguments:
81
			n (Optional[int]): Number of glowworms in population.
82
			l0 (Optional[float]): Initial luciferin quantity for each glowworm.
83
			nt (Optional[float]): --
84
			rs (Optional]float]): Maximum sensing range.
85
			rho (Optional[float]): Luciferin decay constant.
86
			gamma (Optional[float]): Luciferin enhancement constant.
87
			beta (Optional[float]): --
88
			s (Optional[float]): --
89
			Distance (Optional[Callable[[numpy.ndarray, numpy.ndarray], float]]]): Measure distance between two individuals.
90
		"""
91
		ukwargs.pop('NP', None)
92
		Algorithm.setParameters(self, NP=n, **ukwargs)
93
		self.l0, self.nt, self.rho, self.gamma, self.beta, self.s, self.Distance = l0, nt, rho, gamma, beta, s, Distance
94
		if ukwargs: logger.info('Unused arguments: %s' % (ukwargs))
95
96
	def randMove(self, i):
97
		r"""Move a glowworm to another glowworm.
98
99
		Args:
100
			i (int): Index of glowworm that is making a move.
101
102
		Returns:
103
			int: Index of glowworm to move to.
104
		"""
105
		j = i
106
		while i == j: j = self.randint(self.n)
107
		return j
108
109
	def getNeighbors(self, i, r, GS, L):
110
		r"""Get neighbours of glowworm.
111
112
		Args:
113
			i (int): Index of glowworm.
114
			r (float): Neighborhood distance.
115
			GS (numpy.ndarray):
116
			L (numpy.ndarray[float]): Luciferin value of glowworm.
117
118
		Returns:
119
			numpy.ndarray[int]: Indexes of neighborhood glowworms.
120
		"""
121
		N = full(self.NP, 0)
122
		for j, gw in enumerate(GS): N[j] = 1 if i != j and self.Distance(GS[i], gw) <= r and L[i] >= L[j] else 0
123
		return N
124
125
	def probabilityes(self, i, N, L):
126
		r"""TODO.
127
128
		Args:
129
			i:
130
			N:
131
			L:
132
133
		Returns:
134
135
		"""
136
		d, P = sum(L[where(N == 1)] - L[i]), full(self.NP, .0)
137
		for j in range(self.NP): P[i] = ((L[j] - L[i]) / d) if N[j] == 1 else 0
138
		return P
139
140
	def moveSelect(self, pb, i):
141
		r"""TODO.
142
143
		Args:
144
			pb:
145
			i:
146
147
		Returns:
148
149
		"""
150
		r, b_l, b_u = self.rand(), 0, 0
151
		for j in range(self.NP):
152
			b_l, b_u = b_u, b_u + pb[i]
153
			if b_l < r < b_u: return j
154
		return self.randint(self.NP)
155
156
	def calcLuciferin(self, L, GS_f):
157
		r"""TODO.
158
159
		Args:
160
			L:
161
			GS_f:
162
163
		Returns:
164
165
		"""
166
		return (1 - self.rho) * L + self.gamma * GS_f
167
168
	def rangeUpdate(self, R, N, rs):
169
		r"""TODO.
170
171
		Args:
172
			R:
173
			N:
174
			rs:
175
176
		Returns:
177
178
		"""
179
		return R + self.beta * (self.nt - sum(N))
180
181
	def initPopulation(self, task):
182
		r"""Initialize population.
183
184
		Args:
185
			task (Task): Optimization task.
186
187
		Returns:
188
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
189
				1. Initialized population of glowwarms.
190
				2. Initialized populations function/fitness values.
191
				3. Additional arguments:
192
					* L (numpy.ndarray): TODO.
193
					* R (numpy.ndarray): TODO.
194
					* rs (numpy.ndarray): TODO.
195
		"""
196
		GS, GS_f, d = Algorithm.initPopulation(self, task)
197
		rs = euclidean(full(task.D, 0), task.bRange)
198
		L, R = full(self.NP, self.l0), full(self.NP, rs)
199
		d.update({'L': L, 'R': R, 'rs': rs})
200
		return GS, GS_f, d
201
202
	def runIteration(self, task, GS, GS_f, xb, fxb, L, R, rs, **dparams):
203
		r"""Core function of GlowwormSwarmOptimization algorithm.
204
205
		Args:
206
			task (Task): Optimization taks.
207
			GS (numpy.ndarray): Current population.
208
			GS_f (numpy.ndarray[float]): Current populations fitness/function values.
209
			xb (numpy.ndarray): Global best individual.
210
			fxb (float): Global best individuals function/fitness value.
211
			L (numpy.ndarray):
212
			R (numpy.ndarray):
213
			rs (numpy.ndarray):
214
			**dparams Dict[str, Any]: Additional arguments.
215
216
		Returns:
217
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
218
				1. Initialized population of glowwarms.
219
				2. Initialized populations function/fitness values.
220
				3. Additional arguments:
221
					* L (numpy.ndarray): TODO.
222
					* R (numpy.ndarray): TODO.
223
					* rs (numpy.ndarray): TODO.
224
		"""
225
		GSo, Ro = copy(GS), copy(R)
226
		L = self.calcLuciferin(L, GS_f)
227
		N = [self.getNeighbors(i, Ro[i], GSo, L) for i in range(self.NP)]
228
		P = [self.probabilityes(i, N[i], L) for i in range(self.NP)]
229
		j = [self.moveSelect(P[i], i) for i in range(self.NP)]
230
		for i in range(self.NP): GS[i] = task.repair(GSo[i] + self.s * ((GSo[j[i]] - GSo[i]) / (self.Distance(GSo[j[i]], GSo[i]) + 1e-31)), rnd=self.Rand)
231
		for i in range(self.NP): R[i] = max(0, min(rs, self.rangeUpdate(Ro[i], N[i], rs)))
232
		GS_f = apply_along_axis(task.eval, 1, GS)
233
		return GS, GS_f, {'L': L, 'R': R, 'rs': rs}
234
235
class GlowwormSwarmOptimizationV1(GlowwormSwarmOptimization):
236
	r"""Implementation of glowwarm swarm optimization.
237
238
	Algorithm:
239
		Glowwarm Swarm Optimization Algorithm
240
241
	Date:
242
		2018
243
244
	Authors:
245
		Klemen Berkovič
246
247
	License:
248
		MIT
249
250
	Reference URL:
251
		https://www.springer.com/gp/book/9783319515946
252
253
	Reference paper:
254
		Kaipa, Krishnanand N., and Debasish Ghose. Glowworm swarm optimization: theory, algorithms, and applications. Vol. 698. Springer, 2017.
255
256
	Attributes:
257
		Name (List[str]): List of strings representing algorithm names.
258
		alpha (float): --
259
260
	See Also:
261
		* :class:`NiaPy.algorithms.basic.GlowwormSwarmOptimization`
262
	"""
263
	Name = ['GlowwormSwarmOptimizationV1', 'GSOv1']
264
265
	def setParameters(self, **kwargs):
266
		self.__setParams(**kwargs)
267
		GlowwormSwarmOptimization.setParameters(self, **kwargs)
268
269
	def __setParams(self, alpha=0.2, **ukwargs):
270
		r"""Set the arguments of an algorithm.
271
272
		Arguments:
273
			alpha (float): --
274
		"""
275
		self.alpha = alpha
276
		if ukwargs: logger.info('Unused arguments: %s' % (ukwargs))
277
278
	def calcLuciferin(self, L, GS_f):
279
		r"""TODO.
280
281
		Args:
282
			L:
283
			GS_f:
284
285
		Returns:
286
287
		"""
288
		return fmax(0, (1 - self.rho) * L + self.gamma * GS_f)
289
290
	def rangeUpdate(self, R, N, rs):
291
		r"""TODO.
292
293
		Args:
294
			R:
295
			N:
296
			rs:
297
298
		Returns:
299
300
		"""
301
		return rs / (1 + self.beta * (sum(N) / (pi * rs ** 2)))
302
303
class GlowwormSwarmOptimizationV2(GlowwormSwarmOptimization):
304
	r"""Implementation of glowwarm swarm optimization.
305
306
	Algorithm:
307
		Glowwarm Swarm Optimization Algorithm
308
309
	Date:
310
		2018
311
312
	Authors:
313
		Klemen Berkovič
314
315
	License:
316
		MIT
317
318
	Reference URL:
319
		https://www.springer.com/gp/book/9783319515946
320
321
	Reference paper:
322
		Kaipa, Krishnanand N., and Debasish Ghose. Glowworm swarm optimization: theory, algorithms, and applications. Vol. 698. Springer, 2017.
323
324
	Attributes:
325
		Name (List[str]): List of strings representing algorithm names.
326
		alpha (float): --
327
328
	See Also:
329
		* :class:`NiaPy.algorithms.basic.GlowwormSwarmOptimization`
330
	"""
331
	Name = ['GlowwormSwarmOptimizationV2', 'GSOv2']
332
333
	def setParameters(self, alpha=0.2, **kwargs):
334
		r"""Set core parameters for GlowwormSwarmOptimizationV2 algorithm.
335
336
		Args:
337
			alpha (Optional[float]): --
338
			**kwargs (Dict[str, Any]): Additional arguments.
339
340
		See Also:
341
			* :func:`NiaPy.algorithms.basic.GlowwormSwarmOptimization.setParameters`
342
		"""
343
		GlowwormSwarmOptimization.setParameters(self, **kwargs)
344
		self.alpha = alpha
345
		if kwargs: logger.info('Unused arguments: %s' % (kwargs))
346
347
	def rangeUpdate(self, P, N, rs):
348
		r"""TODO.
349
350
		Args:
351
			P:
352
			N:
353
			rs:
354
355
		Returns:
356
			float: TODO
357
		"""
358
		return self.alpha + (rs - self.alpha) / (1 + self.beta * sum(N))
359
360
class GlowwormSwarmOptimizationV3(GlowwormSwarmOptimization):
361
	r"""Implementation of glowwarm swarm optimization.
362
363
	Algorithm:
364
		Glowwarm Swarm Optimization Algorithm
365
366
	Date:
367
		2018
368
369
	Authors:
370
		Klemen Berkovič
371
372
	License:
373
		MIT
374
375
	Reference URL:
376
		https://www.springer.com/gp/book/9783319515946
377
378
	Reference paper:
379
		Kaipa, Krishnanand N., and Debasish Ghose. Glowworm swarm optimization: theory, algorithms, and applications. Vol. 698. Springer, 2017.
380
381
	Attributes:
382
		Name (List[str]): List of strings representing algorithm names.
383
		beta1 (float): --
384
385
	See Also:
386
		* :class:`NiaPy.algorithms.basic.GlowwormSwarmOptimization`
387
	"""
388
	Name = ['GlowwormSwarmOptimizationV3', 'GSOv3']
389
390
	def setParameters(self, beta1=0.2, **kwargs):
391
		r"""Set core parameters for GlowwormSwarmOptimizationV3 algorithm.
392
393
		Args:
394
			beta1 (Optional[float]): --
395
			**kwargs (Dict[str, Any]): Additional arguments.
396
397
		See Also:
398
			* :func:`NiaPy.algorithms.basic.GlowwormSwarmOptimization.setParameters`
399
		"""
400
		GlowwormSwarmOptimization.setParameters(self, **kwargs)
401
		self.beta1 = beta1
402
		if kwargs: logger.info('Unused arguments: %s' % (kwargs))
403
404
	def rangeUpdate(self, R, N, rs):
405
		r"""TODO.
406
407
		Args:
408
			R:
409
			N:
410
			rs:
411
412
		Returns:
413
414
		"""
415
		return R + (self.beta * sum(N)) if sum(N) < self.nt else (-self.beta1 * sum(N))
416
417
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
418