NiaPy.algorithms.basic.foa   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 262
Duplicated Lines 9.16 %

Importance

Changes 0
Metric Value
eloc 95
dl 24
loc 262
rs 10
c 0
b 0
f 0
wmc 17

10 Methods

Rating   Name   Duplication   Size   Complexity  
A ForestOptimizationAlgorithm.localSeeding() 0 18 1
B ForestOptimizationAlgorithm.typeParameters() 24 24 6
A ForestOptimizationAlgorithm.globalSeeding() 0 21 1
A ForestOptimizationAlgorithm.removeLifeTimeExceeded() 0 19 1
A ForestOptimizationAlgorithm.getParameters() 0 15 1
A ForestOptimizationAlgorithm.algorithmInfo() 0 11 1
A ForestOptimizationAlgorithm.survivalOfTheFittest() 0 23 1
A ForestOptimizationAlgorithm.runIteration() 0 38 3
A ForestOptimizationAlgorithm.initPopulation() 0 20 1
A ForestOptimizationAlgorithm.setParameters() 0 17 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
# encoding=utf8
2
import logging
3
from numpy import where, apply_along_axis, zeros, append, ndarray, delete, arange, argmin, absolute, int32
4
from NiaPy.algorithms.algorithm import Algorithm
5
from NiaPy.util import limit_repair
6
7
__all__ = ['ForestOptimizationAlgorithm']
8
9
logging.basicConfig()
10
logger = logging.getLogger('NiaPy.algorithms.basic')
11
logger.setLevel('INFO')
12
13
class ForestOptimizationAlgorithm(Algorithm):
14
	r"""Implementation of Forest Optimization Algorithm.
15
16
	Algorithm:
17
		 Forest Optimization Algorithm
18
19
	Date:
20
		 2019
21
22
	Authors:
23
		 Luka Pečnik
24
25
	License:
26
		 MIT
27
28
	Reference paper:
29
		 Manizheh Ghaemi, Mohammad-Reza Feizi-Derakhshi, Forest Optimization Algorithm, Expert Systems with Applications, Volume 41, Issue 15, 2014, Pages 6676-6687, ISSN 0957-4174, https://doi.org/10.1016/j.eswa.2014.05.009.
30
31
	References URL:
32
		 Implementation is based on the following MATLAB code: https://github.com/cominsys/FOA
33
34
	Attributes:
35
		 Name (List[str]): List of strings representing algorithm name.
36
		 lt (int): Life time of trees parameter.
37
		 al (int): Area limit parameter.
38
		 lsc (int): Local seeding changes parameter.
39
		 gsc (int): Global seeding changes parameter.
40
		 tr (float): Transfer rate parameter.
41
42
	See Also:
43
		 * :class:`NiaPy.algorithms.Algorithm`
44
	"""
45
	Name = ['ForestOptimizationAlgorithm', 'FOA']
46
47
	@staticmethod
48
	def algorithmInfo():
49
		r"""Get algorithms information.
50
51
		Returns:
52
			str: Algorithm information.
53
54
		See Also:
55
			* :func:`NiaPy.algorithms.Algorithm.algorithmInfo`
56
		"""
57
		return r"""Manizheh Ghaemi, Mohammad-Reza Feizi-Derakhshi, Forest Optimization Algorithm, Expert Systems with Applications, Volume 41, Issue 15, 2014, Pages 6676-6687, ISSN 0957-4174, https://doi.org/10.1016/j.eswa.2014.05.009."""
58
59 View Code Duplication
	@staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
60
	def typeParameters():
61
		r"""Get dictionary with functions for checking values of parameters.
62
63
		Returns:
64
			 Dict[str, Callable]:
65
				  * lt (Callable[[int], bool]): Checks if life time parameter has a proper value.
66
				  * al (Callable[[int], bool]): Checks if area limit parameter has a proper value.
67
				  * lsc (Callable[[int], bool]): Checks if local seeding changes parameter has a proper value.
68
				  * gsc (Callable[[int], bool]): Checks if global seeding changes parameter has a proper value.
69
				  * tr (Callable[[float], bool]): Checks if transfer rate parameter has a proper value.
70
71
		See Also:
72
			 * :func:`NiaPy.algorithms.algorithm.Algorithm.typeParameters`
73
		"""
74
		d = Algorithm.typeParameters()
75
		d.update({
76
			'lt': lambda x: isinstance(x, int) and x > 0,
77
			'al': lambda x: isinstance(x, int) and x > 0,
78
			'lsc': lambda x: isinstance(x, int) and x > 0,
79
			'gsc': lambda x: isinstance(x, int) and x > 0,
80
			'tr': lambda x: isinstance(x, float) and 0 <= x <= 1,
81
		})
82
		return d
83
84
	def setParameters(self, NP=10, lt=3, al=10, lsc=1, gsc=1, tr=0.3, **ukwargs):
85
		r"""Set the parameters of the algorithm.
86
87
		Args:
88
			 NP (Optional[int]): Population size.
89
			 lt (Optional[int]): Life time parameter.
90
			 al (Optional[int]): Area limit parameter.
91
			 lsc (Optional[int]): Local seeding changes parameter.
92
			 gsc (Optional[int]): Global seeding changes parameter.
93
			 tr (Optional[float]): Transfer rate parameter.
94
			 ukwargs (Dict[str, Any]): Additional arguments.
95
96
		See Also:
97
			 * :func:`NiaPy.algorithms.Algorithm.setParameters`
98
		"""
99
		Algorithm.setParameters(self, NP=NP, **ukwargs)
100
		self.lt, self.al, self.lsc, self.gsc, self.tr = lt, al, lsc, gsc, tr
101
102
	def getParameters(self):
103
		r"""Get parameters values of the algorithm.
104
105
		Returns:
106
			Dict[str, Any]: TODO.
107
		"""
108
		d = Algorithm.getParameters(self)
109
		d.update({
110
			'lt': self.lt,
111
			'al': self.al,
112
			'lsc': self.lsc,
113
			'gsc': self.gsc,
114
			'tr': self.tr
115
		})
116
		return d
117
118
	def localSeeding(self, task, trees):
119
		r"""Local optimum search stage.
120
121
		Args:
122
			 task (Task): Optimization task.
123
			 trees (numpy.ndarray): Zero age trees for local seeding.
124
125
		Returns:
126
			 numpy.ndarray: Resulting zero age trees.
127
		"""
128
		n = trees.shape[0]
129
		deltas = self.uniform(-self.dx, self.dx, (n, self.lsc))
130
		deltas = append(deltas, zeros((n, task.D - self.lsc)), axis=1)
131
		perms = self.rand([deltas.shape[0], deltas.shape[1]]).argsort(1)
132
		deltas = deltas[arange(deltas.shape[0])[:, None], perms]
133
		trees += deltas
134
		trees = apply_along_axis(limit_repair, 1, trees, task.Lower, task.Upper)
135
		return trees
136
137
	def globalSeeding(self, task, candidates, size):
138
		r"""Global optimum search stage that should prevent getting stuck in a local optimum.
139
140
		Args:
141
			 task (Task): Optimization task.
142
			 candidates (numpy.ndarray): Candidate population for global seeding.
143
			 size (int): Number of trees to produce.
144
145
		Returns:
146
			 numpy.ndarray: Resulting trees.
147
		"""
148
		seeds = candidates[self.randint(len(candidates), D=size)]
149
		deltas = self.uniform(task.benchmark.Lower, task.benchmark.Upper, (size, self.gsc))
150
		deltas = append(deltas, zeros((size, task.D - self.gsc)), axis=1)
151
		perms = self.rand([deltas.shape[0], deltas.shape[1]]).argsort(1)
152
		deltas = deltas[arange(deltas.shape[0])[:, None], perms]
153
		deltas = deltas.flatten()
154
		seeds = seeds.flatten()
155
		seeds[deltas != 0] = deltas[deltas != 0]
156
157
		return seeds.reshape(size, task.D)
158
159
	def removeLifeTimeExceeded(self, trees, candidates, age):
160
		r"""Remove dead trees.
161
162
		Args:
163
			 trees (numpy.ndarray): Population to test.
164
			 candidates (numpy.ndarray): Candidate population array to be updated.
165
			 age (numpy.ndarray[int32]): Age of trees.
166
167
		Returns:
168
			 Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray[int32]]:
169
				  1. Alive trees.
170
				  2. New candidate population.
171
				  3. Age of trees.
172
		"""
173
		lifeTimeExceeded = where(age > self.lt)
174
		candidates = trees[lifeTimeExceeded]
175
		trees = delete(trees, lifeTimeExceeded, axis=0)
176
		age = delete(age, lifeTimeExceeded, axis=0)
177
		return trees, candidates, age
178
179
	def survivalOfTheFittest(self, task, trees, candidates, age):
180
		r"""Evaluate and filter current population.
181
182
		Args:
183
			 task (Task): Optimization task.
184
			 trees (numpy.ndarray): Population to evaluate.
185
			 candidates (numpy.ndarray): Candidate population array to be updated.
186
			 age (numpy.ndarray[int32]): Age of trees.
187
188
		Returns:
189
			 Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray[float], numpy.ndarray[int32]]:
190
				  1. Trees sorted by fitness value.
191
				  2. Updated candidate population.
192
				  3. Population fitness values.
193
				  4. Age of trees
194
		"""
195
		evaluations = apply_along_axis(task.eval, 1, trees)
196
		ei = evaluations.argsort()
197
		candidates = append(candidates, trees[ei[self.al:]], axis=0)
198
		trees = trees[ei[:self.al]]
199
		age = age[ei[:self.al]]
200
		evaluations = evaluations[ei[:self.al]]
201
		return trees, candidates, evaluations, age
202
203
	def initPopulation(self, task):
204
		r"""Initialize the starting population.
205
206
		Args:
207
			 task (Task): Optimization task
208
209
		Returns:
210
			 Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
211
				  1. New population.
212
				  2. New population fitness/function values.
213
				  3. Additional arguments:
214
						* age (numpy.ndarray[int32]): Age of trees.
215
216
		See Also:
217
			 * :func:`NiaPy.algorithms.Algorithm.initPopulation`
218
		"""
219
		Trees, Evaluations, _ = Algorithm.initPopulation(self, task)
220
		age = zeros(self.NP, dtype=int32)
221
		self.dx = absolute(task.benchmark.Upper) / 5
222
		return Trees, Evaluations, {'age': age}
223
224
	def runIteration(self, task, Trees, Evaluations, xb, fxb, age, **dparams):
225
		r"""Core function of Forest Optimization Algorithm.
226
227
		Args:
228
			 task (Task): Optimization task.
229
			 Trees (numpy.ndarray): Current population.
230
			 Evaluations (numpy.ndarray[float]): Current population function/fitness values.
231
			 xb (numpy.ndarray): Global best individual.
232
			 fxb (float): Global best individual fitness/function value.
233
			 age (numpy.ndarray[int32]): Age of trees.
234
			 **dparams (Dict[str, Any]): Additional arguments.
235
236
		Returns:
237
			 Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
238
				  1. New population.
239
				  2. New population fitness/function values.
240
				  3. Additional arguments:
241
						* age (numpy.ndarray[int32]): Age of trees.
242
		"""
243
		candidatePopulation = ndarray((0, task.D + 1))
244
		zeroAgeTrees = Trees[age == 0]
245
		localSeeds = self.localSeeding(task, zeroAgeTrees)
246
		age += 1
247
		Trees, candidatePopulation, age = self.removeLifeTimeExceeded(Trees, candidatePopulation, age)
248
		Trees = append(Trees, localSeeds, axis=0)
249
		age = append(age, zeros(len(localSeeds), dtype=int32))
250
		Trees, candidatePopulation, Evaluations, age = self.survivalOfTheFittest(task, Trees, candidatePopulation, age)
251
		gsn = int(self.tr * len(candidatePopulation))
252
		if gsn > 0:
253
			globalSeeds = self.globalSeeding(task, candidatePopulation, gsn)
254
			Trees = append(Trees, globalSeeds, axis=0)
255
			age = append(age, zeros(len(globalSeeds), dtype=int32))
256
			gste = apply_along_axis(task.eval, 1, globalSeeds)
257
			Evaluations = append(Evaluations, gste)
258
		ib = argmin(Evaluations)
259
		age[ib] = 0
260
		if Evaluations[ib] < fxb: xb, fxb = Trees[ib].copy(), Evaluations[ib]
261
		return Trees, Evaluations, xb, fxb, {'age': age}
262