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