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

AdaptiveBatAlgorithm.initPopulation()   A

Complexity

Conditions 1

Size

Total Lines 23
Code Lines 5

Duplication

Lines 23
Ratio 100 %

Importance

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