Completed
Push — master ( cc7745...279fb5 )
by Grega
19s queued 17s
created

ArtificialBeeColonyAlgorithm.runIteration()   D

Complexity

Conditions 12

Size

Total Lines 54
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 32
nop 9
dl 0
loc 54
rs 4.8
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like NiaPy.algorithms.basic.abc.ArtificialBeeColonyAlgorithm.runIteration() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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 copy
3
import logging
4
5
from numpy import asarray, full, argmax
6
7
from NiaPy.algorithms.algorithm import Algorithm, Individual, defaultIndividualInit
8
9
logging.basicConfig()
10
logger = logging.getLogger('NiaPy.algorithms.basic')
11
logger.setLevel('INFO')
12
13
__all__ = ['ArtificialBeeColonyAlgorithm']
14
15
class SolutionABC(Individual):
16
	r"""Representation of solution for Artificial Bee Colony Algorithm.
17
18
	Date:
19
		2018
20
21
	Author:
22
		Klemen Berkovič
23
24
	See Also:
25
		* :class:`NiaPy.algorithms.Individual`
26
	"""
27
	def __init__(self, **kargs):
28
		r"""Initialize individual.
29
30
		Args:
31
			kargs (Dict[str, Any]): Additional arguments.
32
33
		See Also:
34
			* :func:`NiaPy.algorithms.Individual.__init__`
35
		"""
36
		Individual.__init__(self, **kargs)
37
38
class ArtificialBeeColonyAlgorithm(Algorithm):
39
	r"""Implementation of Artificial Bee Colony algorithm.
40
41
	Algorithm:
42
		Artificial Bee Colony algorithm
43
44
	Date:
45
		2018
46
47
	Author:
48
		Uros Mlakar and Klemen Berkovič
49
50
	License:
51
		MIT
52
53
	Reference paper:
54
		Karaboga, D., and Bahriye B. "A powerful and efficient algorithm for numerical function optimization: artificial bee colony (ABC) algorithm." Journal of global optimization 39.3 (2007): 459-471.
55
56
	Arguments
57
		Name (List[str]): List containing strings that represent algorithm names
58
		Limit (Union[float, numpy.ndarray[float]]): Limt
59
60
	See Also:
61
		* :class:`NiaPy.algorithms.Algorithm`
62
	"""
63
	Name = ['ArtificialBeeColonyAlgorithm', 'ABC']
64
65
	@staticmethod
66
	def typeParameters():
67
		r"""Return functions for checking values of parameters.
68
69
		Returns:
70
			Dict[str, Callable]:
71
				* Limit (Callable[Union[float, numpy.ndarray[float]]]): TODO
72
73
		See Also:
74
			* :func:`NiaPy.algorithms.Algorithm.typeParameters`
75
		"""
76
		d = Algorithm.typeParameters()
77
		d.update({'Limit': lambda x: isinstance(x, int) and x > 0})
78
		return d
79
80
	def setParameters(self, NP=10, Limit=100, **ukwargs):
81
		r"""Set the parameters of Artificial Bee Colony Algorithm.
82
83
		Parameters:
84
			Limit (Optional[Union[float, numpy.ndarray[float]]]): Limt
85
			**ukwargs (Dict[str, Any]): Additional arguments
86
87
		See Also:
88
			* :func:`NiaPy.algorithms.Algorithm.setParameters`
89
		"""
90
		Algorithm.setParameters(self, NP=NP, InitPopFunc=defaultIndividualInit, itype=SolutionABC, **ukwargs)
91
		self.FoodNumber, self.Limit = int(self.NP / 2), Limit
92
93
	def CalculateProbs(self, Foods, Probs):
94
		r"""Calculate the probes.
95
96
		Parameters:
97
			Foods (numpy.ndarray): TODO
98
			Probs (numpy.ndarray): TODO
99
100
		Returns:
101
			numpy.ndarray: TODO
102
		"""
103
		Probs = [1.0 / (Foods[i].f + 0.01) for i in range(self.FoodNumber)]
104
		s = sum(Probs)
105
		Probs = [Probs[i] / s for i in range(self.FoodNumber)]
106
		return Probs
107
108
	def initPopulation(self, task):
109
		r"""Initialize the starting population.
110
111
		Parameters:
112
			task (Task): Optimization task
113
114
		Returns:
115
			Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
116
				1. New population
117
				2. New population fitness/function values
118
				3. Additional arguments:
119
					* Probes (numpy.ndarray): TODO
120
					* Trial (numpy.ndarray): TODO
121
122
		See Also:
123
			* :func:`NiaPy.algorithms.Algorithm.initPopulation`
124
		"""
125
		Foods, fpop, _ = Algorithm.initPopulation(self, task)
126
		Probs, Trial = full(self.FoodNumber, 0.0), full(self.FoodNumber, 0.0)
127
		return Foods, fpop, {'Probs': Probs, 'Trial': Trial}
128
129
	def runIteration(self, task, Foods, fpop, xb, fxb, Probs, Trial, **dparams):
130
		r"""Core funciton of  the algorithm.
131
132
		Parameters:
133
			task (Task): Optimization task
134
			Foods (numpy.ndarray): Current population
135
			fpop (numpy.ndarray[float]): Function/fitness values of current population
136
			xb (numpy.ndarray): Current best individual
137
			fxb (float): Current best individual fitness/function value
138
			Probs (numpy.ndarray): TODO
139
			Trial (numpy.ndarray): TODO
140
			dparams (Dict[str, Any]): Additional parameters
141
142
		Returns:
143
			Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, float, Dict[str, Any]]:
144
				1. New population
145
				2. New population fitness/function values
146
				3. New global best solution
147
				4. New global best fitness/objecive value
148
				5. Additional arguments:
149
					* Probes (numpy.ndarray): TODO
150
					* Trial (numpy.ndarray): TODO
151
		"""
152
		for i in range(self.FoodNumber):
153
			newSolution = copy.deepcopy(Foods[i])
154
			param2change = int(self.rand() * task.D)
155
			neighbor = int(self.FoodNumber * self.rand())
156
			newSolution.x[param2change] = Foods[i].x[param2change] + (-1 + 2 * self.rand()) * (Foods[i].x[param2change] - Foods[neighbor].x[param2change])
157
			newSolution.evaluate(task, rnd=self.Rand)
158
			if newSolution.f < Foods[i].f:
159
				Foods[i], Trial[i] = newSolution, 0
160
				if newSolution.f < fxb: xb, fxb = newSolution.x.copy(), newSolution.f
161
			else: Trial[i] += 1
162
		Probs, t, s = self.CalculateProbs(Foods, Probs), 0, 0
163
		while t < self.FoodNumber:
164
			if self.rand() < Probs[s]:
165
				t += 1
166
				Solution = copy.deepcopy(Foods[s])
167
				param2change = int(self.rand() * task.D)
168
				neighbor = int(self.FoodNumber * self.rand())
169
				while neighbor == s: neighbor = int(self.FoodNumber * self.rand())
170
				Solution.x[param2change] = Foods[s].x[param2change] + (-1 + 2 * self.rand()) * (Foods[s].x[param2change] - Foods[neighbor].x[param2change])
171
				Solution.evaluate(task, rnd=self.Rand)
172
				if Solution.f < Foods[s].f:
173
					Foods[s], Trial[s] = Solution, 0
174
					if Solution.f < fxb: xb, fxb = Solution.x.copy(), Solution.f
175
				else: Trial[s] += 1
176
			s += 1
177
			if s == self.FoodNumber: s = 0
178
		mi = argmax(Trial)
179
		if Trial[mi] >= self.Limit:
180
			Foods[mi], Trial[mi] = SolutionABC(task=task, rnd=self.Rand), 0
181
			if Foods[mi].f < fxb: xb, fxb = Foods[mi].x.copy(), Foods[mi].f
182
		return Foods, asarray([f.f for f in Foods]), xb, fxb, {'Probs': Probs, 'Trial': Trial}
183
184
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
185