Modernized GAlib  3.0.0 current
GATreeGenome.hpp
1 // $Header$
2 /* ----------------------------------------------------------------------------
3  tree.h
4  mbwall 25feb95
5  Copyright (c) 1995 Massachusetts Institute of Technology
6  all rights reserved
7 
8  DESCRIPTION:
9  This header defines the interface for the tree genome.
10 ---------------------------------------------------------------------------- */
11 #ifndef _ga_tree_h_
12 #define _ga_tree_h_
13 
14 #include <GAGenome.h>
15 #include <GATree.hpp>
16 #include <garandom.h>
17 
18 extern int _GATreeCompare(GANodeBASE *anode, GANodeBASE *bnode);
19 
20 /* ----------------------------------------------------------------------------
21 TreeGenome
22 -------------------------------------------------------------------------------
23  Beware that the tree genome can grow unbounded - there is no size limit
24 on the tree, so if you have an objective function that encourages size the tree
25 will grow until you run out of memory.
26 ---------------------------------------------------------------------------- */
27 template <class T> class GATreeGenome : public GATree<T>, public GAGenome
28 {
29  public:
30  GADefineIdentity("GATreeGenome", GAID::TreeGenome);
31 
32  // This mutation method is destructive. We randomly pick a node in the
33  // tree
34  // then delete the subtree and node at that point. Each node in the tree
35  // has a pmut probability of getting nuked.
36  // After the mutation the iterator is left at the root of the tree.
37  static int DestructiveMutator(GAGenome &c, float pmut)
38  {
39  GATreeGenome<T> &child = DYN_CAST(GATreeGenome<T> &, c);
40  int n, i;
41  if (pmut <= 0.0)
42  return 0;
43 
44  n = child.size();
45  float nMut = pmut * STA_CAST(float, n);
46  if (nMut < 1.0)
47  { // we have to do a flip test for each node
48  nMut = 0;
49  for (i = 0; i < n; i++)
50  {
51  if (GAFlipCoin(pmut) && child.warp(i))
52  {
53  child.destroy();
54  nMut++;
55  }
56  }
57  }
58  else
59  { // only nuke the number of nodes we need to
60  for (i = 0; i < nMut; i++)
61  {
62  if (child.warp(GARandomInt(0, n - 1)))
63  child.destroy();
64  }
65  }
66  child.root(); // set iterator to root node
67 
68  return (STA_CAST(int, nMut));
69  }
70 
71  // This is a rearranging mutation operator. It randomly picks two nodes in
72  // the tree and swaps them. Any node has a pmut chance of getting swapped,
73  // and the swap could happen to any other node. And in the case of nMut <
74  // 1, the swap may generate a swap partner that is the same node, in which
75  // case no swap occurs (we don't check).
76  // After the mutation the iterator is left at the root of the tree.
77  static int SwapNodeMutator(GAGenome &c, float pmut)
78  {
79  GATreeGenome<T> &child = DYN_CAST(GATreeGenome<T> &, c);
80  int n, i;
81  if (pmut <= 0.0)
82  return 0;
83 
84  n = child.size();
85  float nMut = pmut * STA_CAST(float, n);
86  nMut *= 0.5; // swapping one node swaps another as well
87  if (nMut < 1.0)
88  { // we have to do a flip test for each node
89  nMut = 0;
90  for (i = 0; i < n; i++)
91  {
92  if (GAFlipCoin(pmut))
93  {
94  child.swap(i, GARandomInt(0, n - 1));
95  nMut++;
96  }
97  }
98  }
99  else
100  { // only nuke the number of nodes we need to
101  for (i = 0; i < nMut; i++)
102  child.swap(GARandomInt(0, n - 1), GARandomInt(0, n - 1));
103  }
104  child.root(); // set iterator to root node
105 
106  return (STA_CAST(int, nMut * 2));
107  }
108 
109  // This is a rearranging mutation operator with subtree swap. It does the
110  // same
111  // thing as the rearranging mutator above, but swaps subtrees as well as the
112  // nodes that are selected.
113  // After the mutation the iterator is left at the root of the tree.
114  // We check to make sure that we don't try to swap ancestral nodes. If it
115  // is
116  // an ancestral swap, we give up and don't do anything to the tree. This
117  // could result in mutation rates that are lower than the specified rate!
118  // *** mutation rates are not exact!
119  static int SwapSubtreeMutator(GAGenome &c, float pmut)
120  {
121  GATreeGenome<T> &child = DYN_CAST(GATreeGenome<T> &, c);
122 
123  if (pmut <= 0.0)
124  return 0;
125 
126  int n = child.size();
127  float nMut = pmut * STA_CAST(float, n);
128  nMut *= 0.5; // swapping one node swaps another as well
129  if (nMut < 1.0)
130  { // we have to do a flip test for each node
131  nMut = 0;
132  for (int i = 0; i < n; i++)
133  {
134  if (GAFlipCoin(pmut))
135  {
136  int b = GARandomInt(0, n - 1);
137  if (!child.ancestral(i, b))
138  child.swaptree(i, b);
139  nMut++;
140  }
141  }
142  }
143  else
144  { // only nuke the number of nodes we need to
145  for (int i = 0; i < nMut; i++)
146  {
147  int a = GARandomInt(0, n - 1);
148  int b = GARandomInt(0, n - 1);
149  if (!child.ancestral(a, b))
150  child.swaptree(a, b);
151  }
152  }
153  child.root(); // set iterator to root node
154 
155  return (STA_CAST(int, nMut * 2));
156  }
157 
158  // The default crossover operator takes a node from parent a (with its
159  // entire
160  // sub-tree) and replaces it with a node from parent b (with its entire sub-
161  // tree). If the crossover site is not set, then we pick a random site
162  // based on the trees in the genomes we're going to cross. Once we have a
163  // valid crossover site, we copy the trees from the two genomes.
164  // If the crossover site is out of bounds (ie refers to a node not in the
165  // tree) then we don't do anything to the child.
166  // We allow crossover at ANY site in the genomes (including at the root
167  // node).
168  // *** we should be able to speed this up. there is an extra traversal when
169  // we
170  // do the check to see if the crossover site is valid.
171  static int OnePointCrossover(const GAGenome &p1, const GAGenome &p2,
172  GAGenome *c1, GAGenome *c2)
173  {
174  const GATreeGenome<T> &mom = DYN_CAST(const GATreeGenome<T> &, p1);
175  const GATreeGenome<T> &dad = DYN_CAST(const GATreeGenome<T> &, p2);
176 
177  int nc = 0;
178  unsigned int a = GARandomInt(0, mom.size() - 1);
179  unsigned int b = GARandomInt(0, dad.size() - 1);
180  GATreeIter<T> momiter(mom), daditer(dad);
181  GATree<T> *tree;
182 
183  if (c1 && c2)
184  {
185  GATreeGenome<T> &sis = DYN_CAST(GATreeGenome<T> &, *c1);
186  GATreeGenome<T> &bro = DYN_CAST(GATreeGenome<T> &, *c2);
187 
188  // first do the sister...
189 
190  if (momiter.warp(a) && daditer.warp(b))
191  {
192  sis.GATree<T>::copy(mom);
193  tree = dad.GATree<T>::clone(b);
194  sis.warp(a);
195  sis.swaptree(tree);
196  delete tree;
197  sis.warp(0);
198  }
199 
200  // ...now do the brother.
201 
202  if (momiter.warp(a) && daditer.warp(b))
203  {
204  bro.GATree<T>::copy(dad);
205  tree = mom.GATree<T>::clone(a);
206  bro.warp(b);
207  bro.swaptree(tree);
208  delete tree;
209  bro.warp(0);
210  }
211 
212  nc = 2;
213  }
214  else if (c1)
215  {
216  GATreeGenome<T> &sis = DYN_CAST(GATreeGenome<T> &, *c1);
217 
218  if (GARandomBit())
219  {
220  if (momiter.warp(a) && daditer.warp(b))
221  {
222  sis.GATree<T>::copy(mom);
223  tree = dad.GATree<T>::clone(b);
224  sis.warp(a);
225  sis.swaptree(tree);
226  delete tree;
227  sis.warp(0);
228  }
229  }
230  else
231  {
232  if (momiter.warp(a) && daditer.warp(b))
233  {
234  sis.GATree<T>::copy(dad);
235  tree = mom.GATree<T>::clone(a);
236  sis.warp(b);
237  sis.swaptree(tree);
238  delete tree;
239  sis.warp(0);
240  }
241  }
242 
243  nc = 1;
244  }
245 
246  return nc;
247  }
248 
249  // We use the recursive tree function to compare the tree structures. This
250  // does not compare the contents of the nodes.
251  static float TopologyComparator(const GAGenome &a, const GAGenome &b)
252  {
253  if (&a == &b)
254  return 0;
255  const GATreeGenome<T> &sis = DYN_CAST(const GATreeGenome<T> &, a);
256  const GATreeGenome<T> &bro = DYN_CAST(const GATreeGenome<T> &, b);
257 
258  return STA_CAST(float, _GATreeCompare(sis.rt, bro.rt));
259  }
260 
261  // static float NodeComparator(const GAGenome&, const GAGenome&);
262 
263  public:
264  GATreeGenome(GAGenome::Evaluator f = nullptr, void *u = nullptr)
265  : GATree<T>(), GAGenome(DEFAULT_TREE_INITIALIZER, DEFAULT_TREE_MUTATOR,
266  DEFAULT_TREE_COMPARATOR)
267  {
268  evaluator(f);
269  userData(u);
270  crossover(DEFAULT_TREE_CROSSOVER);
271  }
272 
273  GATreeGenome(const GATreeGenome<T> &orig) : GATree<T>(), GAGenome()
274  {
275  GATreeGenome<T>::copy(orig);
276  }
277 
278  GATreeGenome<T> &operator=(const GAGenome &orig)
279  {
280  copy(orig);
281  return *this;
282  }
283  ~GATreeGenome() override = default;
284 
285  GAGenome *
286  clone(GAGenome::CloneMethod flag = CloneMethod::CONTENTS) const override
287  {
288  auto *cpy = new GATreeGenome<T>();
289  if (flag == CloneMethod::CONTENTS)
290  {
291  cpy->copy(*this);
292  } // cast is for metrowerks...
293  else
294  {
295  cpy->GAGenome::copy(*this);
296  }
297  return cpy;
298  }
299 
300  void copy(const GAGenome &orig) override
301  {
302  if (&orig == this)
303  return;
304  const GATreeGenome<T> *c = DYN_CAST(const GATreeGenome<T> *, &orig);
305  if (c)
306  {
307  GAGenome::copy(*c);
308  GATree<T>::copy(*c);
309  }
310  }
311 
312  // Traverse the tree (breadth-first) and dump the contents as best we can to
313  // the stream. We don't try to write the contents of the nodes - we simply
314  // write a . for each node in the tree.
315  // We allocate space for x,y coord pair for each node in the tree. Then
316  // we
317  // do a depth-first traversal of the tree and assign coords to the nodes in
318  // the order we get them in the traversal. Each coord pair is measured
319  // relative to the parent of the node.
320  void _tt(std::ostream &os, GANode<T> *n)
321  {
322  if (!n)
323  return;
324  GANodeBASE *node = DYN_CAST(GANodeBASE *, n);
325 
326  os.width(10);
327  os << node << " ";
328  os.width(10);
329  os << node->parent << " ";
330  os.width(10);
331  os << node->child << " ";
332  os.width(10);
333  os << node->next << " ";
334  os.width(10);
335  os << node->prev << " ";
336  os.width(10);
337  os << &(n->contents) << "\n";
338  _tt(os, DYN_CAST(GANode<T> *, node->child));
339 
340  for (GANodeBASE *tmp = node->next; tmp && tmp != node; tmp = tmp->next)
341  {
342  os.width(10);
343  os << tmp << " ";
344  os.width(10);
345  os << tmp->parent << " ";
346  os.width(10);
347  os << tmp->child << " ";
348  os.width(10);
349  os << tmp->next << " ";
350  os.width(10);
351  os << tmp->prev << " ";
352  os.width(10);
353  os << &(DYN_CAST(GANode<T> *, tmp)->contents) << "\n";
354  _tt(os, DYN_CAST(GANode<T> *, tmp->child));
355  }
356  }
357 
358  int write(std::ostream &os) const override
359  {
360  os << "node parent child next prev "
361  "contents\n";
362  _tt(os, (GANode<T> *)(this->rt));
363  return 0;
364  }
365 
366  bool equal(const GAGenome &c) const override
367  {
368  if (this == &c)
369  return true;
370  const GATreeGenome<T> &b = DYN_CAST(const GATreeGenome<T> &, c);
371  return _GATreeCompare(this->rt, b.rt) ? false : true;
372  }
373 
374  // Here we do inlined versions of the access members of the super class. We
375  // do our own here so that we can set/unset the _evaluated flag
376  // appropriately.
377 
378  int destroy()
379  {
380  _evaluated = false;
381  return GATree<T>::destroy();
382  }
383  int swaptree(GATree<T> *t)
384  {
385  _evaluated = false;
386  return GATree<T>::swaptree(t);
387  }
388  int swaptree(unsigned int i, unsigned int j)
389  {
390  _evaluated = false;
391  return GATree<T>::swaptree(i, j);
392  }
393  int swap(unsigned int i, unsigned int j)
394  {
395  _evaluated = false;
396  return GATree<T>::swap(i, j);
397  }
398  GATree<T> *remove()
399  {
400  _evaluated = false;
401  return GATree<T>::remove();
402  }
403  int insert(GATree<T> *t, GATreeBASE::Location where = GATreeBASE::BELOW)
404  {
405  _evaluated = false;
406  return GATree<T>::insert(t, where);
407  }
408  int insert(const T &t, GATreeBASE::Location where = GATreeBASE::BELOW)
409  {
410  _evaluated = false;
411  return GATree<T>::insert(t, where);
412  }
413 };
414 
415 #endif
The base genome class just defines the genome interface - how to mutate, crossover,...
Definition: GAGenome.h:200
Definition: GATreeGenome.hpp:28
Definition: GATree.hpp:474
Definition: GATree.hpp:163
This is the basic node object.
Definition: GANode.h:18
Definition: GANode.h:79