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

GlowwormSwarmOptimization.rangeUpdate()   A

Complexity

Conditions 1

Size

Total Lines 12
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 4
dl 0
loc 12
rs 10
c 0
b 0
f 0
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