SelfAdaptiveBatAlgorithm.runIteration()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 37
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 11
nop 12
dl 0
loc 37
rs 8.6666
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
import logging
3
4
import numpy as np
5
6
from NiaPy.algorithms.algorithm import Algorithm
7
8
logging.basicConfig()
9
logger = logging.getLogger('NiaPy.algorithms.modified')
10
logger.setLevel('INFO')
11
12
__all__ = ['AdaptiveBatAlgorithm', 'SelfAdaptiveBatAlgorithm']
13
14
class AdaptiveBatAlgorithm(Algorithm):
15
	r"""Implementation of Adaptive bat algorithm.
16
17
	Algorithm:
18
		Adaptive bat algorithm
19
20
	Date:
21
		April 2019
22
23
	Authors:
24
		Klemen Berkovič
25
26
	License:
27
		MIT
28
29
	Attributes:
30
		Name (List[str]): List of strings representing algorithm name.
31
		epsilon (float): Scaling factor.
32
		alpha (float): Constant for updating loudness.
33
		r (float): Pulse rate.
34
		Qmin (float): Minimum frequency.
35
		Qmax (float): Maximum frequency.
36
37
	See Also:
38
		* :class:`NiaPy.algorithms.Algorithm`
39
	"""
40
	Name = ['AdaptiveBatAlgorithm', 'ABA']
41
42
	@staticmethod
43
	def algorithmInfo():
44
		r"""Get basic information about the algorithm.
45
46
		Returns:
47
			str: Basic information.
48
49
		See Also:
50
			* :func:`NiaPy.algorithms.Algorithm.algorithmInfo`
51
		"""
52
		return r"""TODO"""
53
54
	@staticmethod
55
	def typeParameters():
56
		r"""Return dict with where key of dict represents parameter name and values represent checking functions for selected parameter.
57
58
		Returns:
59
			Dict[str, Callable]:
60
				* epsilon (Callable[[Union[float, int]], bool]): Scale factor.
61
				* alpha (Callable[[Union[float, int]], bool]): Constant for updating loudness.
62
				* r (Callable[[Union[float, int]], bool]): Pulse rate.
63
				* Qmin (Callable[[Union[float, int]], bool]): Minimum frequency.
64
				* Qmax (Callable[[Union[float, int]], bool]): Maximum frequency.
65
66
		See Also:
67
			* :func:`NiaPy.algorithms.Algorithm.typeParameters`
68
		"""
69
		d = Algorithm.typeParameters()
70
		d.update({
71
			'epsilon': lambda x: isinstance(x, (float, int)) and x > 0,
72
			'alpha': lambda x: isinstance(x, (float, int)) and x > 0,
73
			'r': lambda x: isinstance(x, (float, int)) and x > 0,
74
			'Qmin': lambda x: isinstance(x, (float, int)),
75
			'Qmax': lambda x: isinstance(x, (float, int))
76
		})
77
		return d
78
79
	def setParameters(self, NP=100, A=0.5, epsilon=0.001, alpha=1.0, r=0.5, Qmin=0.0, Qmax=2.0, **ukwargs):
80
		r"""Set the parameters of the algorithm.
81
82
		Args:
83
			A (Optional[float]): Starting loudness.
84
			epsilon (Optional[float]): Scaling factor.
85
			alpha (Optional[float]): Constant for updating loudness.
86
			r (Optional[float]): Pulse rate.
87
			Qmin (Optional[float]): Minimum frequency.
88
			Qmax (Optional[float]): Maximum frequency.
89
90
		See Also:
91
			* :func:`NiaPy.algorithms.Algorithm.setParameters`
92
		"""
93
		Algorithm.setParameters(self, NP=NP, **ukwargs)
94
		self.A, self.epsilon, self.alpha, self.r, self.Qmin, self.Qmax = A, epsilon, alpha, r, Qmin, Qmax
95
96
	def getParameters(self):
97
		r"""Get algorithm parameters.
98
99
		Returns:
100
			Dict[str, Any]: Arguments values.
101
102
		See Also:
103
			* :func:`NiaPy.algorithms.algorithm.Algorithm.getParameters`
104
		"""
105
		d = Algorithm.getParameters(self)
106
		d.update({
107
			'A': self.A,
108
			'epsilon': self.epsilon,
109
			'alpha': self.alpha,
110
			'r': self.r,
111
			'Qmin': self.Qmin,
112
			'Qmax': self.Qmax
113
		})
114
		return d
115
116 View Code Duplication
	def initPopulation(self, task):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
117
		r"""Initialize the starting population.
118
119
		Parameters:
120
			task (Task): Optimization task
121
122
		Returns:
123
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
124
				1. New population.
125
				2. New population fitness/function values.
126
				3. Additional arguments:
127
					* A (float): Loudness.
128
					* S (numpy.ndarray): TODO
129
					* Q (numpy.ndarray[float]): 	TODO
130
					* v (numpy.ndarray[float]): TODO
131
132
		See Also:
133
			* :func:`NiaPy.algorithms.Algorithm.initPopulation`
134
		"""
135
		Sol, Fitness, d = Algorithm.initPopulation(self, task)
136
		A, S, Q, v = np.full(self.NP, self.A), np.full([self.NP, task.D], 0.0), np.full(self.NP, 0.0), np.full([self.NP, task.D], 0.0)
137
		d.update({'A': A, 'S': S, 'Q': Q, 'v': v})
138
		return Sol, Fitness, d
139
140
	def localSearch(self, best, A, task, **kwargs):
141
		r"""Improve the best solution according to the Yang (2010).
142
143
		Args:
144
			best (numpy.ndarray): Global best individual.
145
			A (float): Loudness.
146
			task (Task): Optimization task.
147
			**kwargs (Dict[str, Any]): Additional arguments.
148
149
		Returns:
150
			numpy.ndarray: New solution based on global best individual.
151
		"""
152
		return task.repair(best + self.epsilon * A * self.normal(0, 1, task.D), rnd=self.Rand)
153
154
	def updateLoudness(self, A):
155
		r"""Update loudness when the prey is found.
156
157
		Args:
158
			A (float): Loudness.
159
160
		Returns:
161
			float: New loudness.
162
		"""
163
		nA = A * self.alpha
164
		return nA if nA > 1e-13 else self.A
165
166
	def runIteration(self, task, Sol, Fitness, xb, fxb, A, S, Q, v, **dparams):
167
		r"""Core function of Bat Algorithm.
168
169
		Parameters:
170
			task (Task): Optimization task.
171
			Sol (numpy.ndarray): Current population
172
			Fitness (numpy.ndarray[float]): Current population fitness/funciton values
173
			best (numpy.ndarray): Current best individual
174
			f_min (float): Current best individual function/fitness value
175
			S (numpy.ndarray): TODO
176
			Q (numpy.ndarray[float]): TODO
177
			v (numpy.ndarray[float]): TODO
178
			dparams (Dict[str, Any]): Additional algorithm arguments
179
180
		Returns:
181
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
182
				1. New population
183
				2. New population fitness/function vlues
184
				3. Additional arguments:
185
					* A (numpy.ndarray[float]): Loudness.
186
					* S (numpy.ndarray): TODO
187
					* Q (numpy.ndarray[float]): TODO
188
					* v (numpy.ndarray[float]): TODO
189
		"""
190
		for i in range(self.NP):
191
			Q[i] = self.Qmin + (self.Qmax - self.Qmin) * self.uniform(0, 1)
192
			v[i] += (Sol[i] - xb) * Q[i]
193
			if self.rand() > self.r: S[i] = self.localSearch(best=xb, A=A[i], task=task, i=i, Sol=Sol)
194
			else: S[i] = task.repair(Sol[i] + v[i], rnd=self.Rand)
195
			Fnew = task.eval(S[i])
196
			if (Fnew <= Fitness[i]) and (self.rand() < A[i]): Sol[i], Fitness[i] = S[i], Fnew
197
			if Fnew <= fxb: xb, fxb, A[i] = S[i].copy(), Fnew, self.updateLoudness(A[i])
198
		return Sol, Fitness, xb, fxb, {'A': A, 'S': S, 'Q': Q, 'v': v}
199
200
class SelfAdaptiveBatAlgorithm(AdaptiveBatAlgorithm):
201
	r"""Implementation of Hybrid bat algorithm.
202
203
	Algorithm:
204
		Hybrid bat algorithm
205
206
	Date:
207
		April 2019
208
209
	Author:
210
		Klemen Berkovič
211
212
	License:
213
		MIT
214
215
	Reference paper:
216
		Fister Jr., Iztok and Fister, Dusan and Yang, Xin-She. "A Hybrid Bat Algorithm". Elektrotehniski vestnik, 2013. 1-7.
217
218
	Attributes:
219
		Name (List[str]): List of strings representing algorithm name.
220
		A_l (Optional[float]): Lower limit of loudness.
221
		A_u (Optional[float]): Upper limit of loudness.
222
		r_l (Optional[float]): Lower limit of pulse rate.
223
		r_u (Optional[float]): Upper limit of pulse rate.
224
		tao_1 (Optional[float]): Learning rate for loudness.
225
		tao_2 (Optional[float]): Learning rate for pulse rate.
226
227
	See Also:
228
		* :class:`NiaPy.algorithms.basic.BatAlgorithm`
229
	"""
230
	Name = ['SelfAdaptiveBatAlgorithm', 'SABA']
231
232
	@staticmethod
233
	def algorithmInfo():
234
		r"""Get basic information about the algorithm.
235
236
		Returns:
237
			str: Basic information.
238
239
		See Also:
240
			* :func:`NiaPy.algorithms.Algorithm.algorithmInfo`
241
		"""
242
		return r"""Fister Jr., Iztok and Fister, Dusan and Yang, Xin-She. "A Hybrid Bat Algorithm". Elektrotehniski vestnik, 2013. 1-7."""
243
244 View Code Duplication
	@staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
245
	def typeParameters():
246
		r"""Get dictionary with functions for checking values of parameters.
247
248
		Returns:
249
			Dict[str, Callable]: TODO
250
251
		See Also:
252
			* :func:`NiaPy.algorithms.basic.BatAlgorithm.typeParameters`
253
		"""
254
		d = AdaptiveBatAlgorithm.typeParameters()
255
		d.pop('A', None), d.pop('r', None)
256
		d.update({
257
			'A_l': lambda x: isinstance(x, (float, int)) and x >= 0,
258
			'A_u': lambda x: isinstance(x, (float, int)) and x >= 0,
259
			'r_l': lambda x: isinstance(x, (float, int)) and x >= 0,
260
			'r_u': lambda x: isinstance(x, (float, int)) and x >= 0,
261
			'tao_1': lambda x: isinstance(x, (float, int)) and 0 <= x <= 1,
262
			'tao_2': lambda x: isinstance(x, (float, int)) and 0 <= x <= 1
263
		})
264
		return d
265
266
	def setParameters(self, A_l=0.9, A_u=1.0, r_l=0.001, r_u=0.1, tao_1=0.1, tao_2=0.1, **ukwargs):
267
		r"""Set core parameters of HybridBatAlgorithm algorithm.
268
269
		Arguments:
270
			A_l (Optional[float]): Lower limit of loudness.
271
			A_u (Optional[float]): Upper limit of loudness.
272
			r_l (Optional[float]): Lower limit of pulse rate.
273
			r_u (Optional[float]): Upper limit of pulse rate.
274
			tao_1 (Optional[float]): Learning rate for loudness.
275
			tao_2 (Optional[float]): Learning rate for pulse rate.
276
277
		See Also:
278
			* :func:`NiaPy.algorithms.modified.AdaptiveBatAlgorithm.setParameters`
279
		"""
280
		AdaptiveBatAlgorithm.setParameters(self, **ukwargs)
281
		self.A_l, self.A_u, self.r_l, self.r_u, self.tao_1, self.tao_2 = A_l, A_u, r_l, r_u, tao_1, tao_2
282
283
	def getParameters(self):
284
		r"""Get parameters of the algorithm.
285
286
		Returns:
287
			Dict[str, Any]: Parameters of the algorithm.
288
289
		See Also:
290
			* :func:`NiaPy.algorithms.modified.AdaptiveBatAlgorithm.getParameters`
291
		"""
292
		d = AdaptiveBatAlgorithm.getParameters(self)
293
		d.update({
294
			'A_l': self.A_l,
295
			'A_u': self.A_u,
296
			'r_l': self.r_l,
297
			'r_u': self.r_u,
298
			'tao_1': self.tao_1,
299
			'tao_2': self.tao_2
300
		})
301
		return d
302
303
	def initPopulation(self, task):
304
		Sol, Fitness, d = AdaptiveBatAlgorithm.initPopulation(self, task)
305
		A, r = np.full(self.NP, self.A), np.full(self.NP, self.r)
306
		d.update({'A': A, 'r': r})
307
		return Sol, Fitness, d
308
309
	def selfAdaptation(self, A, r):
310
		r"""Adaptation step.
311
312
		Args:
313
			A (float): Current loudness.
314
			r (float): Current pulse rate.
315
316
		Returns:
317
			Tuple[float, float]:
318
				1. New loudness.
319
				2. Nwq pulse rate.
320
		"""
321
		return self.A_l + self.rand() * (self.A_u - self.A_l) if self.rand() < self.tao_1 else A, self.r_l + self.rand() * (self.r_u - self.r_l) if self.rand() < self.tao_2 else r
322
323
	def runIteration(self, task, Sol, Fitness, xb, fxb, A, r, S, Q, v, **dparams):
324
		r"""Core function of Bat Algorithm.
325
326
		Parameters:
327
			task (Task): Optimization task.
328
			Sol (numpy.ndarray): Current population
329
			Fitness (numpy.ndarray[float]): Current population fitness/funciton values
330
			xb (numpy.ndarray): Current best individual
331
			fxb (float): Current best individual function/fitness value
332
			A (numpy.ndarray[flaot]): Loudness of individuals.
333
			r (numpy.ndarray[float[): Pulse rate of individuals.
334
			S (numpy.ndarray): TODO
335
			Q (numpy.ndarray[float]): TODO
336
			v (numpy.ndarray[float]): TODO
337
			dparams (Dict[str, Any]): Additional algorithm arguments
338
339
		Returns:
340
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
341
				1. New population
342
				2. New population fitness/function vlues
343
				3. Additional arguments:
344
					* A (numpy.ndarray[float]): Loudness.
345
					* r (numpy.ndarray[float]): Pulse rate.
346
					* S (numpy.ndarray): TODO
347
					* Q (numpy.ndarray[float]): TODO
348
					* v (numpy.ndarray[float]): TODO
349
		"""
350
		for i in range(self.NP):
351
			A[i], r[i] = self.selfAdaptation(A[i], r[i])
352
			Q[i] = self.Qmin + (self.Qmax - self.Qmin) * self.uniform(0, 1)
353
			v[i] += (Sol[i] - xb) * Q[i]
354
			if self.rand() > r[i]: S[i] = self.localSearch(best=xb, A=A[i], task=task, i=i, Sol=Sol)
355
			else: S[i] = task.repair(Sol[i] + v[i], rnd=self.Rand)
356
			Fnew = task.eval(S[i])
357
			if (Fnew <= Fitness[i]) and (self.rand() < (self.A_l - A[i]) / self.A): Sol[i], Fitness[i] = S[i], Fnew
358
			if Fnew <= fxb: xb, fxb = S[i].copy(), Fnew
359
		return Sol, Fitness, xb, fxb, {'A': A, 'r': r, 'S': S, 'Q': Q, 'v': v}
360
361
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
362