ECF 1.5
AlgArtificialBeeColony.cpp
1#include "ECF_base.h"
2#include "ECF_derived.h"
3#include "ECF_macro.h"
4#include "AlgArtificialBeeColony.h"
5
6
7ArtificialBeeColony::ArtificialBeeColony()
8{
9 // define algorithm name
10 name_ = "ArtificialBeeColony";
11
12 // create selection operators needed
13 // in this case, selRandomOp and selFitOp
14 selRandomOp = (SelRandomOpP) (new SelRandomOp);
15 selBestOp = (SelBestOpP) (new SelBestOp);
16 selWorstOp = (SelWorstOpP) (new SelWorstOp);
17 selFitOp = (SelFitnessProportionalOpP) (new SelFitnessProportionalOp);
18
19 isTrialAdded_ = false;
20 elitism_ = true;
21}
22
23
24//register any parameters
26{
27 // limit is a maximum number of cycles for each individual
28 registerParameter(state, "limit", (voidP) new uint(300), ECF::INT,
29 "Maximum number of cycles for each individual (default: 300)");
30 // elitism: should the current best individual be preserved
31 registerParameter(state, "elitism", (voidP) new uint(1), ECF::INT,
32 "Elitism: the current best food source is preserved (default: 1)");
33}
34
35
37{
38 // initialize all operators
39 selFitOp->initialize(state);
40 selFitOp->setSelPressure(2);
41 selBestOp->initialize(state);
42 selWorstOp->initialize(state);
43 selRandomOp->initialize(state);
44
45 voidP sptr = state->getRegistry()->getEntry("population.size");
46 uint size = *((uint*) sptr.get());
47 probability_.resize(size);
48
49 // algorithm accepts a single FloatingPoint or Binary genotype
50 // or a genotype derived from the abstract RealValueGenotype class
51 GenotypeP activeGenotype = state->getGenotypes()[0];
52 RealValueGenotypeP rv = boost::dynamic_pointer_cast<RealValueGenotype> (activeGenotype);
53 if(!rv) {
54 ECF_LOG_ERROR(state, "Error: ABC algorithm accepts only a RealValueGenotype derived genotype! (FloatingPoint or Binary)");
55 throw ("");
56 }
57
58 voidP limitp = getParameterValue(state, "limit");
59 limit_ = *((uint*) limitp.get());
60
61 if( (int)limit_ < 0 ) {
62 ECF_LOG(state, 1, "Error: ABC algorithm requires parameter 'limit' to be a nonnegative value!");
63 throw "";
64 }
65
66 voidP elitismp = getParameterValue(state, "elitism");
67 elitism_ = *((bool*) elitismp.get());
68
69 voidP lBound = state->getGenotypes()[0]->getParameterValue(state, "lbound");
70 lbound_ = *((double*) lBound.get());
71 voidP uBound = state->getGenotypes()[0]->getParameterValue(state, "ubound");
72 ubound_ = *((double*) uBound.get());
73
74 // batch run check
75 if(isTrialAdded_)
76 return true;
77
78 FloatingPointP flpoint[2];
79 for(uint iGen = 1; iGen < 2; iGen++) {
80
81 flpoint[iGen] = (FloatingPointP) new FloatingPoint::FloatingPoint;
82 state->setGenotype(flpoint[iGen]);
83
84 flpoint[iGen]->setParameterValue(state, "dimension", (voidP) new uint(1));
85
86 // initial value of trial parameter should be (as close as possible to) 0
87 flpoint[iGen]->setParameterValue(state, "lbound", (voidP) new double(0));
88 flpoint[iGen]->setParameterValue(state, "ubound", (voidP) new double(0.01));
89 }
90 ECF_LOG(state, 1, "ABC algorithm: added 1 FloatingPoint genotype (trial)");
91
92 // mark adding of trial genotype
93 isTrialAdded_ = true;
94
95 return true;
96}
97
98
99bool ArtificialBeeColony::advanceGeneration(StateP state, DemeP deme)
100{
101// In ABC, a colony of artificial bees search for artificial food sources (good solutions for a given problem):
102// The colony of artificial bees contains three groups of bees: employed bees, onlooker bees, and scout bees
103// - employed bees are associated with specific food sources
104// - onlooker bees watch the dance of employed bees within the hive to choose a food source
105// - scout bees search for food sources randomly
106//
107// Initially, a randomly distributed initial population (food sources) is generated
108// REPEAT
109// 1) Employed Bees Phase
110// 1a) for each food source createNewFoodSource() is called
111//
112// 2) Onlooker Bees Phase
113// 2a) each onlooker bee chooses a food source depending on their fitness values (better individuals are more likely to be chosen)
114// 2b) for each chosen food source createNewFoodSource() is called
115//
116// 3) Scout Bees Phase
117// ** as a rule, none or one food source gets abandoned per generation
118// 3a) for each food source get trial variable
119// 3b) remember the source if its trial exceeded limit
120// 3c) if there is a source that exceeded limit, replace it with a random food source
121//
122// UNTIL(requirements are met)
123//
124// *createNewFoodSource()
125// a) for each food source find a neighbour (a random food source in the population)
126// b) produce a modification on the food source (discover a new food source)
127// c) evaluate new food source
128// d) if the fitness value of the new one is better than that of the original source,
129// memorize the new source, forget the old one and set trial to 0
130// otherwise keep the old one and increment trial
131
132
133 employedBeesPhase(state, deme);
134 onlookerBeesPhase(state, deme);
135 scoutBeesPhase(state, deme);
136
137 return true;
138}
139
140
141bool ArtificialBeeColony::employedBeesPhase(StateP state, DemeP deme)
142{
143 for( uint i = 0; i < deme->getSize(); i++ ) { // for each food source
144 IndividualP food = deme->at(i);
145 createNewFoodSource(food, state, deme);
146 }
147 return true;
148}
149
150
151bool ArtificialBeeColony::onlookerBeesPhase(StateP state, DemeP deme)
152{
153 // choose a food source depending on its fitness value (better individuals are more likely to be chosen)
154 // calculate selection probabilities, rotate individuals
155 calculateProbabilities(state, deme);
156 int demeSize = (int) deme->getSize();
157 int i = state->getRandomizer()->getRandomInteger(demeSize);
158 int n = 0;
159 while( n < demeSize) {
160 int fact = i++ % demeSize;
161 IndividualP food = deme->at(fact);
162
163 if (state->getRandomizer()->getRandomDouble() < probability_[fact]){
164 n++;
165 createNewFoodSource(food, state, deme);
166 }
167 }
168
169 return true;
170}
171
172
173bool ArtificialBeeColony::calculateProbabilities(StateP state, DemeP deme)
174{
175 IndividualP bestFood = selBestOp->select(*deme);
176 double bestFitness = bestFood->fitness->getValue();
177 double worstFitness = selWorstOp->select(*deme)->fitness->getValue();
178 double offset = 0;
179
180 // scale fitness values
181 if(bestFitness < worstFitness && bestFitness < 0)
182 offset = 0.1 - bestFitness; // minimization
183 else if(worstFitness < 0)
184 offset = 0.1 - worstFitness; // maximization
185
186 // for each food source
187 for( uint i = 0; i < deme->getSize(); i++ ) {
188 IndividualP food = deme->at(i);
189 double thisFitness = food->fitness->getValue();
190
191 if (bestFitness == thisFitness)
192 probability_[i] = 1.0;
193 else if (thisFitness < bestFitness) // maximization problems
194 probability_[i] = 0.1 + 0.9 * (thisFitness + offset) / (bestFitness + offset);
195 else // minimization problems
196 probability_[i] = 0.1 + 0.9 * (bestFitness + offset) / (thisFitness + offset);
197
198 // using selFitPropOp method
199 //probability_[i] = 0.1 + 0.9 * (thisFitness - worstFitness)/(bestFitness - worstFitness);
200 }
201 return true;
202}
203
204
205
206bool ArtificialBeeColony::scoutBeesPhase(StateP state, DemeP deme)
207{
208 IndividualP unimproved;
209 IndividualP bestFood = selBestOp->select(*deme);
210
211 double maxTrial = 0;
212 for( uint i = 0; i < deme->getSize(); i++ ) { // for each food source
213 IndividualP food = deme->at(i);
214
215 if(food == bestFood)
216 continue;
217
218 // get food source's trial variable
219 FloatingPointP flp = boost::static_pointer_cast<FloatingPoint::FloatingPoint> (food->getGenotype(1));
220 double &trial = flp->realValue[0];
221
222 // remember the source if its trial exceeded limit
223 if (trial > limit_ && trial > maxTrial){
224 unimproved = food;
225 maxTrial = trial;
226 }
227 }
228
229 // if there is a food source that exceeded the limit, replace it with a random one
230 if (unimproved != NULL){
231 FloatingPointP flp = boost::static_pointer_cast<FloatingPoint::FloatingPoint> (unimproved->getGenotype(1));
232 double &trial = flp->realValue[0];
233 trial = 0;
234 flp = boost::static_pointer_cast<FloatingPoint::FloatingPoint> (unimproved->getGenotype(0));
235 flp->initialize(state);
236 evaluate(unimproved);
237 }
238
239 return true;
240}
241
242
243bool ArtificialBeeColony::createNewFoodSource(IndividualP food, StateP state, DemeP deme)
244{
245 // for each food source find a neighbour
246 IndividualP neighbour;
247 do{
248 neighbour = selRandomOp->select(*deme);
249 }while(food->index == neighbour->index);
250
251 // potential new food source
252 IndividualP newFood = copy(food);
253
254 FloatingPointP flp = boost::static_pointer_cast<FloatingPoint::FloatingPoint> (food->getGenotype(0));
255 std::vector< double > &foodVars = flp->realValue;
256 flp = boost::static_pointer_cast<FloatingPoint::FloatingPoint> (neighbour->getGenotype(0));
257 std::vector< double > &neighbourVars = flp->realValue;
258 flp = boost::static_pointer_cast<FloatingPoint::FloatingPoint> (newFood->getGenotype(0));
259 std::vector< double > &newFoodVars = flp->realValue;
260
261
262 uint param = state->getRandomizer()->getRandomInteger((int)foodVars.size());
263 double factor = state->getRandomizer()->getRandomDouble();
264 double value = foodVars[param] * (1 - 2 * factor) * (foodVars[param] - neighbourVars[param]);
265 if (value > ubound_)
266 value = ubound_;
267 else if (value < lbound_)
268 value = lbound_;
269
270 // produce a modification on the food source (discover a new food source)
271 newFoodVars[param] = value;
272 evaluate(newFood);
273
274 flp = boost::static_pointer_cast<FloatingPoint::FloatingPoint> (food->getGenotype(1));
275 double &foodTrial = flp->realValue[0];
276
277 // d) if the fitness value of the new food source is better than that of the original source,
278 // memorize the new source, forget the old one and set trial to 0
279 // otherwise keep the old one and increment trial
280 if(newFood->fitness->isBetterThan(food->fitness) )
281 {
282 foodVars[param] = value;
283 evaluate(food);
284 foodTrial = 0;
285 }
286 else {
287 foodTrial += 1;
288 }
289 return true;
290}
IndividualP copy(IndividualP source)
Helper function: make a copy of an individual.
Definition: Algorithm.h:291
std::string name_
algorithm name
Definition: Algorithm.h:23
bool registerParameter(StateP state, std::string name, voidP value, enum ECF::type T, std::string description="")
Helper function: register a single parameter with the system.
Definition: Algorithm.h:35
voidP getParameterValue(StateP state, std::string name)
Helper function: get parameter value from the system.
Definition: Algorithm.h:46
void evaluate(IndividualP ind)
Helper function: evaluate an individual.
Definition: Algorithm.h:157
bool advanceGeneration(StateP state, DemeP deme)
Perform a single generation on a single deme.
bool initialize(StateP state)
Initialize the algorithm, read parameters from the system, do a sanity check.
void registerParameters(StateP state)
Register algorithm's parameters (if any).
FloatingPoint class - implements genotype as a vector of floating point values.
Definition: FloatingPoint.h:39
bool setParameterValue(StateP state, std::string name, voidP value)
Write single parameter value to Registry.
Definition: Genotype.cpp:16
Best individual selection operator.
Definition: SelBestOp.h:10
Fitness proportional (and inverse proportional) individual selection operator.
Random individual selection operator.
Definition: SelRandomOp.h:12
Worst individual selection operator.
Definition: SelWorstOp.h:11