Completed
Push — master ( 1ffd79...ed2fa1 )
by Grega
21s queued 13s
created

SelfAdaptiveBatAlgorithm.setParameters()   A

Complexity

Conditions 1

Size

Total Lines 16
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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