Passed
Pull Request — master (#26)
by Grega
01:01
created

ArtificialBeeColonyAlgorithm.run()   C

Complexity

Conditions 10

Size

Total Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
c 2
b 0
f 0
dl 0
loc 56
rs 5.0704

How to fix   Long Method    Complexity   

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 ArtificialBeeColonyAlgorithm.run() 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.

1
"""Artificial Bee Colony algorithm.
2
3
Date: 12. 2. 2018
4
5
Authors : Uros Mlakar
6
7
License: MIT
8
9
Reference paper: Karaboga, D., and Bahriye B. "A powerful
10
and efficient algorithm for numerical function optimization: artificial
11
bee colony (ABC) algorithm." Journal of global optimization 39.3 (2007): 459-471.
12
13
EDITED - TODO: More tests are required! Validation!
14
15
TODO: EVALUATIONS!
16
"""
17
18
import random as rnd
19
import copy
20
21
__all__ = ['ArtificialBeeColonyAlgorithm']
22
23
24
class SolutionABC(object):
25
26
    def __init__(self, D, LB, UB):
27
        self.D = D
28
        self.Solution = []
29
        self.Fitness = float('inf')
30
        self.LB = LB
31
        self.UB = UB
32
        self.generateSolution()
33
34
    def generateSolution(self):
35
        self.Solution = [self.LB + (self.UB - self.LB) * rnd.random()
36
                         for _i in range(self.D)]
37
38
    def repair(self):
39
        for i in range(self.D):
40
            if self.Solution[i] > self.UB:
41
                self.Solution[i] = self.UB
42
43
            if self.Solution[i] < self.LB:
44
                self.Solution[i] = self.LB
45
46
    def evaluate(self):
47
        self.Fitness = SolutionABC.FuncEval(self.D, self.Solution)
48
49
    def toString(self):
50
        pass
51
52
53
class ArtificialBeeColonyAlgorithm(object):
54
    # pylint: disable=too-many-instance-attributes
55
56
    def __init__(self, NP, D, nFES, Lower, Upper, function):
57
        self.NP = NP
58
        self.D = D
59
        self.FoodNumber = self.NP / 2
60
        self.Limit = 100
61
        self.Trial = []
62
        self.Foods = []
63
        self.Probs = []
64
        self.nFES = nFES
65
        self.Lower = Lower
66
        self.Upper = Upper
67
        SolutionABC.FuncEval = staticmethod(function)
68
        self.Best = SolutionABC(self.D, Lower, Upper)
69
70
    def init(self):
71
        self.Probs = [0 for i in range(self.FoodNumber)]
72
        self.Trial = [0 for i in range(self.FoodNumber)]
73
        for i in range(self.FoodNumber):
74
            self.Foods.append(SolutionABC(self.D, self.Lower, self.Upper))
75
            self.Foods[i].evaluate()
76
            self.checkForBest(self.Foods[i])
77
78
    def CalculateProbs(self):
79
        self.Probs = [1.0 / (self.Foods[i].Fitness + 0.01)
80
                      for i in range(self.FoodNumber)]
81
        s = sum(self.Probs)
82
        self.Probs = [self.Probs[i] / s for i in range(self.FoodNumber)]
83
84
    def checkForBest(self, Solution):
85
        if Solution.Fitness <= self.Best.Fitness:
86
            self.Best = copy.deepcopy(Solution)
87
88
    def run(self):
89
        self.init()
90
        FEs = self.FoodNumber
91
        while FEs < self.nFES:
92
            self.Best.toString()
93
            for i in range(self.FoodNumber):
94
                newSolution = copy.deepcopy(self.Foods[i])
95
                param2change = int(rnd.random() * self.D)
96
                neighbor = int(self.FoodNumber * rnd.random())
97
                newSolution.Solution[param2change] = self.Foods[i].Solution[param2change] \
98
                    + (-1 + 2 * rnd.random()) * \
99
                    (self.Foods[i].Solution[param2change] -
100
                     self.Foods[neighbor].Solution[param2change])
101
                newSolution.repair()
102
                newSolution.evaluate()
103
                if newSolution.Fitness < self.Foods[i].Fitness:
104
                    self.checkForBest(newSolution)
105
                    self.Foods[i] = newSolution
106
                    self.Trial[i] = 0
107
                else:
108
                    self.Trial[i] += 1
109
            FEs += self.FoodNumber
110
            self.CalculateProbs()
111
            t, s = 0, 0
112
            while t < self.FoodNumber:
113
                if rnd.random() < self.Probs[s]:
114
                    t += 1
115
                    Solution = copy.deepcopy(self.Foods[s])
116
                    param2change = int(rnd.random() * self.D)
117
                    neighbor = int(self.FoodNumber * rnd.random())
118
                    while neighbor == s:
119
                        neighbor = int(self.FoodNumber * rnd.random())
120
                    Solution.Solution[param2change] = self.Foods[s].Solution[param2change] \
121
                        + (-1 + 2 * rnd.random()) * (
122
                            self.Foods[s].Solution[param2change] -
123
                            self.Foods[neighbor].Solution[param2change])
124
                    Solution.repair()
125
                    Solution.evaluate()
126
                    FEs += 1
127
                    if Solution.Fitness < self.Foods[s].Fitness:
128
                        self.checkForBest(newSolution)
129
                        self.Foods[s] = Solution
130
                        self.Trial[s] = 0
131
                    else:
132
                        self.Trial[s] += 1
133
                s += 1
134
                if s == self.FoodNumber:
135
                    s = 0
136
137
            mi = self.Trial.index(max(self.Trial))
138
            if self.Trial[mi] >= self.Limit:
139
                self.Foods[mi] = SolutionABC(self.D, self.Lower, self.Upper)
140
                self.Foods[mi].evaluate()
141
                FEs += 1
142
                self.Trial[mi] = 0
143
        return self.Best.Fitness
144