MonarchButterflyOptimization.runIteration()   A
last analyzed

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