Modernized GAlib  3.0.0 current
GA1DArrayGenome.hpp
1 /* ----------------------------------------------------------------------------
2  mbwall 25feb95
3  Copyright (c) 1995-1996 Massachusetts Institute of Technology
4  all rights reserved
5  ---------------------------------------------------------------------------- */
6 
7 #pragma once
8 
9 #include "GAAllele.h"
10 #include "GAArray.h"
11 #include "GAGenome.h"
12 #include "GAMask.h"
13 #include <cstdio>
14 #include <cstdlib>
15 #include <cstring>
16 #include "garandom.h"
17 #include <vector>
18 #include <array>
19 
20 
41 template <class T> class GA1DArrayGenome : public GAArray<T>, public GAGenome
42 {
43  public:
44  GADefineIdentity("GA1DArrayGenome", GAID::ArrayGenome);
45 
52  static int SwapMutator(GAGenome &c, float pmut)
53  {
54  GA1DArrayGenome<T> &child = DYN_CAST(GA1DArrayGenome<T> &, c);
55 
56  if (pmut <= 0.0)
57  return (0);
58 
59  float nMut = pmut * STA_CAST(float, child.length());
60  int length = child.length() - 1;
61  if (nMut < 1.0)
62  { // we have to do a flip test on each bit
63  nMut = 0;
64  for (int i = length; i >= 0; i--)
65  {
66  if (GAFlipCoin(pmut))
67  {
68  child.swap(i, GARandomInt(0, length));
69  nMut++;
70  }
71  }
72  }
73  else
74  { // only flip the number of bits we need to flip
75  for (int n = 0; n < nMut; n++)
76  child.swap(GARandomInt(0, length), GARandomInt(0, length));
77  }
78  return (STA_CAST(int, nMut));
79  }
80 
90  static float ElementComparator(const GAGenome &a, const GAGenome &b)
91  {
92  const GA1DArrayGenome<T> &sis = DYN_CAST(const GA1DArrayGenome<T> &, a);
93  const GA1DArrayGenome<T> &bro = DYN_CAST(const GA1DArrayGenome<T> &, b);
94 
95  if (sis.length() != bro.length())
96  return -1;
97  if (sis.length() == 0)
98  return 0;
99  float count = 0.0;
100  for (int i = sis.length() - 1; i >= 0; i--)
101  count += ((sis.gene(i) == bro.gene(i)) ? 0 : 1);
102  return count / sis.length();
103  }
104 
116  static int UniformCrossover(const GAGenome &p1, const GAGenome &p2,
117  GAGenome *c1, GAGenome *c2)
118  {
119  const GA1DArrayGenome<T> &mom = DYN_CAST(const GA1DArrayGenome<T> &, p1);
120  const GA1DArrayGenome<T> &dad = DYN_CAST(const GA1DArrayGenome<T> &, p2);
121 
122  int n = 0;
123 
124  if (c1 && c2)
125  {
126  GA1DArrayGenome<T> &sis = DYN_CAST(GA1DArrayGenome<T> &, *c1);
127  GA1DArrayGenome<T> &bro = DYN_CAST(GA1DArrayGenome<T> &, *c2);
128 
129  if (sis.length() == bro.length()
130  && mom.length() == dad.length()
131  && sis.length() == mom.length())
132  {
133  for (int i = sis.length() - 1; i >= 0; i--)
134  {
135  if (GARandomBit())
136  {
137  sis.gene(i, mom.gene(i));
138  bro.gene(i, dad.gene(i));
139  }
140  else
141  {
142  sis.gene(i, dad.gene(i));
143  bro.gene(i, mom.gene(i));
144  }
145  }
146  }
147  else
148  {
149  GAMask mask;
150  int max = (sis.length() > bro.length()) ? sis.length() : bro.length();
151  int min = (mom.length() < dad.length()) ? mom.length() : dad.length();
152  mask.size(max);
153  for (int i = 0; i < max; i++)
154  mask[i] = GARandomBit();
155  int start = (sis.length() < min) ? sis.length() - 1 : min - 1;
156  for (int i = start; i >= 0; i--)
157  sis.gene(i, (mask[i] ? mom.gene(i) : dad.gene(i)));
158  start = (bro.length() < min) ? bro.length() - 1 : min - 1;
159  for (int i = start; i >= 0; i--)
160  bro.gene(i, (mask[i] ? dad.gene(i) : mom.gene(i)));
161  }
162  n = 2;
163  }
164  else if (c1 || c2)
165  {
166  GA1DArrayGenome<T> &sis = (c1 ? DYN_CAST(GA1DArrayGenome<T> &, *c1) : DYN_CAST(GA1DArrayGenome<T> &, *c2));
167 
168  if (mom.length() == dad.length() && sis.length() == mom.length())
169  {
170  for (int i = sis.length() - 1; i >= 0; i--)
171  sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i)));
172  }
173  else
174  {
175  int min = (mom.length() < dad.length()) ? mom.length() : dad.length();
176  min = (sis.length() < min) ? sis.length() : min;
177  for (int i = min - 1; i >= 0; i--)
178  sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i)));
179  }
180  n = 1;
181  }
182 
183  return n;
184  }
185 
186  // Single point crossover for 1D array genomes. Pick a single point then
187  // copy genetic material from each parent. We must allow for resizable
188  // genomes so be sure to check the behaviours before we do the crossovers.
189  // If resizing is allowed then the children will change depending on where
190  // the site is located. It is also possible to have a mixture of resize
191  // behaviours, but we won't worry about that at this point. If this happens
192  // we just say that we cannot handle that and post an error message.
193  static int OnePointCrossover(const GAGenome &p1, const GAGenome &p2,
194  GAGenome *c1, GAGenome *c2)
195  {
196  const GA1DArrayGenome<T> &mom =
197  DYN_CAST(const GA1DArrayGenome<T> &, p1);
198  const GA1DArrayGenome<T> &dad =
199  DYN_CAST(const GA1DArrayGenome<T> &, p2);
200 
201  int nc = 0;
202  unsigned int momsite, momlen;
203  unsigned int dadsite, dadlen;
204 
205  if (c1 && c2)
206  {
207  GA1DArrayGenome<T> &sis = DYN_CAST(GA1DArrayGenome<T> &, *c1);
208  GA1DArrayGenome<T> &bro = DYN_CAST(GA1DArrayGenome<T> &, *c2);
209 
210  if (sis.resizeBehaviour() == GAGenome::FIXED_SIZE &&
211  bro.resizeBehaviour() == GAGenome::FIXED_SIZE)
212  {
213  if (mom.length() != dad.length() ||
214  sis.length() != bro.length() ||
215  sis.length() != mom.length())
216  {
217  GAErr(GA_LOC, mom.className(), "one-point cross",
218  GAError::SameLengthReqd);
219  return nc;
220  }
221  momsite = dadsite = GARandomInt(0, mom.length());
222  momlen = dadlen = mom.length() - momsite;
223  }
224  else if (sis.resizeBehaviour() == GAGenome::FIXED_SIZE ||
225  bro.resizeBehaviour() == GAGenome::FIXED_SIZE)
226  {
227  GAErr(GA_LOC, mom.className(), "one-point cross",
228  GAError::SameBehavReqd);
229  return nc;
230  }
231  else
232  {
233  momsite = GARandomInt(0, mom.length());
234  dadsite = GARandomInt(0, dad.length());
235  momlen = mom.length() - momsite;
236  dadlen = dad.length() - dadsite;
237  sis.resize(momsite + dadlen);
238  bro.resize(dadsite + momlen);
239  }
240 
241  sis.copy(mom, 0, 0, momsite);
242  sis.copy(dad, momsite, dadsite, dadlen);
243  bro.copy(dad, 0, 0, dadsite);
244  bro.copy(mom, dadsite, momsite, momlen);
245 
246  nc = 2;
247  }
248  else if (c1 || c2)
249  {
250  GA1DArrayGenome<T> &sis =
251  (c1 ? DYN_CAST(GA1DArrayGenome<T> &, *c1)
252  : DYN_CAST(GA1DArrayGenome<T> &, *c2));
253 
254  if (sis.resizeBehaviour() == GAGenome::FIXED_SIZE)
255  {
256  if (mom.length() != dad.length() ||
257  sis.length() != mom.length())
258  {
259  GAErr(GA_LOC, mom.className(), "one-point cross",
260  GAError::SameLengthReqd);
261  return nc;
262  }
263  momsite = dadsite = GARandomInt(0, mom.length());
264  momlen = dadlen = mom.length() - momsite;
265  }
266  else
267  {
268  momsite = GARandomInt(0, mom.length());
269  dadsite = GARandomInt(0, dad.length());
270  momlen = mom.length() - momsite;
271  dadlen = dad.length() - dadsite;
272  sis.resize(momsite + dadlen);
273  }
274 
275  if (GARandomBit())
276  {
277  sis.copy(mom, 0, 0, momsite);
278  sis.copy(dad, momsite, dadsite, dadlen);
279  }
280  else
281  {
282  sis.copy(dad, 0, 0, dadsite);
283  sis.copy(mom, dadsite, momsite, momlen);
284  }
285 
286  nc = 1;
287  }
288 
289  return nc;
290  }
291 
292  // Two point crossover for the 1D array genome. Similar to the single point
293  // crossover, but here we pick two points then grab the sections based upon
294  // those two points.
295  // When we pick the points, it doesn't matter where they fall (one is not
296  // dependent upon the other). Make sure we get the lesser one into the
297  // first position of our site array.
298  static int TwoPointCrossover(const GAGenome &p1, const GAGenome &p2,
299  GAGenome *c1, GAGenome *c2)
300  {
301  const GA1DArrayGenome<T> &mom =
302  DYN_CAST(const GA1DArrayGenome<T> &, p1);
303  const GA1DArrayGenome<T> &dad =
304  DYN_CAST(const GA1DArrayGenome<T> &, p2);
305 
306  int nc = 0;
307  std::array<unsigned int, 2> momsite;
308  std::array<unsigned int, 2> momlen;
309  std::array<unsigned int, 2> dadsite;
310  std::array<unsigned int, 2> dadlen;
311 
312  if (c1 && c2)
313  {
314  GA1DArrayGenome<T> &sis = DYN_CAST(GA1DArrayGenome<T> &, *c1);
315  GA1DArrayGenome<T> &bro = DYN_CAST(GA1DArrayGenome<T> &, *c2);
316 
317  if (sis.resizeBehaviour() == GAGenome::FIXED_SIZE &&
318  bro.resizeBehaviour() == GAGenome::FIXED_SIZE)
319  {
320  if (mom.length() != dad.length() ||
321  sis.length() != bro.length() ||
322  sis.length() != mom.length())
323  {
324  GAErr(GA_LOC, mom.className(), "two-point cross",
325  GAError::SameLengthReqd);
326  return nc;
327  }
328  momsite.at(0) = GARandomInt(0, mom.length());
329  momsite.at(1) = GARandomInt(0, mom.length());
330  if (momsite.at(0) > momsite.at(1))
331  SWAP(momsite.at(0), momsite.at(1));
332  momlen.at(0) = momsite.at(1) - momsite.at(0);
333  momlen.at(1) = mom.length() - momsite.at(1);
334 
335  dadsite.at(0) = momsite.at(0);
336  dadsite.at(1) = momsite.at(1);
337  dadlen.at(0) = momlen.at(0);
338  dadlen.at(1) = momlen.at(1);
339  }
340  else if (sis.resizeBehaviour() == GAGenome::FIXED_SIZE ||
341  bro.resizeBehaviour() == GAGenome::FIXED_SIZE)
342  {
343  return nc;
344  }
345  else
346  {
347  momsite.at(0) = GARandomInt(0, mom.length());
348  momsite.at(1) = GARandomInt(0, mom.length());
349  if (momsite.at(0) > momsite.at(1))
350  SWAP(momsite.at(0), momsite.at(1));
351  momlen.at(0) = momsite.at(1) - momsite.at(0);
352  momlen.at(1) = mom.length() - momsite.at(1);
353 
354  dadsite.at(0) = GARandomInt(0, dad.length());
355  dadsite.at(1) = GARandomInt(0, dad.length());
356  if (dadsite.at(0) > dadsite.at(1))
357  SWAP(dadsite.at(0), dadsite.at(1));
358  dadlen.at(0) = dadsite.at(1) - dadsite.at(0);
359  dadlen.at(1) = dad.length() - dadsite.at(1);
360 
361  sis.resize(momsite.at(0) + dadlen.at(0) + momlen.at(1));
362  bro.resize(dadsite.at(0) + momlen.at(0) + dadlen.at(1));
363  }
364 
365  sis.copy(mom, 0, 0, momsite.at(0));
366  sis.copy(dad, momsite.at(0), dadsite.at(0), dadlen.at(0));
367  sis.copy(mom, momsite.at(0) + dadlen.at(0), momsite.at(1), momlen.at(1));
368  bro.copy(dad, 0, 0, dadsite.at(0));
369  bro.copy(mom, dadsite.at(0), momsite.at(0), momlen.at(0));
370  bro.copy(dad, dadsite.at(0) + momlen.at(0), dadsite.at(1), dadlen.at(1));
371 
372  nc = 2;
373  }
374  else if (c1 || c2)
375  {
376  GA1DArrayGenome<T> &sis =
377  (c1 ? DYN_CAST(GA1DArrayGenome<T> &, *c1)
378  : DYN_CAST(GA1DArrayGenome<T> &, *c2));
379 
380  if (sis.resizeBehaviour() == GAGenome::FIXED_SIZE)
381  {
382  if (mom.length() != dad.length() ||
383  sis.length() != mom.length())
384  {
385  GAErr(GA_LOC, mom.className(), "two-point cross",
386  GAError::SameLengthReqd);
387  return nc;
388  }
389  momsite.at(0) = GARandomInt(0, mom.length());
390  momsite.at(1) = GARandomInt(0, mom.length());
391  if (momsite.at(0) > momsite.at(1))
392  SWAP(momsite.at(0), momsite.at(1));
393  momlen.at(0) = momsite.at(1) - momsite.at(0);
394  momlen.at(1) = mom.length() - momsite.at(1);
395 
396  dadsite.at(0) = momsite.at(0);
397  dadsite.at(1) = momsite.at(1);
398  dadlen.at(0) = momlen.at(0);
399  dadlen.at(1) = momlen.at(1);
400  }
401  else
402  {
403  momsite.at(0) = GARandomInt(0, mom.length());
404  momsite.at(1) = GARandomInt(0, mom.length());
405  if (momsite.at(0) > momsite.at(1))
406  SWAP(momsite.at(0), momsite.at(1));
407  momlen.at(0) = momsite.at(1) - momsite.at(0);
408  momlen.at(1) = mom.length() - momsite.at(1);
409 
410  dadsite.at(0) = GARandomInt(0, dad.length());
411  dadsite.at(1) = GARandomInt(0, dad.length());
412  if (dadsite.at(0) > dadsite.at(1))
413  SWAP(dadsite.at(0), dadsite.at(1));
414  dadlen.at(0) = dadsite.at(1) - dadsite.at(0);
415  dadlen.at(1) = dad.length() - dadsite.at(1);
416 
417  sis.resize(momsite.at(0) + dadlen.at(0) + momlen.at(1));
418  }
419 
420  if (GARandomBit())
421  {
422  sis.copy(mom, 0, 0, momsite.at(0));
423  sis.copy(dad, momsite.at(0), dadsite.at(0), dadlen.at(0));
424  sis.copy(mom, momsite.at(0) + dadlen.at(0), momsite.at(1), momlen.at(1));
425  }
426  else
427  {
428  sis.copy(dad, 0, 0, dadsite.at(0));
429  sis.copy(mom, dadsite.at(0), momsite.at(0), momlen.at(0));
430  sis.copy(dad, dadsite.at(0) + momlen.at(0), dadsite.at(1), dadlen.at(1));
431  }
432 
433  nc = 1;
434  }
435 
436  return nc;
437  }
438 
439  // Even and odd crossover for the array works just like it does for the
440  // binary strings. For even crossover we take the 0th element and every
441  // other one after that from the mother. The 1st and every other come from
442  // the father. For odd crossover, we do just the opposite.
443  static int EvenOddCrossover(const GAGenome &p1, const GAGenome &p2,
444  GAGenome *c1, GAGenome *c2)
445  {
446  const GA1DArrayGenome<T> &mom =
447  DYN_CAST(const GA1DArrayGenome<T> &, p1);
448  const GA1DArrayGenome<T> &dad =
449  DYN_CAST(const GA1DArrayGenome<T> &, p2);
450 
451  int nc = 0;
452  int i;
453 
454  if (c1 && c2)
455  {
456  GA1DArrayGenome<T> &sis = DYN_CAST(GA1DArrayGenome<T> &, *c1);
457  GA1DArrayGenome<T> &bro = DYN_CAST(GA1DArrayGenome<T> &, *c2);
458  if (sis.length() == bro.length() && mom.length() == dad.length() &&
459  sis.length() == mom.length())
460  {
461  for (i = sis.length() - 1; i >= 1; i -= 2)
462  {
463  sis.gene(i, mom.gene(i));
464  bro.gene(i, dad.gene(i));
465  sis.gene(i - 1, dad.gene(i - 1));
466  bro.gene(i - 1, mom.gene(i - 1));
467  }
468  if (i == 0)
469  {
470  sis.gene(0, mom.gene(0));
471  bro.gene(0, dad.gene(0));
472  }
473  }
474  else
475  {
476  int min = (mom.length() < dad.length()) ? mom.length() : dad.length();
477  int start = (sis.length() < min) ? sis.length() - 1 : min - 1;
478  for (i = start; i >= 0; i--)
479  sis.gene(i, ((i % 2 == 0) ? mom.gene(i) : dad.gene(i)));
480  start = (bro.length() < min) ? bro.length() - 1 : min - 1;
481  for (i = start; i >= 0; i--)
482  bro.gene(i, ((i % 2 == 0) ? dad.gene(i) : mom.gene(i)));
483  }
484 
485  nc = 2;
486  }
487  else if (c1 || c2)
488  {
489  GA1DArrayGenome<T> &sis =
490  (c1 ? DYN_CAST(GA1DArrayGenome<T> &, *c1)
491  : DYN_CAST(GA1DArrayGenome<T> &, *c2));
492 
493  if (mom.length() == dad.length() && sis.length() == mom.length())
494  {
495  for (i = sis.length() - 1; i >= 1; i -= 2)
496  {
497  sis.gene(i, mom.gene(i));
498  sis.gene(i - 1, dad.gene(i - 1));
499  }
500  if (i == 0)
501  {
502  sis.gene(0, mom.gene(0));
503  }
504  }
505  else
506  {
507  int min =
508  (mom.length() < dad.length()) ? mom.length() : dad.length();
509  min = (sis.length() < min) ? sis.length() - 1 : min - 1;
510  for (i = min; i >= 0; i--)
511  sis.gene(i, ((i % 2 == 0) ? mom.gene(i) : dad.gene(i)));
512  }
513 
514  nc = 1;
515  }
516 
517  return nc;
518  }
519 
520  // Partial match crossover for the 1D array genome. This uses the partial
521  // matching algorithm described in Goldberg's book.
522  // Parents and children must be the same size for this crossover to work.
523  // If
524  // they are not, we post an error message.
525  // We make sure that b will be greater than a.
526  static int PartialMatchCrossover(const GAGenome &p1, const GAGenome &p2,
527  GAGenome *c1, GAGenome *c2)
528  {
529  const GA1DArrayGenome<T> &mom =
530  DYN_CAST(const GA1DArrayGenome<T> &, p1);
531  const GA1DArrayGenome<T> &dad =
532  DYN_CAST(const GA1DArrayGenome<T> &, p2);
533 
534  int nc = 0;
535  int a = GARandomInt(0, mom.length());
536  int b = GARandomInt(0, dad.length());
537  if (b < a)
538  SWAP(a, b);
539  int i, j, index;
540 
541  if (mom.length() != dad.length())
542  {
543  GAErr(GA_LOC, mom.className(), "parial match cross",
544  GAError::BadParentLength);
545  return nc;
546  }
547 
548  if (c1 && c2)
549  {
550  GA1DArrayGenome<T> &sis = DYN_CAST(GA1DArrayGenome<T> &, *c1);
551  GA1DArrayGenome<T> &bro = DYN_CAST(GA1DArrayGenome<T> &, *c2);
552 
553  sis.GAArray<T>::copy(mom);
554  for (i = a, index = a; i < b; i++, index++)
555  {
556  for (j = 0;
557  j < sis.length() - 1 && sis.gene(j) != dad.gene(index);
558  j++)
559  ;
560  sis.swap(i, j);
561  }
562  bro.GAArray<T>::copy(dad);
563  for (i = a, index = a; i < b; i++, index++)
564  {
565  for (j = 0;
566  j < bro.length() - 1 && bro.gene(j) != mom.gene(index);
567  j++)
568  ;
569  bro.swap(i, j);
570  }
571 
572  nc = 2;
573  }
574  else if (c1 || c2)
575  {
576  GA1DArrayGenome<T> &sis =
577  (c1 ? DYN_CAST(GA1DArrayGenome<T> &, *c1)
578  : DYN_CAST(GA1DArrayGenome<T> &, *c2));
579 
580  const GA1DArrayGenome<T> *parent1, *parent2;
581  if (GARandomBit())
582  {
583  parent1 = &mom;
584  parent2 = &dad;
585  }
586  else
587  {
588  parent1 = &dad;
589  parent2 = &mom;
590  }
591 
592  sis.GAArray<T>::copy(*parent1);
593  for (i = a, index = a; i < b; i++, index++)
594  {
595  for (j = 0; j < sis.length() - 1 &&
596  sis.gene(j) != parent2->gene(index);
597  j++)
598  ;
599  sis.swap(i, j);
600  }
601 
602  nc = 1;
603  }
604 
605  return nc;
606  }
607 
608  // Order crossover for the 1D array genome. This uses the order crossover
609  // described in Goldberg's book.
610  // Parents and children must be the same length.
611  // We make sure that b will be greater than a.
612  // This implementation isn't terribly smart. For example, I do a linear
613  // search rather than caching and doing binary search or smarter hash
614  // tables.
615  // First we copy the mother into the sister. Then move the 'holes' into
616  // the
617  // crossover section and maintain the ordering of the non-hole elements.
618  // Finally, put the 'holes' in the proper order within the crossover
619  // section. After we have done the sister, we do the brother.
620  static int OrderCrossover(const GAGenome &p1, const GAGenome &p2, GAGenome *c1, GAGenome *c2)
621  {
622  const GA1DArrayGenome<T> &mom = DYN_CAST(const GA1DArrayGenome<T> &, p1);
623  const GA1DArrayGenome<T> &dad = DYN_CAST(const GA1DArrayGenome<T> &, p2);
624 
625  int nc = 0;
626  int a = GARandomInt(0, mom.length());
627  int b = GARandomInt(0, mom.length());
628  if (b < a)
629  SWAP(a, b);
630  int i, j, index;
631 
632  if (mom.length() != dad.length())
633  {
634  GAErr(GA_LOC, mom.className(), "order cross", GAError::BadParentLength);
635  return nc;
636  }
637 
638  if (c1 && c2)
639  {
640  GA1DArrayGenome<T> &sis = DYN_CAST(GA1DArrayGenome<T> &, *c1);
641  GA1DArrayGenome<T> &bro = DYN_CAST(GA1DArrayGenome<T> &, *c2);
642 
643  // Copy the parent
644  sis.GAArray<T>::copy(mom);
645 
646  // Move all the 'holes' into the crossover section
647  for (i = 0, index = b; i < sis.size(); i++, index++)
648  {
649  if (index >= sis.size())
650  index = 0;
651  if (GA1DArrayIsHole(sis, dad, index, a, b))
652  break;
653  }
654 
655  for (; i < sis.size() - b + a; i++, index++)
656  {
657  if (index >= sis.size())
658  index = 0;
659  j = index;
660  do
661  {
662  j++;
663  if (j >= sis.size())
664  j = 0;
665  } while (GA1DArrayIsHole(sis, dad, j, a, b));
666  sis.swap(index, j);
667  }
668 
669  // Now put the 'holes' in the proper order within the crossover
670  // section.
671  for (i = a; i < b; i++)
672  {
673  if (sis.gene(i) != dad.gene(i))
674  {
675  for (j = i + 1; j < b; j++)
676  if (sis.gene(j) == dad.gene(i))
677  sis.swap(i, j);
678  }
679  }
680 
681  // Now do the other child
682  bro.GAArray<T>::copy(dad);
683 
684  // Move all the 'holes' into the crossover section
685  for (i = 0, index = b; i < bro.size(); i++, index++)
686  {
687  if (index >= bro.size())
688  index = 0;
689  if (GA1DArrayIsHole(bro, mom, index, a, b))
690  break;
691  }
692 
693  for (; i < bro.size() - b + a; i++, index++)
694  {
695  if (index >= bro.size())
696  index = 0;
697  j = index;
698  do
699  {
700  j++;
701  if (j >= bro.size())
702  j = 0;
703  } while (GA1DArrayIsHole(bro, mom, j, a, b));
704  bro.swap(index, j);
705  }
706 
707  // Now put the 'holes' in the proper order within the crossover
708  // section.
709  for (i = a; i < b; i++)
710  {
711  if (bro.gene(i) != mom.gene(i))
712  {
713  for (j = i + 1; j < b; j++)
714  if (bro.gene(j) == mom.gene(i))
715  bro.swap(i, j);
716  }
717  }
718 
719  nc = 2;
720  }
721  else if (c1 || c2)
722  {
723  GA1DArrayGenome<T> &sis =
724  (c1 ? DYN_CAST(GA1DArrayGenome<T> &, *c1)
725  : DYN_CAST(GA1DArrayGenome<T> &, *c2));
726 
727  const GA1DArrayGenome<T> *parent1, *parent2;
728  if (GARandomBit())
729  {
730  parent1 = &mom;
731  parent2 = &dad;
732  }
733  else
734  {
735  parent1 = &dad;
736  parent2 = &mom;
737  }
738 
739  sis.GAArray<T>::copy(*parent1);
740  for (i = 0, index = b; i < sis.size(); i++, index++)
741  {
742  if (index >= sis.size())
743  index = 0;
744  if (GA1DArrayIsHole(sis, *parent2, index, a, b))
745  break;
746  }
747  for (; i < sis.size() - b + a; i++, index++)
748  {
749  if (index >= sis.size())
750  index = 0;
751  j = index;
752  do
753  {
754  j++;
755  if (j >= sis.size())
756  j = 0;
757  } while (GA1DArrayIsHole(sis, *parent2, j, a, b));
758  sis.swap(index, j);
759  }
760  for (i = a; i < b; i++)
761  {
762  if (sis.gene(i) != parent2->gene(i))
763  {
764  for (j = i + 1; j < b; j++)
765  if (sis.gene(j) == parent2->gene(i))
766  sis.swap(i, j);
767  }
768  }
769 
770  nc = 1;
771  }
772 
773  return nc;
774  }
775 
776  // Cycle crossover for the 1D array genome. This is implemented as
777  // described in goldberg's book. The first is picked from mom, then cycle
778  // using dad. Finally, fill in the gaps with the elements from dad.
779  // We allocate space for a temporary array in this routine. It never
780  // frees
781  // the memory that it uses, so you might want to re-think this if you're
782  // really memory-constrained (similar to what we do with the uniform
783  // crossover when the children are resizeable).
784  // Allocate space for an array of flags. We use this to keep track of
785  // whether
786  // the child's contents came from the mother or the father. We don't free
787  // the space here, but it is not a memory leak.
788  // The first step is to cycle through mom & dad to get the cyclic part of
789  // the crossover. Then fill in the rest of the sis with dad's contents that
790  // we didn't use in the cycle. Finally, do the same thing for the other
791  // child.
792  // Notice that this implementation makes serious use of the operator= for
793  // the
794  // objects in the array. It also requires the operator != and ==
795  // comparators.
796  static int CycleCrossover(const GAGenome &p1, const GAGenome &p2,
797  GAGenome *c1, GAGenome *c2)
798  {
799  const GA1DArrayGenome<T> &mom = DYN_CAST(const GA1DArrayGenome<T> &, p1);
800  const GA1DArrayGenome<T> &dad = DYN_CAST(const GA1DArrayGenome<T> &, p2);
801 
802  int nc = 0;
803  int current = 0;
804 
805  if (mom.length() != dad.length())
806  {
807  GAErr(GA_LOC, mom.className(), "cycle cross", GAError::BadParentLength);
808  return nc;
809  }
810 
811  if (c1 && c2)
812  {
813  GAMask mask;
814  GA1DArrayGenome<T> &sis = DYN_CAST(GA1DArrayGenome<T> &, *c1);
815  GA1DArrayGenome<T> &bro = DYN_CAST(GA1DArrayGenome<T> &, *c2);
816 
817  mask.size(sis.length());
818  mask.clear();
819 
820  sis.gene(0, mom.gene(0));
821  mask[0] = 1;
822  while (dad.gene(current) != mom.gene(0))
823  {
824  for (int i = 0; i < sis.size(); i++)
825  {
826  if (mom.gene(i) == dad.gene(current))
827  {
828  sis.gene(i, mom.gene(i));
829  mask[i] = 1;
830  current = i;
831  break;
832  }
833  }
834  }
835 
836  for (int i = 0; i < sis.size(); i++)
837  if (mask[i] == 0)
838  sis.gene(i, dad.gene(i));
839 
840  mask.clear();
841 
842  bro.gene(0, dad.gene(0));
843  mask[0] = 1;
844  while (mom.gene(current) != dad.gene(0))
845  {
846  for (int i = 0; i < bro.size(); i++)
847  {
848  if (dad.gene(i) == mom.gene(current))
849  {
850  bro.gene(i, dad.gene(i));
851  mask[i] = 1;
852  current = i;
853  break;
854  }
855  }
856  }
857 
858  for (int i = 0; i < bro.size(); i++)
859  if (mask[i] == 0)
860  bro.gene(i, mom.gene(i));
861 
862  nc = 2;
863  }
864  else if (c1 || c2)
865  {
866  GA1DArrayGenome<T> &sis = (c1 ? DYN_CAST(GA1DArrayGenome<T> &, *c1) : DYN_CAST(GA1DArrayGenome<T> &, *c2));
867 
868  const GA1DArrayGenome<T> *parent1, *parent2;
869  if (GARandomBit())
870  {
871  parent1 = &mom;
872  parent2 = &dad;
873  }
874  else
875  {
876  parent1 = &dad;
877  parent2 = &mom;
878  }
879 
880  GAMask mask;
881  mask.size(sis.length());
882  mask.clear();
883 
884  sis.gene(0, parent1->gene(0));
885  mask[0] = 1;
886  while (parent2->gene(current) != parent1->gene(0))
887  {
888  for (int i = 0; i < sis.size(); i++)
889  {
890  if (parent1->gene(i) == parent2->gene(current))
891  {
892  sis.gene(i, parent1->gene(i));
893  mask[i] = 1;
894  current = i;
895  break;
896  }
897  }
898  }
899  for (int i = 0; i < sis.size(); i++)
900  if (mask[i] == 0)
901  sis.gene(i, parent2->gene(i));
902 
903  nc = 1;
904  }
905 
906  return nc;
907  }
908 
909  public:
910  // Set all the initial values to NULL or zero, then allocate the space we'll
911  // need (using the resize method). We do NOT call the initialize method at
912  // this point - initialization must be done explicitly by the user of the
913  // genome (eg when the population is created or reset). If we called the
914  // initializer routine here then we could end up with multiple
915  // initializations and/or calls to dummy initializers (for example when the
916  // genome is created with a dummy initializer and the initializer is
917  // assigned later on). Besides, we default to the no-initialization
918  // initializer by calling the default genome constructor.
919  GA1DArrayGenome(unsigned int length, GAGenome::Evaluator f = nullptr, void *u = nullptr)
920  : GAArray<T>(length),
921  GAGenome(DEFAULT_1DARRAY_INITIALIZER, DEFAULT_1DARRAY_MUTATOR, DEFAULT_1DARRAY_COMPARATOR)
922  {
923  evaluator(f);
924  userData(u);
925  nx = minX = maxX = length;
926  crossover(DEFAULT_1DARRAY_CROSSOVER);
927  }
928 
929  // This is the copy initializer. We set everything to the default values,
930  // then copy the original. The Array creator takes care of zeroing the
931  // data.
933  : GAArray<T>(orig.size()), GAGenome()
934  {
936  }
937 
938  GA1DArrayGenome<T> &operator=(const GAGenome &orig)
939  {
940  copy(orig);
941  return *this;
942  }
943  GA1DArrayGenome<T> &operator=(const T array[]) // no err checks!
944  {
945  for (int i = 0; i < this->size(); i++)
946  gene(i, *(array + i));
947  return *this;
948  }
949  ~GA1DArrayGenome() override= default;;
950 
951  GAGenome * clone(GAGenome::CloneMethod flag = CloneMethod::CONTENTS) const override
952  {
953  auto *cpy = new GA1DArrayGenome<T>(nx);
954  if (flag == CloneMethod::CONTENTS)
955  {
956  cpy->copy(*this);
957  }
958  else
959  {
960  cpy->GAGenome::copy(*this);
961  cpy->maxX = maxX;
962  cpy->minX = minX;
963  }
964  return cpy;
965  }
966 
967  // This is the class-specific copy method. It will get called by the super
968  // class since the superclass operator= is set up to call ccopy (and that is
969  // what we define here - a virtual function). We should check to be sure
970  // that both genomes are the same class and same dimension. This function
971  // tries to be smart about they way it copies. If we already have data,
972  // then we do a memcpy of the one we're supposed to copy. If we don't or
973  // we're not the same size as the one we're supposed to copy, then we adjust
974  // ourselves.
975  // The Array takes care of the resize in its copy method.
976  void copy(const GAGenome &orig) override
977  {
978  if (&orig == this)
979  return;
980  const GA1DArrayGenome<T> *c = DYN_CAST(const GA1DArrayGenome<T> *, &orig);
981  if (c)
982  {
983  GAGenome::copy(*c);
984  GAArray<T>::copy(*c);
985  nx = c->nx;
986  minX = c->minX;
987  maxX = c->maxX;
988  }
989  }
990 
991  // We don't define this one apriori. Do it in a specialization.
992  int read(std::istream &) override
993  {
994  GAErr(GA_LOC, className(), "read", GAError::OpUndef);
995  return 1;
996  }
997 
998  // When we write the data to a stream we do it with spaces between elements.
999  // Also, there is no newline at the end of the stream of digits.
1000  int write(std::ostream &os) const override
1001  {
1002  for (unsigned int i = 0; i < nx; i++)
1003  os << gene(i) << " ";
1004  return 0;
1005  }
1006 
1007  bool equal(const GAGenome &c) const override
1008  {
1009  const GA1DArrayGenome<T> &b = DYN_CAST(const GA1DArrayGenome<T> &, c);
1010  return ((this == &c) ? true : ((nx != b.nx) ? 0 : GAArray<T>::equal(b, 0, 0, nx)));
1011  }
1012 
1013  const T &gene(unsigned int x = 0) const { return this->a[x]; }
1014  T &gene(unsigned int x, const T &value)
1015  {
1016  if (this->a.at(x) != value)
1017  {
1018  this->a.at(x) = value;
1019  _evaluated = false;
1020  }
1021  return this->a.at(x);
1022  }
1023  int length() const { return nx; }
1024  int length(int x)
1025  {
1026  resize(x);
1027  return nx;
1028  }
1029 
1030  // Resize the genome.
1031  // A negative value for the length means that we should randomly set the
1032  // length of the genome (if the resize behaviour is resizeable). If
1033  // someone tries to randomly set the length and the resize behaviour is
1034  // fixed length, then we don't do anything.
1035  // We pay attention to the values of minX and maxX - they determine what
1036  // kind
1037  // of resizing we are allowed to do. If a resize is requested with a length
1038  // less than the min length specified by the behaviour, we set the minimum
1039  // to the length. If the length is longer than the max length specified by
1040  // the behaviour, we set the max value to the length.
1041  // We return the total size (in bits) of the genome after resize.
1042  // We don't do anything to the new contents!
1043  virtual int resize(int len)
1044  {
1045  if (len == STA_CAST(int, nx))
1046  return nx;
1047 
1048  if (len == GAGenome::ANY_SIZE)
1049  len = GARandomInt(minX, maxX);
1050  else if (len < 0)
1051  return nx; // do nothing
1052  else if (minX == maxX)
1053  minX = maxX = len;
1054  else
1055  {
1056  if (len < STA_CAST(int, minX))
1057  len = minX;
1058  if (len > STA_CAST(int, maxX))
1059  len = maxX;
1060  }
1061 
1062  nx = GAArray<T>::size(len);
1063  _evaluated = false;
1064  return this->size();
1065  }
1066 
1067  // Set the resize behaviour of the genome. A genome can be fixed
1068  // length, resizeable with a max and min limit, or resizeable with no limits
1069  // (other than an implicit one that we use internally).
1070  // A value of 0 means no resize, a value less than zero mean unlimited
1071  // resize, and a positive value means resize with that value as the limit.
1072 
1073  int resizeBehaviour(unsigned int lower, unsigned int upper)
1074  {
1075  if (upper < lower)
1076  {
1077  GAErr(GA_LOC, className(), "resizeBehaviour",
1078  GAError::BadResizeBehaviour);
1079  return resizeBehaviour();
1080  }
1081  minX = lower;
1082  maxX = upper;
1083  if (nx > upper)
1085  if (nx < lower)
1087  return resizeBehaviour();
1088  }
1089 
1090  int resizeBehaviour() const
1091  {
1092  int val = maxX;
1093  if (maxX == minX)
1094  val = FIXED_SIZE;
1095  return val;
1096  }
1097 
1098  void copy(const GA1DArrayGenome<T> &orig, unsigned int r, unsigned int x, unsigned int l)
1099  {
1100  if (l > 0 && x < orig.nx && r < nx)
1101  {
1102  if (x + l > orig.nx)
1103  l = orig.nx - x;
1104  if (r + l > nx)
1105  l = nx - r;
1106  GAArray<T>::copy(orig, r, x, l);
1107  }
1108  _evaluated = false;
1109  }
1110  void swap(unsigned int i, unsigned int j)
1111  {
1112  GAArray<T>::swap(i, j);
1113  _evaluated = false;
1114  }
1115 
1116  protected:
1117  unsigned int nx; // how long is the data string?
1118  unsigned int minX; // what is the lower limit?
1119  unsigned int maxX; // what is the upper limit?
1120 
1121  private:
1122  GA1DArrayGenome() : GAArray<T>(0) {}
1123  // This function determines whether or not an indexed position is a hole
1124  // that
1125  // we can substitute into. It does a linear search to find the holes (yuk).
1126  static int GA1DArrayIsHole(const GA1DArrayGenome<T> &c,
1127  const GA1DArrayGenome<T> &dad, int index, int a,
1128  int b)
1129  {
1130  for (int i = a; i < b; i++)
1131  if (c.gene(index) == dad.gene(i))
1132  return 1;
1133  return 0;
1134  }
1135 };
1136 
1137 /* ----------------------------------------------------------------------------
1138 1DArrayAlleleGenome
1139 -------------------------------------------------------------------------------
1140  We don't do any error checking on the assignment to const array of type T, so
1141 the array may contain elements that are not in the allele set.
1142  When we clone, we link the new allele set to our own so that we don't make
1143 unnecessary copies. If someone sets a new allele set on the genome, then we
1144 make a complete new copy of the new one and break any link to a previous one.
1145  It is OK to resize these genomes, so we don't have to protect the resize.
1146  If this is an order-based genome then resizing should be done when the allele
1147 set is changed, but there is nothing implicit in the object that tells us that
1148 this is an order-based genome, so that's up to the user to take care of. If
1149 you're really concerned about catching this type of error, derive a class from
1150 this class that does order-based protection.
1151  I have defined all of the genome virtual functions here to make it easier to
1152 do specializations (you can specialize this class instead if its superclass).
1153  We define our own resize so that we can set to allele values on resize to a
1154 bigger length.
1155 ---------------------------------------------------------------------------- */
1156 /* ----------------------------------------------------------------------------
1157 1DArrayAlleleGenome
1158 
1159  These genomes contain an allele set. When we create a new genome, it owns
1160 its own, independent allele set. If we clone a new genome, the new one gets a
1161 link to our allele set (so we don't end up with zillions of allele sets). Same
1162 is true for the copy constructor.
1163  The array may have a single allele set or an array of allele sets, depending
1164 on which creator was called. Either way, the allele set cannot be changed
1165 once the array is created.
1166 ---------------------------------------------------------------------------- */
1167 
1168 template <class T> class GA1DArrayAlleleGenome : public GA1DArrayGenome<T>
1169 {
1170  public:
1171  GADefineIdentity("GA1DArrayAlleleGenome", GAID::ArrayAlleleGenome);
1172 
1173  /* ----------------------------------------------------------------------------
1174  Operator definitions
1175 ---------------------------------------------------------------------------- */
1176  // The random initializer sets the elements of the array based on the
1177  // alleles set. We choose randomly the allele for each element.
1178  static void UniformInitializer(GAGenome &c)
1179  {
1180  GA1DArrayAlleleGenome<T> &child = DYN_CAST(GA1DArrayAlleleGenome<T> &, c);
1181  child.resize(GAGenome::ANY_SIZE); // let chrom resize if it can
1182  for (int i = child.length() - 1; i >= 0; i--)
1183  child.gene(i, child.alleleset(i).allele());
1184  }
1185 
1186  // Random initializer for order-based genome. Loop through the genome
1187  // and assign each element the next allele in the allele set. Once each
1188  // element has been initialized, scramble the contents by swapping elements.
1189  // This assumes that there is only one allele set for the array.
1190  static void OrderedInitializer(GAGenome &c)
1191  {
1192  GA1DArrayAlleleGenome<T> &child = DYN_CAST(GA1DArrayAlleleGenome<T> &, c);
1193  child.resize(GAGenome::ANY_SIZE); // let chrom resize if it can
1194  int length = child.length() - 1;
1195  int n = 0;
1196  for (int i = length; i >= 0; i--)
1197  {
1198  child.gene(i, child.alleleset().allele(n++));
1199  if (n >= child.alleleset().size())
1200  n = 0;
1201  }
1202  for (int i = length; i >= 0; i--)
1203  child.swap(i, GARandomInt(0, length));
1204  }
1205 
1206  // Randomly pick elements in the array then set the element to any of the
1207  // alleles in the allele set for this genome. This will work for any number
1208  // of allele sets for a given array.
1209  static int FlipMutator(GAGenome &c, float pmut)
1210  {
1211  GA1DArrayAlleleGenome<T> &child = DYN_CAST(GA1DArrayAlleleGenome<T> &, c);
1212 
1213  if (pmut <= 0.0)
1214  return (0);
1215 
1216  float nMut = pmut * STA_CAST(float, child.length());
1217  if (nMut < 1.0)
1218  { // we have to do a flip test on each bit
1219  nMut = 0;
1220  for (int i = child.length() - 1; i >= 0; i--)
1221  {
1222  if (GAFlipCoin(pmut))
1223  {
1224  child.gene(i, child.alleleset(i).allele());
1225  nMut++;
1226  }
1227  }
1228  }
1229  else
1230  { // only flip the number of bits we need to flip
1231  for (int n = 0; n < nMut; n++)
1232  {
1233  int i = GARandomInt(0, child.length() - 1);
1234  child.gene(i, child.alleleset(i).allele());
1235  }
1236  }
1237  return (STA_CAST(int, nMut));
1238  }
1239 
1240  public:
1241  GA1DArrayAlleleGenome(unsigned int length, const GAAlleleSet<T> &s,
1242  GAGenome::Evaluator f = nullptr, void *u = nullptr)
1243  : GA1DArrayGenome<T>(length, f, u),
1244  aset(std::vector<GAAlleleSet<T>>(1))
1245  {
1246  aset.at(0) = s;
1247 
1252  }
1253 
1254  GA1DArrayAlleleGenome(const GAAlleleSetArray<T> &sa, GAGenome::Evaluator f = nullptr, void *u = nullptr)
1255  : GA1DArrayGenome<T>(sa.size(), f, u),
1256  aset(std::vector<GAAlleleSet<T>>(sa.size()))
1257  {
1258  for (int i = 0; i < size(); i++)
1259  aset.at(i) = sa.set(i);
1260 
1261  this->initializer(
1266  }
1267 
1268  // The copy constructor creates a new genome whose allele set refers to the
1269  // original's allele set.
1271  : GA1DArrayGenome<T>(orig.size())
1272  {
1274  }
1275 
1276  GA1DArrayAlleleGenome<T> &operator=(const GAGenome &arr)
1277  {
1278  copy(arr);
1279  return *this;
1280  }
1281  GA1DArrayAlleleGenome<T> &operator=(const T array[]) // no err checks!
1282  {
1284  return *this;
1285  }
1286 
1287  // Delete the allele set
1288  ~GA1DArrayAlleleGenome() override { delete[] aset; }
1289 
1290  // This implementation of clone does not make use of the contents/attributes
1291  // capability because this whole interface isn't quite right yet... Just
1292  // clone the entire thing, contents and all.
1293 
1294  GAGenome *clone(GAGenome::CloneMethod = GAGenome::CloneMethod::CONTENTS) const override
1295  {
1296  return new GA1DArrayAlleleGenome<T>(*this);
1297  }
1298 
1299  void copy(const GAGenome &orig) override
1300  {
1301  if (&orig == this)
1302  return;
1303  const GA1DArrayAlleleGenome<T> *c =
1304  DYN_CAST(const GA1DArrayAlleleGenome<T> *, &orig);
1305  if (c)
1306  {
1308  if (size() != c->size())
1309  {
1310  aset = std::vector<GAAlleleSet<T>>(c->size());
1311  }
1312  for (std::size_t i = 0; i < aset.size(); i++)
1313  {
1314  aset.at(i).link(c->aset.at(i));
1315  }
1316  }
1317  }
1318 
1319  // Define these so they can easily be specialized as needed.
1320  int read(std::istream &is) override { return GA1DArrayGenome<T>::read(is); }
1321 
1322  int write(std::ostream &os) const override
1323  {
1324  return GA1DArrayGenome<T>::write(os);
1325  }
1326 
1327  bool equal(const GAGenome &c) const override
1328  {
1329  return GA1DArrayGenome<T>::equal(c);
1330  }
1331 
1340  int resize(int len) override
1341  {
1342  unsigned int oldx = this->nx;
1344  if (this->nx > oldx)
1345  {
1346  for (unsigned int i = oldx; i < this->nx; i++)
1347  this->a.at(i) = aset.at(i % size()).allele();
1348  }
1349  return len;
1350  }
1351 
1352  const GAAlleleSet<T> &alleleset(unsigned int i = 0) const
1353  {
1354  return aset.at(i % size());
1355  }
1356 
1357  int size() const { return aset.size(); }
1358 
1359  protected:
1361  std::vector<GAAlleleSet<T>> aset;
1362 };
Definition: GA1DArrayGenome.hpp:1169
std::vector< GAAlleleSet< T > > aset
the allele set(s) for this genome
Definition: GA1DArrayGenome.hpp:1361
int resize(int len) override
If we resize to a larger length then we need to set the contents to a valid value (ie one of our alle...
Definition: GA1DArrayGenome.hpp:1340
1 dimensional Array Genome
Definition: GA1DArrayGenome.hpp:42
static int SwapMutator(GAGenome &c, float pmut)
Randomly swap elements in the array.
Definition: GA1DArrayGenome.hpp:52
static float ElementComparator(const GAGenome &a, const GAGenome &b)
How similar are two genomes.
Definition: GA1DArrayGenome.hpp:90
static int UniformCrossover(const GAGenome &p1, const GAGenome &p2, GAGenome *c1, GAGenome *c2)
Randomly take bits from each parent.
Definition: GA1DArrayGenome.hpp:116
Definition: GAAllele.h:404
Definition: GAAllele.h:192
Array Base Class.
Definition: GAArray.h:29
std::vector< T > a
the contents of the array
Definition: GAArray.h:121
The base genome class just defines the genome interface - how to mutate, crossover,...
Definition: GAGenome.h:200
GAMask.
Definition: GAMask.h:15