forked from jibsen/galib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathex14.C
373 lines (312 loc) · 11.2 KB
/
ex14.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/* ----------------------------------------------------------------------------
ex14.C
mbwall 29apr95
Copyright (c) 1995-1996 Massachusetts Institute of Technology
DESCRIPTION:
Example program for a composite genome derived from the GAGenome and
containing a list of lists. This example shows how to derive your own genome
class and illustrates the use of one of the template genomes (GAListGenome)
from the GAlib.
---------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <ga/ga.h>
#include <ga/std_stream.h>
#define cout STD_COUT
#define cerr STD_CERR
#define endl STD_ENDL
#define istream STD_ISTREAM
#define ostream STD_OSTREAM
// Here we specify how big the lists will be and how many lists will be in each
// composite genome. These are the default values - you can change them from
// the command line. Beware that this program will break if nrobots is bigger
// than the size of the lists.
int listsize = 10;
int nrobots = 6;
// This is the class definition. We override the methods of the base class and
// define a few methods of our own to access the protected members. The list
// genomes in the composite genome are assigned the 'List' operators
// by default (they can be overridden by using the 'Operator' members on the
// lists explicitly).
// The ID can be any number over 200 (IDs under 200 are reserved for use by
// GAlib objects).
class RobotPathGenome : public GAGenome {
public:
GADefineIdentity("RobotPathGenome", 251);
static void Initializer(GAGenome&);
static int Mutator(GAGenome&, float);
static float Comparator(const GAGenome&, const GAGenome&);
static float Evaluator(GAGenome&);
static void PathInitializer(GAGenome&);
static int Crossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*);
public:
RobotPathGenome(int nrobots, int pathlength);
RobotPathGenome(const RobotPathGenome & orig) { n=l=0; list=0; copy(orig); }
RobotPathGenome operator=(const GAGenome & arg) { copy(arg); return *this; }
virtual ~RobotPathGenome();
virtual GAGenome *clone(GAGenome::CloneMethod) const ;
virtual void copy(const GAGenome & c);
virtual int equal(const GAGenome& g) const;
virtual int read(istream & is);
virtual int write(ostream & os) const ;
GAListGenome<int> & path(const int i){return *list[i];}
int npaths() const { return n; }
int length() const { return l; }
protected:
int n, l;
GAListGenome<int> **list;
};
RobotPathGenome::RobotPathGenome(int nrobots, int pathlength) :
GAGenome(Initializer, Mutator, Comparator){
evaluator(Evaluator); crossover(Crossover); n = nrobots; l = pathlength;
list = (n ? new GAListGenome<int> * [n] : (GAListGenome<int> **)0);
for(int i=0; i<n; i++){
list[i] = new GAListGenome<int>;
list[i]->initializer(PathInitializer);
list[i]->mutator(GAListGenome<int>::SwapMutator);
}
}
void
RobotPathGenome::copy(const GAGenome& g) {
if(&g != this && sameClass(g)){
GAGenome::copy(g); // copy the base class part
RobotPathGenome & genome = (RobotPathGenome &)g;
if(n == genome.n){
for(int i=0; i<n; i++)
list[i]->copy(*genome.list[i]);
}
else{
int i;
for(i=0; i<n; i++)
delete list[i];
delete [] list;
n = genome.n;
list = new GAListGenome<int> * [n];
for(i=0; i<n; i++)
list[i] = (GAListGenome<int> *)genome.list[i]->clone();
}
}
}
RobotPathGenome::~RobotPathGenome(){
for(int i=0; i<n; i++)
delete list[i];
delete [] list;
}
GAGenome*
RobotPathGenome::clone(GAGenome::CloneMethod) const {
return new RobotPathGenome(*this);
}
int
RobotPathGenome::equal(const GAGenome& g) const {
RobotPathGenome& genome = (RobotPathGenome&)g;
int flag=0;
for(int i=0; i<n && flag==0; i++)
flag = list[i]->equal(*genome.list[i]);
return flag;
}
int
RobotPathGenome::read(istream & is) {
for(int i=0; i<n; i++)
is >> *(list[i]);
return is.fail() ? 1 : 0;
}
int
RobotPathGenome::write(ostream & os) const {
for(int i=0; i<n; i++)
os << "list " << i << ":\t" << *(list[i]) << "\n";
return os.fail() ? 1 : 0;
}
// These are the definitions of the operators for the robot path genome.
void
RobotPathGenome::Initializer(GAGenome& g) {
RobotPathGenome & genome = (RobotPathGenome &)g;
for(int i=0; i<genome.npaths(); i++)
genome.path(i).initialize();
genome._evaluated = gaFalse;
}
int
RobotPathGenome::Mutator(GAGenome& g, float pmut) {
RobotPathGenome & genome = (RobotPathGenome &)g;
int nMut = 0;
for(int i=0; i<genome.npaths(); i++)
nMut += genome.path(i).mutate(pmut);
if(nMut) genome._evaluated = gaFalse;
return nMut;
}
float
RobotPathGenome::Comparator(const GAGenome& a, const GAGenome& b) {
RobotPathGenome& sis = (RobotPathGenome &)a;
RobotPathGenome& bro = (RobotPathGenome &)b;
float diff = 0;
for(int i=0; i<sis.npaths(); i++)
diff += sis.path(i).compare(bro.path(i));
return diff/sis.npaths();
}
// The objective function should evaluate the genomes. This one tries to
// put the node with value 0 into the nth position where n is the number of the
// list in the composite genome. We're assuming that there are more nodes
// in the list than there are lists in the composite genome.
float
RobotPathGenome::Evaluator(GAGenome & c) {
RobotPathGenome & genome = (RobotPathGenome &)c;
float score=0;
for(int i=0; i<genome.npaths(); i++)
if(*genome.path(i).warp(i) == 0) score += 1;
return score;
}
// This crossover method assumes that all of the robot path genomes have the
// same number of paths in them. With a few modifications you could make the
// paths be variable length, but then you must use a crossover method other
// than the partial match crossover used here (defined in the robot path
// crossover object).
int
RobotPathGenome::
Crossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) {
RobotPathGenome& mom = (RobotPathGenome &)a;
RobotPathGenome& dad = (RobotPathGenome &)b;
int n=0;
if(c && d){
RobotPathGenome& sis = (RobotPathGenome &)*c;
RobotPathGenome& bro = (RobotPathGenome &)*d;
for(int i=0; i<mom.npaths(); i++)
GAListGenome<int>::PartialMatchCrossover(mom.path(i), dad.path(i),
&sis.path(i), &bro.path(i));
sis._evaluated = gaFalse;
bro._evaluated = gaFalse;
n=2;
}
else if(c) {
RobotPathGenome& sis = (RobotPathGenome &)*c;
for(int i=0; i<mom.npaths(); i++)
GAListGenome<int>::PartialMatchCrossover(mom.path(i), dad.path(i),
&sis.path(i), 0);
sis._evaluated = gaFalse;
n=1;
}
else if(d) {
RobotPathGenome& bro = (RobotPathGenome &)*d;
for(int i=0; i<mom.npaths(); i++)
GAListGenome<int>::PartialMatchCrossover(mom.path(i), dad.path(i),
0, &bro.path(i));
bro._evaluated = gaFalse;
n=1;
}
return n;
}
// This is the initialization operator for our lists. We create a list that is
// n long and whose nodes contain numbers in sequence.
// The first thing to do in the initializer is to clear out any old
// contents - we do not want to build our new list on a previously existing
// one! Notice that we have to cast the genome into the type of
// genome we're using (in this case a list). The GA always operates on
// generic genomes.
// All of our lists must be the same length since we're going to use the
// ordered crossover operators.
void
RobotPathGenome::PathInitializer(GAGenome & c){
GAListGenome<int> & list = (GAListGenome<int> &)c;
// We must first destroy any pre-existing list.
while(list.head()) list.destroy();
// Insert the head of the list. This node has a random number in it, but the
// number is in a range different than those in the rest of the list. This
// way we'll be able to see how the lists get scrambled up. Since we're using
// ordered crossover (see the header file) we should never end up with more
// than one node in each list that has a given value.
list.insert(0, GAListBASE::HEAD);
// Loop through n times and append nodes onto the end of the list.
int i;
for(i=0; i<listsize-1; i++)
list.insert(i+20, GAListBASE::AFTER);
// Now randomize the contents of the list.
for(i=0; i<listsize; i++)
if(GARandomBit()) list.swap(i, GARandomInt(0, listsize-1));
}
// Here is the specialization of the write method for our lists. The default
// write method just prints out pointers to the contents of the nodes (it has
// no way of knowing in advance how you'll want things printed). Here we
// do almost the same thing, but print out the contents of the nodes rather
// than the pointers to the contents.
template <> int
GAListGenome<int>::write(ostream & os) const {
int *cur, *head;
GAListIter<int> iter(*this);
if((head=iter.head()) != 0) os << *head << " ";
for(cur=iter.next(); cur && cur != head; cur=iter.next())
os << *cur << " ";
return os.fail() ? 1 : 0;
}
int
main(int argc, char *argv[])
{
cout << "Example 14\n\n";
cout << "This example shows how to create a genome that contains\n";
cout << "a list of lists. We create a composite genome that has\n";
cout << "lists in it. Each list has some nodes, only one of which\n";
cout << "contains the number 0. The objective is to move the node with\n";
cout << "number 0 in it to the nth position where n is the number of the\n";
cout << "list within the composite genome.\n\n";
cout.flush();
// See if we've been given a seed to use (for testing purposes). When you
// specify a random seed, the evolution will be exactly the same each time
// you use that seed number.
int i;
for(i=1; i<argc; i++){
if(strcmp("nr", argv[i]) == 0){
if(++i >= argc){
cerr << argv[0] << ": number of robots needs a value.\n";
exit(1);
}
else{
nrobots = atoi(argv[i]);
continue;
}
}
else if(strcmp("pl", argv[i]) == 0){
if(++i >= argc){
cerr << argv[0] << ": path length needs a value.\n";
exit(1);
}
else{
listsize = atoi(argv[i]);
continue;
}
}
else if(strcmp(argv[i],"seed") == 0) {
if(++i >= argc){
cerr << argv[0] << ": seed needs a value.\n";
exit(1);
}
else {
GARandomSeed((unsigned int)atoi(argv[i]));
}
}
else if(strcmp("help",argv[i]) == 0){
cerr << "valid arguements include standard GAlib arguments plus:\n";
cerr << " nr\tnumber of robots (" << nrobots << ")\n";
cerr << " pl\tlength of the paths (" << listsize << ")\n";
cerr << "\n";
exit(1);
}
}
if(listsize < nrobots) {
cerr << "path length must be greater than the number of robots.\n";
exit(1);
}
RobotPathGenome genome(nrobots, listsize);
GASteadyStateGA ga(genome);
ga.parameters(argc,argv);
ga.evolve();
genome.initialize();
cout << "a randomly-generated set of paths:\n" << genome << endl;
cout << "the ga generated:\n" << ga.statistics().bestIndividual() << "\n";
return 0;
}
// force instantiations for compilers that do not do auto instantiation.
// for some compilers (e.g. metrowerks) this must come after any
// specializations or you will get 'multiply-defined errors when you compile.
#if !defined(GALIB_USE_AUTO_INST)
#include <ga/GAList.C>
#include <ga/GAListGenome.C>
GALIB_INSTANTIATION_PREFIX GAList<int>;
GALIB_INSTANTIATION_PREFIX GAListGenome<int>;
#endif