Passed
Pull Request — master (#233)
by
unknown
01:19
created

MonarchButterflyOptimization.runIteration()   A

Complexity

Conditions 2

Size

Total Lines 31
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nop 8
dl 0
loc 31
rs 9.85
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, multiple-statements, attribute-defined-outside-init, logging-not-lazy, redefined-builtin, line-too-long, no-self-use, arguments-differ, no-else-return, bad-continuation, unused-argument
3
import logging
4
5
from numpy import argsort, sum, apply_along_axis, where, pi, ceil, isinf, array, copy, tan
6
from numpy.random import exponential
7
8
from NiaPy.algorithms.algorithm import Algorithm
9
10
__all__ = ['MonarchButterflyOptimization']
11
12
logging.basicConfig()
13
logger = logging.getLogger('NiaPy.algorithms.basic')
14
logger.setLevel('INFO')
15
16
class MonarchButterflyOptimization(Algorithm):
17
	r"""Implementation of Monarch Butterfly Optimization.
18
19
	Algorithm:
20
		 Monarch Butterfly Optimization
21
22
	Date:
23
		 2019
24
25
	Authors:
26
		 Jan Banko
27
28
	License:
29
		 MIT
30
31
	Reference paper:
32
		 Wang, Gai-Ge & Deb, Suash & Cui, Zhihua. (2015). Monarch Butterfly Optimization. Neural Computing and Applications. 10.1007/s00521-015-1923-y. , https://www.researchgate.net/publication/275964443_Monarch_Butterfly_Optimization.
33
34
	Attributes:
35
		 Name (List[str]): List of strings representing algorithm name.
36
		 PAR (float): Partition.
37
		 PER (float): Period.
38
39
	See Also:
40
		 * :class:`NiaPy.algorithms.Algorithm`
41
	"""
42
	Name = ['MonarchButterflyOptimization', 'MBO']
43
44
	@staticmethod
45
	def algorithmInfo():
46
		r"""Get information of the algorithm.
47
48
		Returns:
49
			str: Algorithm information.
50
51
		See Also:
52
			 * :func:`NiaPy.algorithms.algorithm.Algorithm.algorithmInfo`
53
		"""
54
		return r"""
55
		Description: Monarch butterfly optimization algorithm is inspired by the migration behaviour of the monarch butterflies in nature.
56
		Authors: Wang, Gai-Ge & Deb, Suash & Cui, Zhihua.
57
		Year: 2015
58
		Main reference: Wang, Gai-Ge & Deb, Suash & Cui, Zhihua. (2015). Monarch Butterfly Optimization. Neural Computing and Applications. 10.1007/s00521-015-1923-y. , https://www.researchgate.net/publication/275964443_Monarch_Butterfly_Optimization.
59
    """
60
61 View Code Duplication
	@staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
62
	def typeParameters():
63
		r"""Get dictionary with functions for checking values of parameters.
64
65
		Returns:
66
			 Dict[str, Callable]:
67
				  * PAR (Callable[[float], bool]): Checks if partition parameter has a proper value.
68
				  * PER (Callable[[float], bool]): Checks if period parameter has a proper value.
69
		See Also:
70
			 * :func:`NiaPy.algorithms.algorithm.Algorithm.typeParameters`
71
		"""
72
		d = Algorithm.typeParameters()
73
		d.update({
74
			'PAR': lambda x: isinstance(x, float) and x > 0,
75
			'PER': lambda x: isinstance(x, float) and x > 0
76
		})
77
		return d
78
79
	def setParameters(self, NP=20, PAR=5.0 / 12.0, PER=1.2, **ukwargs):
80
		r"""Set the parameters of the algorithm.
81
82
		Args:
83
			 NP (Optional[int]): Population size.
84
			 PAR (Optional[int]): Partition.
85
			 PER (Optional[int]): Period.
86
			 ukwargs (Dict[str, Any]): Additional arguments.
87
88
		See Also:
89
			 * :func:`NiaPy.algorithms.Algorithm.setParameters`
90
		"""
91
		Algorithm.setParameters(self, NP=NP, **ukwargs)
92
		self.NP, self.PAR, self.PER, self.keep, self.BAR, self.NP1 = NP, PAR, PER, 2, PAR, int(ceil(PAR * NP))
93
		self.NP2 = int(NP - self.NP1)
94
95
	def getParameters(self):
96
		r"""Get parameters values for the algorithm.
97
98
		Returns:
99
			Dict[str, Any]: TODO.
100
		"""
101
		d = Algorithm.getParameters(self)
102
		d.update({
103
			'PAR': self.PAR,
104
			'PER': self.PER,
105
			'keep': self.keep,
106
			'BAR': self.BAR,
107
			'NP1': self.NP1,
108
			'NP2': self.NP2
109
		})
110
		return d
111
112 View Code Duplication
	def repair(self, x, lower, upper):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
113
		r"""Truncate exceeded dimensions to the limits.
114
115
		Args:
116
			 x (numpy.ndarray): Individual to repair.
117
			 lower (numpy.ndarray): Lower limits for dimensions.
118
			 upper (numpy.ndarray): Upper limits for dimensions.
119
120
		Returns:
121
			 numpy.ndarray: Repaired individual.
122
		"""
123
		ir = where(x < lower)
124
		x[ir] = lower[ir]
125
		ir = where(x > upper)
126
		x[ir] = upper[ir]
127
		return x
128
129
	def levy(self, step_size, D):
130
		r"""Calculate levy flight.
131
132
		Args:
133
			 step_size (float): Size of the walk step.
134
			 D (int): Number of dimensions.
135
136
		Returns:
137
			 numpy.ndarray: Calculated values for levy flight.
138
		"""
139
		delataX = array([sum(tan(pi * self.uniform(0.0, 1.0, 10))) for _ in range(0, D)])
140
		return delataX
141
142
	def migrationOperator(self, D, NP1, NP2, Butterflies):
143
		r"""Apply the migration operator.
144
145
		Args:
146
			 D (int): Number of dimensions.
147
			 NP1 (int): Number of butterflies in Land 1.
148
			 NP2 (int): Number of butterflies in Land 2.
149
			 Butterflies (numpy.ndarray): Current butterfly population.
150
151
		Returns:
152
			 numpy.ndarray: Adjusted butterfly population.
153
		"""
154
		pop1 = copy(Butterflies[:NP1])
155
		pop2 = copy(Butterflies[NP1:])
156
		for k1 in range(0, NP1):
157
			for parnum1 in range(0, D):
158
				r1 = self.uniform(0.0, 1.0) * self.PER
159
				if r1 <= self.PAR:
160
					r2 = self.randint(Nmin=0, Nmax=NP1 - 1)
161
					Butterflies[k1, parnum1] = pop1[r2, parnum1]
162
				else:
163
					r3 = self.randint(Nmin=0, Nmax=NP2 - 1)
164
					Butterflies[k1, parnum1] = pop2[r3, parnum1]
165
		return Butterflies
166
167
	def adjustingOperator(self, t, max_t, D, NP1, NP2, Butterflies, best):
168
		r"""Apply the adjusting operator.
169
170
		Args:
171
			 t (int): Current generation.
172
			 max_t (int): Maximum generation.
173
			 D (int): Number of dimensions.
174
			 NP1 (int): Number of butterflies in Land 1.
175
			 NP2 (int): Number of butterflies in Land 2.
176
			 Butterflies (numpy.ndarray): Current butterfly population.
177
			 best (numpy.ndarray): The best butterfly currently.
178
179
		Returns:
180
			 numpy.ndarray: Adjusted butterfly population.
181
		"""
182
		pop2 = copy(Butterflies[NP1:])
183
		for k2 in range(NP1, NP1 + NP2):
184
			scale = 1.0 / ((t + 1)**2)
185
			step_size = ceil(exponential(2 * max_t))
186
			delataX = self.levy(step_size, D)
187
			for parnum2 in range(0, D):
188
				if self.uniform(0.0, 1.0) >= self.PAR:
189
					Butterflies[k2, parnum2] = best[parnum2]
190
				else:
191
					r4 = self.randint(Nmin=0, Nmax=NP2 - 1)
192
					Butterflies[k2, parnum2] = pop2[r4, 1]
193
					if self.uniform(0.0, 1.0) > self.BAR:
194
						Butterflies[k2, parnum2] += scale * \
195
															 (delataX[parnum2] - 0.5)
196
		return Butterflies
197
198
	def evaluateAndSort(self, task, Butterflies):
199
		r"""Evaluate and sort the butterfly population.
200
201
		Args:
202
			 task (Task): Optimization task
203
			 Butterflies (numpy.ndarray): Current butterfly population.
204
205
		Returns:
206
			 numpy.ndarray: Tuple[numpy.ndarray, float, numpy.ndarray]:
207
				  1. Best butterfly according to the evaluation.
208
				  2. The best fitness value.
209
				  3. Butterfly population.
210
		"""
211
		Fitness = apply_along_axis(task.eval, 1, Butterflies)
212
		indices = argsort(Fitness)
213
		Butterflies = Butterflies[indices]
214
		Fitness = Fitness[indices]
215
216
		return Fitness, Butterflies
217
218
	def initPopulation(self, task):
219
		r"""Initialize the starting population.
220
221
		Args:
222
			 task (Task): Optimization task
223
224
		Returns:
225
			 Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
226
				  1. New population.
227
				  2. New population fitness/function values.
228
				  3. Additional arguments:
229
						* dx (float): A small value used in local seeding stage.
230
231
		See Also:
232
			 * :func:`NiaPy.algorithms.Algorithm.initPopulation`
233
		"""
234
		Butterflies = self.uniform(task.Lower, task.Upper, [self.NP, task.D])
235
		Fitness, Butterflies = self.evaluateAndSort(task, Butterflies)
236
		return Butterflies, Fitness, {'tmp_best': Butterflies[0]}
237
238
	def runIteration(self, task, Butterflies, Evaluations, xb, fxb, tmp_best, **dparams):
239
		r"""Core function of Forest Optimization Algorithm.
240
241
		Args:
242
			 task (Task): Optimization task.
243
			 Butterflies (numpy.ndarray): Current population.
244
			 Evaluations (numpy.ndarray[float]): Current population function/fitness values.
245
			 xb (numpy.ndarray): Global best individual.
246
			 fxb (float): Global best individual fitness/function value.
247
			 tmp_best (numpy.ndarray): Best individual currently.
248
			 **dparams (Dict[str, Any]): Additional arguments.
249
250
		Returns:
251
			 Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, Dict[str, Any]]:
252
				  1. New population.
253
				  2. New population fitness/function values.
254
				  3. New global best solution
255
				  4. New global best solutions fitness/objective value
256
				  5. Additional arguments:
257
						* dx (float): A small value used in local seeding stage.
258
		"""
259
		tmpElite = copy(Butterflies[:self.keep])
260
		max_t = task.nGEN if isinf(task.nGEN) is False else task.nFES / self.NP
261
		Butterflies = apply_along_axis(self.repair, 1, self.migrationOperator(task.D, self.NP1, self.NP2, Butterflies), task.Lower, task.Upper)
262
		Butterflies = apply_along_axis(self.repair, 1, self.adjustingOperator(task.Iters, max_t, task.D, self.NP1, self.NP2, Butterflies, tmp_best), task.Lower, task.Upper)
263
		Fitness, Butterflies = self.evaluateAndSort(task, Butterflies)
264
		tmp_best = Butterflies[0]
265
		Butterflies[-self.keep:] = tmpElite
266
		Fitness, Butterflies = self.evaluateAndSort(task, Butterflies)
267
		xb, fxb = self.getBest(Butterflies, Fitness, xb, fxb)
268
		return Butterflies, Fitness, xb, fxb, {'tmp_best': tmp_best}
269
270
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
271