KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgap > gp > impl > ProgramChromosome


1 /*
2  * This file is part of JGAP.
3  *
4  * JGAP offers a dual license model containing the LGPL as well as the MPL.
5  *
6  * For licencing information please see the file license.txt included with JGAP
7  * or have a look at the top of class org.jgap.Chromosome which representatively
8  * includes the JGAP license policy applicable for any file delivered with JGAP.
9  */

10 package org.jgap.gp.impl;
11
12 import java.util.*;
13 import org.jgap.*;
14 import org.jgap.util.*;
15 import org.jgap.gp.terminal.*;
16 import org.jgap.gp.*;
17
18 /**
19  * Chromosome representing a single GP Program.
20  *
21  * @author Klaus Meffert
22  * @since 3.0
23  */

24 public class ProgramChromosome
25     extends BaseGPChromosome implements IGPChromosome, Comparable JavaDoc, Cloneable JavaDoc {
26   /** String containing the CVS revision. Read out via reflection!*/
27   private final static String JavaDoc CVS_REVISION = "$Revision: 1.16 $";
28
29   /**
30    * The list of allowed functions/terminals.
31    */

32   private transient CommandGene[] m_functionSet;
33
34   /**
35    * Array to hold the depths of each node.
36    */

37   private int[] m_depth;
38
39   /**
40    * Array to hold the types of the arguments to this Chromosome.
41    */

42   private Class JavaDoc[] argTypes;
43
44   private transient int m_index;
45
46   private transient int m_maxDepth;
47
48   /**
49    * The array of genes contained in this chromosome.
50    */

51   private CommandGene[] m_genes;
52
53   /**
54    * Application-specific data that is attached to this Chromosome.
55    * This data may assist the application in evaluating this Chromosome
56    * in the fitness function. JGAP does not operate on the data, aside
57    * from allowing it to be set and retrieved, and considering it with
58    * comparations (if user opted in to do so).
59    */

60   private Object JavaDoc m_applicationData;
61
62   /**
63    * Method compareTo(): Should we also consider the application data when
64    * comparing? Default is "false" as "true" means a Chromosome's losing its
65    * identity when application data is set differently!
66    *
67    * @since 3.0
68    */

69   private boolean m_compareAppData;
70
71   public ProgramChromosome(GPConfiguration a_configuration, int a_size,
72                            IGPProgram a_ind)
73       throws InvalidConfigurationException {
74     super(a_configuration, a_ind);
75     if (a_size <= 0) {
76       throw new IllegalArgumentException JavaDoc(
77           "Chromosome size must be greater than zero");
78     }
79     init(a_size);
80   }
81
82   public ProgramChromosome(GPConfiguration a_configuration, int a_size,
83                            CommandGene[] a_functionSet,
84                            Class JavaDoc[] a_argTypes,
85                            IGPProgram a_ind)
86       throws InvalidConfigurationException {
87     super(a_configuration, a_ind);
88     if (a_size <= 0) {
89       throw new IllegalArgumentException JavaDoc(
90           "Chromosome size must be greater than zero");
91     }
92     m_functionSet = a_functionSet;
93     argTypes = a_argTypes;
94     init(a_size);
95   }
96
97   public ProgramChromosome(GPConfiguration a_configuration,
98                            CommandGene[] a_initialGenes)
99       throws InvalidConfigurationException {
100     super(a_configuration);
101     int i = 0;
102     while (i < a_initialGenes.length && a_initialGenes[i] != null) {
103       i++;
104     }
105     CommandGene[] genes = new CommandGene[i];
106     for (int k = 0; k < i; k++) {
107       genes[k] = a_initialGenes[k];
108     }
109     init(a_initialGenes.length);
110   }
111
112   public ProgramChromosome(final GPConfiguration a_conf)
113       throws InvalidConfigurationException {
114     super(a_conf);
115     init();
116   }
117
118   /**
119    * Default constructor. Only use with dynamic instantiation.
120    *
121    * @throws InvalidConfigurationException
122    *
123    * @author Klaus Meffert
124    * @since 3.0
125    */

126   public ProgramChromosome()
127       throws InvalidConfigurationException {
128     this(GPGenotype.getStaticGPConfiguration());
129   }
130
131   private void init()
132       throws InvalidConfigurationException {
133     init(getGPConfiguration().getPopulationSize());
134   }
135
136   private void init(final int a_size)
137       throws InvalidConfigurationException {
138     m_depth = new int[a_size];
139     m_genes = new CommandGene[a_size];
140         /**@todo speedup possible by using dynamic list?*/
141   }
142
143   public void setArgTypes(Class JavaDoc[] a_argTypes) {
144     argTypes = a_argTypes;
145   }
146
147   public synchronized Object JavaDoc clone() {
148     try {
149       ProgramChromosome chrom = new ProgramChromosome( (GPConfiguration)
150           getGPConfiguration(), (CommandGene[]) m_genes.clone());
151       chrom.argTypes = (Class JavaDoc[]) argTypes.clone();
152       chrom.setFunctionSet( (CommandGene[]) getFunctionSet().clone());
153       chrom.setFunctions( (CommandGene[]) getFunctions().clone());
154       chrom.m_depth = (int[]) m_depth.clone();
155       return chrom;
156     } catch (Exception JavaDoc cex) {
157       // Rethrow to have a more convenient handling.
158
// -------------------------------------------
159
throw new IllegalStateException JavaDoc(cex.getMessage());
160     }
161   }
162
163   /**
164    * Clean up the chromosome.
165    *
166    * @author Klaus Meffert
167    * @since 3.0
168    */

169   public void cleanup() {
170     int len = m_genes.length;
171     for (int i = 0; i < len; i++) {
172       if (m_genes[i] == null) {
173         break;
174       }
175       m_genes[i].cleanup();
176     }
177   }
178
179   /**
180    * Initialize this chromosome using the grow or the full method.
181    *
182    * @param a_num the chromosome's index in the individual of this chromosome
183    * @param a_depth the maximum depth of the chromosome to create
184    * @param a_type the type of the chromosome to create
185    * @param a_argTypes the array of types of arguments for this chromosome
186    * @param a_functionSet the set of nodes valid to pick from
187    * @param a_grow true: use grow method; false: use full method
188    *
189    * @author Klaus Meffert
190    * @since 3.0
191    */

192   public void growOrFull(final int a_num, final int a_depth, final Class JavaDoc a_type,
193                          final Class JavaDoc[] a_argTypes,
194                          final CommandGene[] a_functionSet,
195                          boolean a_grow) {
196     try {
197       argTypes = a_argTypes;
198       setFunctionSet(new CommandGene[a_functionSet.length + a_argTypes.length]);
199       System.arraycopy(a_functionSet, 0, getFunctionSet(), 0,
200                        a_functionSet.length);
201       for (int i = 0; i < a_argTypes.length; i++) {
202         m_functionSet[a_functionSet.length + i]
203             = new Argument(getGPConfiguration(), i, a_argTypes[i]);
204       }
205       /**@todo make init as below dynamic/configurable*/
206       // Initialization of genotype according to specific problem requirements.
207
// ----------------------------------------------------------------------
208
CommandGene n = null;
209 // if (a_num == 0 && false) {
210
// for (int i = 0; i < m_functionSet.length; i++) {
211
// CommandGene m = m_functionSet[i];
212
// if (m.getClass() == SubProgram.class) {
213
// n = m;
214
// break;
215
// }
216
// }
217
// }
218
// else if (a_num == 1 && false) {
219
// for (int i = 0; i < m_functionSet.length; i++) {
220
// CommandGene m = m_functionSet[i];
221
// if (m.getClass() == ForLoop.class) {
222
// n = m;
223
// break;
224
// }
225
// }
226
// }
227
int localDepth = a_depth;
228       m_index = 0;
229       m_maxDepth = localDepth;
230       growOrFullNode(a_num, localDepth, a_type, 0, m_functionSet, n, 0, a_grow,
231                      -1, true);
232       redepth();
233     } catch (InvalidConfigurationException iex) {
234       throw new IllegalStateException JavaDoc(iex.getMessage());
235     }
236   }
237
238   /**
239    * Output program in left-hand notion (e.g.: "+ X Y" for "X + Y")
240    * @param a_startNode node to start with
241    * @return output in left-hand notion
242    *
243    * @author Klaus Meffert
244    * @since 3.0
245    */

246   public String JavaDoc toString(final int a_startNode) {
247     if (a_startNode < 0) {
248       return "";
249     }
250     // Replace any occurance of placeholders (e.g. &1, &2...) in the function's
251
// name.
252
// ------------------------------------------------------------------------
253
String JavaDoc funcName = m_genes[a_startNode].toString();
254     int j = 1;
255     do {
256       String JavaDoc placeHolder = "&" + j;
257       int foundIndex = funcName.indexOf(placeHolder);
258       if (foundIndex < 0) {
259         break;
260       }
261       funcName = funcName.replaceFirst(placeHolder, "");
262       j++;
263     } while (true);
264     // Now remove any leading and trailing spaces.
265
// -------------------------------------------
266
if (j > 0) {
267       funcName = funcName.trim();
268     }
269     IGPProgram ind = getIndividual();
270     if (getFunctions()[a_startNode].getArity(ind) == 0) {
271       return funcName + " ";
272     }
273     String JavaDoc str = "";
274     str += funcName + " ( ";
275     int arity = m_genes[a_startNode].getArity(ind);
276     for (int i = 0; i < arity; i++) {
277       str += toString(getChild(a_startNode, i));
278     }
279     if (a_startNode == 0) {
280       str += ")";
281     }
282     else {
283       str += ") ";
284     }
285     return str;
286   }
287
288   /**
289    * Output program in "natural" notion (e.g.: "X + Y" for "X + Y")
290    * @param a_startNode the node to start with
291    * @return output in normalized notion
292    *
293    * @author Klaus Meffert
294    * @since 3.0
295    */

296   public String JavaDoc toStringNorm(final int a_startNode) {
297     if (a_startNode < 0) {
298       return "";
299     }
300     IGPProgram ind = getIndividual();
301     if (m_genes[a_startNode].getArity(ind) == 0) {
302       return getFunctions()[a_startNode].toString();
303     }
304     String JavaDoc str = "";
305     boolean paramOutput = false;
306     if (m_genes[a_startNode].getArity(ind) > 0) {
307       if (m_genes[a_startNode].toString().indexOf("&1") >= 0) {
308         paramOutput = true;
309       }
310     }
311     if (m_genes[a_startNode].getArity(ind) == 1 || paramOutput) {
312       str += getFunctions()[a_startNode].toString();
313     }
314     if (a_startNode > 0) {
315       str = "(" + str;
316     }
317     for (int i = 0; i < m_genes[a_startNode].getArity(ind); i++) {
318       String JavaDoc childString = toStringNorm(getChild(a_startNode, i));
319       String JavaDoc placeHolder = "&" + (i + 1);
320       int placeholderIndex = str.indexOf(placeHolder);
321       if (placeholderIndex >= 0) {
322         str = str.replaceFirst(placeHolder, childString);
323       }
324       else {
325         str += childString;
326       }
327       if (i == 0 && m_genes[a_startNode].getArity(ind) != 1
328           && !paramOutput) {
329         str += " " + m_genes[a_startNode].toString() + " ";
330       }
331     }
332     if (a_startNode > 0) {
333       str += ")";
334     }
335     return str;
336   }
337
338   /**
339    * Determines whether there exists a function or terminal in the given node
340    * set with the given return and sub return type.
341    *
342    * @param a_returnType the return type to look for
343    * @param a_subReturnType the sub return type to look for
344    * @param a_nodeSet the array of nodes to look through
345    * @param a_function true to look for a function, false to look for a terminal
346    * @param a_growing true: grow mode, false: full mode
347    *
348    * @return true if such a node exists, false otherwise
349    *
350    * @author Klaus Meffert
351    * @since 3.0
352    */

353   public boolean isPossible(Class JavaDoc a_returnType, int a_subReturnType,
354                             CommandGene[] a_nodeSet,
355                             boolean a_function, boolean a_growing) {
356     IGPProgram ind = getIndividual();
357     for (int i = 0; i < a_nodeSet.length; i++) {
358       if (a_nodeSet[i].getReturnType() == a_returnType
359           && (a_subReturnType == 0
360               || a_subReturnType == a_nodeSet[i].getSubReturnType())) {
361         if (a_nodeSet[i].getArity(ind) == 0 && (!a_function || a_growing)) {
362           return true;
363         }
364         if (a_nodeSet[i].getArity(ind) != 0 && a_function) {
365           return true;
366         }
367       }
368     }
369     return false;
370   }
371
372   /**
373    * Randomly chooses a valid node from the functions set.
374    *
375    * @param a_chromIndex index of the chromosome in the individual (0..n-1)
376    * @param a_returnType the return type of node to choose
377    * @param a_subReturnType the sub return type to look for
378    * @param a_functionSet the functions to use
379    * @param a_function true to choose a function, false to choose a terminal
380    * @param a_growing true to ignore the function parameter, false otherwise
381    * @return the node chosen
382    *
383    * @author Klaus Meffert
384    * @since 3.0
385    */

386   protected CommandGene selectNode(int a_chromIndex, Class JavaDoc a_returnType,
387                                    int a_subReturnType,
388                                    CommandGene[] a_functionSet,
389                                    boolean a_function, boolean a_growing) {
390     if (!isPossible(a_returnType, a_subReturnType, a_functionSet, a_function,
391                     a_growing)) {
392       if (a_growing && a_returnType == CommandGene.VoidClass) {
393         // We simply return a NOP, it does nothing :-)
394
// -------------------------------------------
395
try {
396           return new NOP(getGPConfiguration(), a_subReturnType);
397         } catch (InvalidConfigurationException iex) {
398           // Should never happen.
399
// --------------------
400
iex.printStackTrace();
401         }
402       }
403       final String JavaDoc errormsg = "Chromosome (index " + a_chromIndex
404           + ") requires a " +
405           (a_function ?
406            ("function" + (a_growing ? " or terminal" : ""))
407            : "terminal") + " of return type " +
408           a_returnType
409           + " (sub return type " + a_subReturnType + ")"
410           + " but there is no such node available";
411       if (!getGPConfiguration().isStrictProgramCreation()) {
412         throw new IllegalStateException JavaDoc(errormsg);
413       }
414       else {
415         throw new RuntimeException JavaDoc(errormsg);
416       }
417     }
418     CommandGene n = null;
419     int lindex;
420     // Following is analog to isPossible except with the random generator.
421
// -------------------------------------------------------------------
422
IGPProgram ind = getIndividual();
423     UniqueRandomGenerator randGen = new UniqueRandomGenerator(a_functionSet.
424         length, getGPConfiguration().getRandomGenerator());
425     do {
426       lindex = randGen.nextInt();
427       // Consider return type AND sub return type (latter only if != 0).
428
// ---------------------------------------------------------------
429
if (a_functionSet[lindex].getReturnType() == a_returnType
430           && (a_subReturnType == 0
431               || a_functionSet[lindex].getSubReturnType() == a_subReturnType)) {
432         if (a_functionSet[lindex].getArity(ind) == 0 &&
433             (!a_function || a_growing)) {
434           n = a_functionSet[lindex];
435         }
436         if (a_functionSet[lindex].getArity(ind) != 0 && a_function) {
437           n = a_functionSet[lindex];
438         }
439       }
440     } while (n == null);
441     return n;
442   }
443
444   /**
445    * Create a tree of nodes using the grow or the full method.
446    *
447    * @param a_num the chromosome's index in the individual of this chromosome
448    * @param a_depth the maximum depth of the tree to create
449    * @param a_returnType the return type the lastly evaluated node must have
450    * @param a_subReturnType the sub return type to look for
451    * @param a_functionSet the set of function valid to pick from
452    * @param a_rootNode null, or parent node of the node to develop
453    * @param a_recurseLevel 0 for first call
454    * @param a_grow true: use grow method; false: use full method
455    * @param a_childNum index of the child in the parent node to which it belongs
456    * (-1 if node is root node)
457    * @param a_validateNode true: check if node selected is valid
458    *
459    * @author Klaus Meffert
460    * @since 3.0
461    */

462   protected void growOrFullNode(int a_num, int a_depth,
463                                 Class JavaDoc a_returnType,
464                                 int a_subReturnType,
465                                 CommandGene[] a_functionSet,
466                                 CommandGene a_rootNode, int a_recurseLevel,
467                                 boolean a_grow,
468                                 int a_childNum, boolean a_validateNode) {
469     // Only do validate for a program once, namely when the root
470
// node is passed in.
471
// ---------------------------------------------------------
472
if (a_rootNode == null || a_validateNode) {
473       int tries = 0;
474       CommandGene[] localFunctionSet = (CommandGene[])a_functionSet.clone();
475       do {
476         CommandGene node = selectNode(a_num, a_returnType, a_subReturnType,
477                                         localFunctionSet, a_depth >= 1, a_grow);
478         if (!getGPConfiguration().validateNode(this, node, a_rootNode, tries++,
479             a_num, a_recurseLevel, a_returnType, localFunctionSet, a_depth,
480             a_grow, a_childNum)) {
481           // Remove invalid node from local function set.
482
// --------------------------------------------
483
localFunctionSet = remove(localFunctionSet, node);
484           if (localFunctionSet.length == 0) {
485             throw new IllegalStateException JavaDoc("No appropriate function found"
486                 +" during program creation!");
487           }
488           continue;
489         }
490         a_rootNode = node;
491         break;
492       } while (true);
493     }
494     // Generate the node.
495
// ------------------
496
m_depth[m_index] = m_maxDepth - a_depth;
497     if (a_rootNode instanceof ICloneable) {
498       m_genes[m_index++] = (CommandGene) ( (ICloneable) a_rootNode).clone();
499     }
500     else {
501       m_genes[m_index++] = a_rootNode;
502     }
503     if (a_depth >= 1) {
504       IGPProgram ind = getIndividual();
505       for (int i = 0; i < a_rootNode.getArity(ind); i++) {
506         /**@todo ensure required depth is cared about*/
507         if (m_index < m_depth.length) {
508           growOrFullNode(a_num, a_depth - 1,
509                          a_rootNode.getChildType(getIndividual(), i),
510                          a_rootNode.getSubChildType(i),
511                          a_functionSet, a_rootNode, a_recurseLevel + 1, a_grow,i, true);
512         }
513         else {
514           // No valid program could be generated. Abort.
515
// -------------------------------------------
516
throw new IllegalStateException JavaDoc("Randomly created program violates"
517               + " configuration constraints (symptom 1). It may be that you"
518               + " specified a too small number of maxNodes to use!");
519         }
520       }
521     }
522     else {
523       if (a_rootNode.getArity(getIndividual()) > 0) {
524         // No valid program could be generated. Abort.
525
// -------------------------------------------
526
throw new IllegalStateException JavaDoc("Randomly created program violates"
527                                         + " configuration constraints"
528                                         + " (symptom 2)");
529       }
530     }
531   }
532
533   /**
534    * Recalculate the depth of each node.
535    *
536    * @author Klaus Meffert
537    * @since 3.0
538    */

539   public void redepth() {
540     m_depth[0] = 0;
541     redepth(0);
542   }
543
544   /**
545    * Calculate the depth of the next node and the indices of the children
546    * of the current node.
547    * The depth of the next node is just one plus the depth of the current node.
548    * The index of the first child is always the next node. The index of the
549    * second child is found by recursively calling this method on the tree
550    * starting with the first child.
551    *
552    * @param a_index the index of the reference depth
553    * @return the index of the next node of the same depth as the
554    * current node (i.e. the next sibling node)
555    *
556    * @author Klaus Meffert
557    * @since 3.0
558    */

559   protected int redepth(int a_index) {
560     int num = a_index + 1;
561     CommandGene command = getNode(a_index);
562     if (command == null) {
563       throw new IllegalStateException JavaDoc("ProgramChromosome invalid at index "
564                                       + a_index);
565     }
566     IGPProgram ind = getIndividual();
567     int arity = command.getArity(ind);
568     for (int i = 0; i < arity; i++) {
569       if (num < m_depth.length) { //xx
570
m_depth[num] = m_depth[a_index] + 1;
571         // children[i][n] = num;
572
num = redepth(num);
573         if (num < 0) {
574           break;
575         }
576       }
577       else {
578         return -1; //xx
579
}
580     }
581     return num;
582   }
583
584   /**
585    * Gets the a_child'th child of the a_index'th node in this chromosome. This
586    * is the same as the a_child'th node whose depth is one more than the depth
587    * of the a_index'th node.
588    *
589    * @param a_index the node number of the parent
590    * @param a_child the child number (starting from 0) of the parent
591    * @return the node number of the child, or -1 if not found
592    *
593    * @author Klaus Meffert
594    * @since 3.01 (since 3.0 in ProgramChromosome)
595    */

596   public int getChild(int a_index, int a_child) {
597     /**@todo speedup*/
598     int len = getFunctions().length;
599     for (int i = a_index + 1; i < len; i++) {
600       if (m_depth[i] <= m_depth[a_index]) {
601         return -1;
602       }
603       if (m_depth[i] == m_depth[a_index] + 1) {
604         if (--a_child < 0) {
605           return i;
606         }
607       }
608     }
609     throw new RuntimeException JavaDoc("Bad child "
610                                + a_child
611                                + " of node with index = "
612                                + a_index);
613   }
614
615   public CommandGene[] getFunctionSet() {
616     return m_functionSet;
617   }
618
619   public void setFunctionSet(CommandGene[] a_functionSet) {
620     m_functionSet = a_functionSet;
621   }
622
623   public CommandGene[] getFunctions() {
624     return m_genes;
625   }
626
627   public void setFunctions(CommandGene[] a_functions)
628       throws InvalidConfigurationException {
629     m_genes = a_functions;
630   }
631
632   /**
633    * Gets the number of nodes in the branch starting at the a_index'th node.
634    *
635    * @param a_index the index of the node at which to start counting
636    * @return the number of nodes in the branch starting at the a_index'th node
637    *
638    * @author Klaus Meffert
639    * @since 3.0
640    */

641   public int getSize(int a_index) {
642     int i;
643     // Get the node at which the depth is <= depth[n].
644
for (i = a_index + 1; i < m_genes.length && m_genes[i] != null;
645          i++) {
646       if (m_depth[i] <= m_depth[a_index]) {
647         break;
648       }
649     }
650     return i - a_index;
651   }
652
653   /**
654    * Gets the depth of the branch starting at the a_index'th node.
655    *
656    * @param a_index the index of the node at which to check the depth
657    * @return the depth of the branch starting at the a_index'th node
658    *
659    * @author Klaus Meffert
660    * @since 3.0
661    */

662   public int getDepth(int a_index) {
663     int i, maxdepth = m_depth[a_index];
664     for (i = a_index + 1; i < m_genes.length && m_genes[i] != null;
665          i++) {
666       if (m_depth[i] <= m_depth[a_index]) {
667         break;
668       }
669       if (m_depth[i] > maxdepth) {
670         maxdepth = m_depth[i];
671       }
672     }
673     return maxdepth - m_depth[a_index];
674   }
675
676   /**
677    * Gets the node which is the parent of the given node in this chromosome. If
678    * the child is at depth d then the parent is the first function at depth d-1
679    * when iterating backwards through the function list starting from the child.
680    *
681    * @param a_child the child node
682    * @return the parent node, or null if the child is the root node
683    *
684    * @author Klaus Meffert
685    * @since 3.0
686    */

687   public int getParentNode(int a_child) {
688     if (a_child >= m_genes.length || m_genes[a_child] == null) {
689       return -1;
690     }
691     for (int i = a_child - 1; i >= 0; i--) {
692       if (m_depth[i] == m_depth[a_child] - 1) {
693         return i;
694       }
695     }
696     return -1;
697   }
698
699   /**
700    * Executes this node as a boolean.
701    *
702    * @param args the arguments for execution
703    * @return the boolean return value of this node
704    * @throws UnsupportedOperationException if the type of this node is not
705    * boolean
706    *
707    * @author Klaus Meffert
708    * @since 3.0
709    */

710   public boolean execute_boolean(Object JavaDoc[] args) {
711     boolean rtn = m_genes[0].execute_boolean(this, 0, args);
712     cleanup();
713     return rtn;
714   }
715
716   /**
717    * Executes this node as a boolean.
718    *
719    * @param n the index of the parent node
720    * @param child the child number of the node to execute
721    * @param args the arguments for execution
722    * @return the boolean return value of this node
723    * @throws UnsupportedOperationException if the type of this node is not
724    * boolean
725    *
726    * @author Klaus Meffert
727    * @since 3.0
728    */

729   public boolean execute_boolean(int n, int child, Object JavaDoc[] args) {
730     if (child == 0) {
731       return m_genes[n + 1].execute_boolean(this, n + 1, args);
732     }
733     int other = getChild(n, child);
734     return m_genes[other].execute_boolean(this, other, args);
735   }
736
737   /**
738    * Executes this node, returning nothing.
739    *
740    * @param args the arguments for execution
741    * @throws UnsupportedOperationException if the type of this node is not void
742    *
743    * @author Klaus Meffert
744    * @since 3.0
745    */

746   public void execute_void(Object JavaDoc[] args) {
747     m_genes[0].execute_void(this, 0, args);
748     cleanup();
749   }
750
751   public void execute_void(int n, int child, Object JavaDoc[] args) {
752     if (child == 0) {
753       m_genes[n + 1].execute_void(this, n + 1, args);
754     }
755     else {
756       int other = getChild(n, child);
757       m_genes[other].execute_void(this, other, args);
758     }
759   }
760
761   /**
762    * Executes this node as an integer.
763    *
764    * @param args the arguments for execution
765    * @return the integer return value of this node
766    * @throws UnsupportedOperationException if the type of this node is not
767    * integer
768    *
769    * @author Klaus Meffert
770    * @since 3.0
771    */

772   public int execute_int(Object JavaDoc[] args) {
773     int rtn = m_genes[0].execute_int(this, 0, args);
774     cleanup();
775     return rtn;
776   }
777
778   public int execute_int(int n, int child, Object JavaDoc[] args) {
779     if (child == 0) {
780       return m_genes[n + 1].execute_int(this, n + 1, args);
781     }
782     else {
783       int other = getChild(n, child);
784       return m_genes[other].execute_int(this, other, args);
785     }
786   }
787
788   /**
789    * Executes this node as a long.
790    *
791    * @param args the arguments for execution
792    * @return the long return value of this node
793    * @throws UnsupportedOperationException if the type of this node is not long
794    *
795    * @author Klaus Meffert
796    * @since 3.0
797    */

798   public long execute_long(Object JavaDoc[] args) {
799     long rtn = m_genes[0].execute_long(this, 0, args);
800     cleanup();
801     return rtn;
802   }
803
804   public long execute_long(int n, int child, Object JavaDoc[] args) {
805     if (child == 0) {
806       return m_genes[n + 1].execute_long(this, n + 1, args);
807     }
808     int other = getChild(n, child);
809     return m_genes[other].execute_long(this, other, args);
810   }
811
812   /**
813    * Executes this node as a float.
814    *
815    * @param args the arguments for execution
816    * @return the float return value of this node
817    * @throws UnsupportedOperationException if the type of this node is not float
818    *
819    * @author Klaus Meffert
820    * @since 3.0
821    */

822   public float execute_float(Object JavaDoc[] args) {
823     float rtn = m_genes[0].execute_float(this, 0, args);
824     cleanup();
825     return rtn;
826   }
827
828   public float execute_float(int n, int child, Object JavaDoc[] args) {
829     if (child == 0) {
830       return m_genes[n + 1].execute_float(this, n + 1, args);
831     }
832     int other = getChild(n, child);
833     return m_genes[other].execute_float(this, other, args);
834   }
835
836   /**
837    * Executes this node as a double.
838    *
839    * @param args the arguments for execution
840    * @return the double return value of this node
841    * @throws UnsupportedOperationException if this node's type is not double
842    *
843    * @author Klaus Meffert
844    * @since 3.0
845    */

846   public double execute_double(Object JavaDoc[] args) {
847     double rtn = m_genes[0].execute_double(this, 0, args);
848     cleanup();
849     return rtn;
850   }
851
852   public double execute_double(int n, int child, Object JavaDoc[] args) {
853     if (child == 0) {
854       return m_genes[n + 1].execute_double(this, n + 1, args);
855     }
856     int other = getChild(n, child);
857     return m_genes[other].execute_double(this, other, args);
858   }
859
860   /**
861    * Executes this node as an object.
862    *
863    * @param args the arguments for execution
864    * @return the object return value of this node
865    * @throws UnsupportedOperationException if the type of this node is not
866    * of type Object
867    *
868    * @author Klaus Meffert
869    * @since 3.0
870    */

871   public Object JavaDoc execute_object(Object JavaDoc[] args) {
872     Object JavaDoc rtn = m_genes[0].execute_object(this, 0, args);
873     cleanup();
874     return rtn;
875   }
876
877   public Object JavaDoc execute_object(int n, int child, Object JavaDoc[] args) {
878     if (child == 0) {
879       return m_genes[n + 1].execute_object(this, n + 1, args);
880     }
881     int other = getChild(n, child);
882     return m_genes[other].execute_object(this, other, args);
883   }
884
885   /**
886    * Executes this node without knowing its return type.
887    *
888    * @param args the arguments for execution
889    * @return the Object which wraps the return value of this node, or null
890    * if the return type is null or unknown
891    *
892    * @author Klaus Meffert
893    * @since 3.0
894    */

895   public Object JavaDoc execute(Object JavaDoc[] args) {
896     return m_genes[0].execute_object(this, 0, args);
897   }
898
899   public Object JavaDoc execute(int n, int child, Object JavaDoc[] args) {
900     return execute_object(n, child, args);
901   }
902
903   public void setGene(int index, CommandGene a_gene) {
904     if (a_gene == null) {
905       throw new IllegalArgumentException JavaDoc("Gene may not be null!");
906     }
907     m_genes[index] = a_gene;
908   }
909
910   public Class JavaDoc[] getArgTypes() {
911     return argTypes;
912   }
913
914   public int getArity() {
915     return argTypes.length;
916   }
917
918   /**
919    * @return number of functions and terminals present
920    *
921    * @author Klaus Meffert
922    * @since 3.0
923    */

924   public int size() {
925     int i = 0;
926     while (i < m_genes.length && m_genes[i] != null) {
927       i++;
928     }
929     return i;
930   }
931
932   /**
933    * Compares the given chromosome to this chromosome. This chromosome is
934    * considered to be "less than" the given chromosome if it has a fewer
935    * number of genes or if any of its gene values (alleles) are less than
936    * their corresponding gene values in the other chromosome.
937    *
938    * @param a_other the chromosome against which to compare this chromosome
939    * @return a negative number if this chromosome is "less than" the given
940    * chromosome, zero if they are equal to each other, and a positive number if
941    * this chromosome is "greater than" the given chromosome
942    *
943    * @author Klaus Meffert
944    * @since 3.0
945    */

946   public int compareTo(Object JavaDoc a_other) {
947     // First, if the other Chromosome is null, then this chromosome is
948
// automatically the "greater" Chromosome.
949
// ---------------------------------------------------------------
950
if (a_other == null) {
951       return 1;
952     }
953     int size = size();
954     ProgramChromosome otherChromosome = (ProgramChromosome) a_other;
955     CommandGene[] otherGenes = otherChromosome.m_genes;
956     // If the other Chromosome doesn't have the same number of genes,
957
// then whichever has more is the "greater" Chromosome.
958
// --------------------------------------------------------------
959
if (otherChromosome.size() != size) {
960       return size() - otherChromosome.size();
961     }
962     // Next, compare the gene values (alleles) for differences. If
963
// one of the genes is not equal, then we return the result of its
964
// comparison.
965
// ---------------------------------------------------------------
966
for (int i = 0; i < size; i++) {
967       int comparison = m_genes[i].compareTo(otherGenes[i]);
968       if (comparison != 0) {
969         return comparison;
970       }
971     }
972     /**@todo compare m_functionSet*/
973     if (isCompareApplicationData()) {
974       // Compare application data.
975
// -------------------------
976
if (getApplicationData() == null) {
977         if (otherChromosome.getApplicationData() != null) {
978           return -1;
979         }
980       }
981       else if (otherChromosome.getApplicationData() == null) {
982         return 1;
983       }
984       else {
985         if (getApplicationData() instanceof Comparable JavaDoc) {
986           try {
987             return ( (Comparable JavaDoc) getApplicationData()).compareTo(
988                 otherChromosome.getApplicationData());
989           } catch (ClassCastException JavaDoc cex) {
990             return -1;
991           }
992         }
993         else {
994           return getApplicationData().getClass().getName().compareTo(
995               otherChromosome.getApplicationData().getClass().getName());
996         }
997       }
998     }
999     // Everything is equal. Return zero.
1000
// ---------------------------------
1001
return 0;
1002  }
1003
1004  /**
1005   * Compares this chromosome against the specified object.
1006   *
1007   * @param a_other the object to compare against
1008   * @return true: if the objects are the same, false otherwise
1009   *
1010   * @author Klaus Meffert
1011   * @since 3.0
1012   */

1013  public boolean equals(Object JavaDoc a_other) {
1014    try {
1015      return compareTo(a_other) == 0;
1016    } catch (ClassCastException JavaDoc cex) {
1017      return false;
1018    }
1019  }
1020
1021  /**
1022   * Should we also consider the application data when comparing? Default is
1023   * "false" as "true" means a Chromosome is losing its identity when
1024   * application data is set differently!
1025   *
1026   * @param a_doCompare true: consider application data in method compareTo
1027   *
1028   * @author Klaus Meffert
1029   * @since 3.0
1030   */

1031  public void setCompareApplicationData(boolean a_doCompare) {
1032    m_compareAppData = a_doCompare;
1033  }
1034
1035  /*
1036   * @return should we also consider the application data when comparing?
1037   *
1038   * @author Klaus Meffert
1039   * @since 3.0
1040   */

1041  public boolean isCompareApplicationData() {
1042    return m_compareAppData;
1043  }
1044
1045  /**
1046   * Retrieves the application-specific data that is attached to this
1047   * Chromosome. Attaching application-specific data may be useful for
1048   * some applications when it comes time to evaluate this Chromosome
1049   * in the fitness function. JGAP ignores this data functionally.
1050   *
1051   * @return the application-specific data previously attached to this
1052   * Chromosome, or null if there is no data attached
1053   *
1054   * @author Klaus Meffert
1055   * @since 3.0
1056   */

1057  public Object JavaDoc getApplicationData() {
1058    return m_applicationData;
1059  }
1060
1061  /**
1062   * Returns the Gene at the given index (locus) within the Chromosome. The
1063   * first gene is at index zero and the last gene is at the index equal to
1064   * the size of this Chromosome - 1.
1065   *
1066   * @param a_locus index of the gene value to be returned
1067   * @return Gene at the given index
1068   *
1069   * @author Klaus Meffert
1070   * @since 3.0
1071   */

1072  public synchronized CommandGene getGene(int a_locus) {
1073    return m_genes[a_locus];
1074  }
1075
1076  private CommandGene[] remove(CommandGene[] a_functionSet, CommandGene node) {
1077    int size = a_functionSet.length;
1078    for (int i = 0; i < size; i++) {
1079      if (a_functionSet[i] == node) {
1080        // Remove found element
1081
CommandGene[] result = new CommandGene[size-1];
1082        if (i>0) {
1083          System.arraycopy(a_functionSet, 0, result, 0, i);
1084        }
1085        if (size - i > 1) {
1086          System.arraycopy(a_functionSet, i + 1, result, i, size - i-1);
1087        }
1088        return result;
1089      }
1090    }
1091    return a_functionSet;
1092  }
1093}
1094
Popular Tags