KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgap > impl > MapGene


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.impl;
11
12 import java.lang.reflect.*;
13 import java.util.*;
14 import org.jgap.*;
15
16 /**
17  * ATTENTION: This class is preliminary and subject of future adaptations! Use
18  * with care or wait for a more mature version we are working on.
19  * <p>
20  * Creates a gene instance in which individual alleles have both a label (key)
21  * and a value with a distinct meaning. For example, IntegerGene only allows
22  * for values having a continuous range, and does not have a function where it
23  * is possible to specify setValue...
24  * <p>This implementation does not support specifying a range of valid
25  * integer values. Instead it is planned to provide a constraint checker plugin
26  * later on. With this, the current implementation will stay unchanged and can
27  * be as performant as possible without losing flexibility.</p>
28  *
29  * @author Johnathan Kool, Organisation: RSMAS, University of Miami
30  * @author Klaus Meffert (adaptations)
31  * @since 2.4
32  */

33 public class MapGene
34     extends BaseGene implements IPersistentRepresentation{
35   /** String containing the CVS revision. Read out via reflection!*/
36   private final static String JavaDoc CVS_REVISION = "$Revision: 1.21 $";
37
38   /**
39    * Container for valid alleles
40    */

41   private Map m_geneMap;
42
43   /**
44    * Represents the constant range of values supported by integers.
45    */

46   private Object JavaDoc m_value;
47
48   /**
49    * Represents the delimiter that is used to mark the allele map.
50    */

51   final static String JavaDoc ALLELEMAP_BEGIN_DELIMITER = "[";
52
53   final static String JavaDoc ALLELEMAP_END_DELIMITER = "]";
54
55   /**
56    * Default constructor.<p>
57    * Attention: The configuration used is the one set with the static method
58    * Genotype.setConfiguration.
59    * @throws InvalidConfigurationException
60    *
61    * @since 2.4
62    */

63   public MapGene()
64       throws InvalidConfigurationException {
65     this(Genotype.getStaticConfiguration());
66   }
67
68   /**
69    * @param a_config the configuration to use
70    * @throws InvalidConfigurationException
71    *
72    * @author Klaus Meffert
73    * @since 3.0
74    */

75   public MapGene(final Configuration a_config)
76       throws InvalidConfigurationException {
77     super(a_config);
78     m_geneMap = new HashMap();
79   }
80
81   /**
82    * Constructor setting up valid alleles directly.
83    * @param a_config the configuration to use
84    * @param a_alleles the valid alleles of the gene
85    * @throws InvalidConfigurationException
86    *
87    * @author Klaus Meffert
88    * @since 2.4
89    */

90   public MapGene(final Configuration a_config, final Map a_alleles)
91       throws InvalidConfigurationException {
92     super(a_config);
93     m_geneMap = new HashMap();
94     addAlleles(a_alleles);
95   }
96
97   protected Gene newGeneInternal() {
98     try {
99       MapGene result = new MapGene(getConfiguration(), m_geneMap);
100       // get m_value from original
101
Object JavaDoc value = getAllele();
102       result.setAllele(value);
103       return result;
104     }
105     catch (InvalidConfigurationException iex) {
106       throw new IllegalStateException JavaDoc(iex.getMessage());
107     }
108   }
109
110   /**
111    * Adds a potential allele value to the collection.
112    *
113    * @param a_key the key to be added
114    * @param a_value the Integer value to be added
115    * @since 2.4
116    */

117   public void addAllele(final Object JavaDoc a_key, final Object JavaDoc a_value) {
118     m_geneMap.put(a_key, a_value);
119   }
120
121   /**
122    * Adds a potential allele value to the collection.
123    *
124    * @param a_value the value to be added, also used as key
125    *
126    * @author Klaus Meffert
127    * @since 2.4
128    */

129   public void addAllele(final Object JavaDoc a_value) {
130     m_geneMap.put(a_value, a_value);
131   }
132
133   /**
134    * Convenience method for addAllele (Object's that are Integer's)
135    *
136    * @param a_value the int value to be added, also used as key
137    *
138    * @author Klaus Meffert
139    * @since 2.4
140    */

141   public void addAllele(final int a_value) {
142     m_geneMap.put(new Integer JavaDoc(a_value), new Integer JavaDoc(a_value));
143   }
144
145   /**
146    * Add a set of potential allele values to the collection
147    *
148    * @param a_alleles the set of alleles to be added
149    *
150    * @since 2.4
151    */

152   public void addAlleles(final Map a_alleles) {
153     if (a_alleles == null) {
154       throw new IllegalArgumentException JavaDoc("List of alleles may not be null!");
155     }
156     else {
157       m_geneMap.putAll(a_alleles);
158     }
159   }
160
161   /**
162    * Removes a potential allele or set of alleles from the collection.
163    *
164    * @param a_key the unique value(s) of the object(s) to be removed
165    *
166    * @since 2.4
167    */

168   public void removeAlleles(final Object JavaDoc a_key) {
169     m_geneMap.remove(a_key);
170   }
171
172   /**
173    * @return the map of alleles
174    *
175    * @author Klaus Meffert
176    * @since 3.0
177    */

178   public Map getAlleles() {
179     return m_geneMap;
180   }
181
182   /**
183    * Sets the allele value to be a random value using a defined random number
184    * generator. If no valid alleles are defined, any allele is allowed. Then,
185    * a new Integer with random value is set as random value. Override this
186    * method if you want a different behaviour, such as a Double instead of the
187    * Integer type.
188    *
189    * @param a_numberGenerator the random generator to use
190    *
191    * @author Klaus Meffert
192    * @since 2.4
193    */

194   public void setToRandomValue(final RandomGenerator a_numberGenerator) {
195     if (m_geneMap.isEmpty()) {
196       m_value = new Integer JavaDoc(a_numberGenerator.nextInt());
197     }
198     else {
199       m_value = m_geneMap.get(m_geneMap.keySet().toArray()[a_numberGenerator.
200                               nextInt(m_geneMap.size())]);
201     }
202   }
203
204   /**
205    * See interface Gene for description of applyMutation.
206    *
207    * For this kind of gene, providing an index and a percentage of mutation
208    * would have no significance because the individual allele forms are
209    * independent of one another. In mutating, they can only change from one
210    * form to another. It may be possible to weight the likelihood of mutation
211    * to different forms, but that is not implemented currently.
212    *
213    * @param a_index ignored here
214    * @param a_percentage ignored here
215    *
216    * @author Klaus Meffert
217    * @author Johnathan Kool
218    * @since 2.4
219    */

220   public void applyMutation(final int a_index, final double a_percentage) {
221     RandomGenerator rn;
222     rn = getConfiguration().getRandomGenerator();
223     setToRandomValue(rn);
224   }
225
226   /**
227    * Sets the value and internal state of this Gene from the string
228    * representation returned by a previous invocation of the
229    * getPersistentRepresentation() method. This is an optional method but,
230    * if not implemented, XML persistence and possibly other features will not
231    * be available. An UnsupportedOperationException should be thrown if no
232    * implementation is provided.
233    *
234    * @param a_representation the string representation retrieved from a prior
235    * call to the getPersistentRepresentation() method.
236    *
237    * @throws UnsupportedOperationException to indicate that no implementation
238    * is provided for this method
239    * @throws UnsupportedRepresentationException if this Gene implementation
240    * does not support the given string representation.
241    *
242    * @author Neil Rostan
243    * @author Klaus Meffert
244    * @since 2.4
245    */

246   public void setValueFromPersistentRepresentation(final String JavaDoc
247       a_representation)
248       throws UnsupportedRepresentationException {
249     if (a_representation != null) {
250       StringTokenizer tokenizer = new StringTokenizer(a_representation,
251           PERSISTENT_FIELD_DELIMITER);
252       // Make sure the representation contains the correct number of
253
// fields. If not, throw an exception.
254
// -----------------------------------------------------------
255
if (tokenizer.countTokens() != 2) {
256         throw new UnsupportedRepresentationException(
257             "The format of the given persistent representation " +
258             "is not recognized: it must contain two tokens.");
259       }
260       String JavaDoc valueRepresentation = tokenizer.nextToken();
261       // First parse and set the representation of the value.
262
// ----------------------------------------------------
263
if (valueRepresentation.equals("null")) {
264         m_value = null;
265       }
266       else {
267         try {
268           m_value = new Integer JavaDoc(Integer.parseInt(valueRepresentation));
269         }
270         catch (NumberFormatException JavaDoc e) {
271           throw new UnsupportedRepresentationException(
272               "The format of the given persistent representation " +
273               "is not recognized: field 1 does not appear to be " +
274               "an integer value.");
275         }
276       }
277       // Parse gene map.
278
// ---------------
279
String JavaDoc s = tokenizer.nextToken();
280       tokenizer = new StringTokenizer(s, ",");
281       int lastWasOpening = 0;
282       String JavaDoc key = null;
283       String JavaDoc keyClass = null;
284       String JavaDoc valueClass = null;
285       while (tokenizer.hasMoreTokens()) {
286         String JavaDoc element = tokenizer.nextToken(",");
287         if (lastWasOpening == 1) {
288           key = element.substring(0);
289           lastWasOpening = 2;
290         }
291         else if (lastWasOpening == 2) {
292           valueClass = element.substring(0);
293           lastWasOpening = 3;
294         }
295         else if (lastWasOpening == 3) {
296           if (element.endsWith(")")) {
297             element = element.substring(0, element.length() - 1);
298             try {
299               Class JavaDoc keyType = Class.forName(keyClass);
300               Constructor keyC = keyType.getConstructor(new Class JavaDoc[]{String JavaDoc.class});
301               Object JavaDoc keyObject = keyC.newInstance(new Object JavaDoc[]{key});
302
303               Class JavaDoc valueType = Class.forName(valueClass);
304               Constructor valueC = valueType.getConstructor(new Class JavaDoc[]{String JavaDoc.class});
305               Object JavaDoc valueObject = valueC.newInstance(new Object JavaDoc[]{element});
306               addAllele(keyObject, valueObject);
307               lastWasOpening = 0;
308             } catch (Exception JavaDoc cex) {
309               throw new UnsupportedRepresentationException("Invalid class: "
310                   + keyClass);
311             }
312           }
313           else {
314             throw new IllegalStateException JavaDoc("Closing bracket missing");
315           }
316         }
317         else {
318           if (element.startsWith("(")) {
319             keyClass = element.substring(1);
320             lastWasOpening = 1;
321           }
322           else {
323             throw new IllegalStateException JavaDoc("Opening bracket missing");
324           }
325         }
326       }
327       if (lastWasOpening != 0) {
328         throw new IllegalStateException JavaDoc("Elements missing");
329       }
330     }
331   }
332
333   /**
334    * Retrieves a string representation of this Gene that includes any
335    * information required to reconstruct it at a later time, such as its
336    * value and internal state. This string will be used to represent this
337    * Gene in XML persistence. This is an optional method but, if not
338    * implemented, XML persistence and possibly other features will not be
339    * available. An UnsupportedOperationException should be thrown if no
340    * implementation is provided.
341    *
342    * @return string representation of this Gene's current state
343    * @throws UnsupportedOperationException to indicate that no implementation
344    * is provided for this method
345    *
346    * @author Neil Rostan
347    * @author Klaus Meffert
348    * @since 2.4
349    */

350   public String JavaDoc getPersistentRepresentation()
351       throws UnsupportedOperationException JavaDoc {
352     // The persistent representation includes the value and the allele
353
// assignment.
354
// ---------------------------------------------------------------
355
Iterator it = m_geneMap.keySet().iterator();
356     StringBuffer JavaDoc strbf = new StringBuffer JavaDoc();
357     boolean first = true;
358     while (it.hasNext()) {
359       if (!first) {
360         strbf.append(",");
361       }
362       Object JavaDoc key = it.next();
363       Object JavaDoc value = m_geneMap.get(key);
364       strbf.append("(" + key.getClass().getName() + "," + key.toString() + "," +
365                    value.getClass().getName() + "," + value.toString() + ")");
366       first = false;
367     }
368     return m_value.toString() + MapGene.PERSISTENT_FIELD_DELIMITER +
369         strbf.toString();
370   }
371
372   /**
373    * Sets the value (allele) of this Gene to the new given value. This class
374    * expects the value to be an instance of current type (e.g. Integer).
375    *
376    * @param a_newValue the new value of this Gene instance
377    *
378    * @author Johnathan Kool
379    * @since 2.4
380    */

381   public void setAllele(Object JavaDoc a_newValue) {
382     // ignore null value as it should have no effect here (otherwise problematic
383
// in conjunction with newGene)
384
if (a_newValue == null) {
385       return;
386     }
387     if (m_geneMap.keySet().isEmpty()) {
388       m_value = a_newValue;
389     }
390     else if (m_geneMap.keySet().contains(a_newValue)) {
391       m_value = m_geneMap.get(a_newValue);
392     }
393     else {
394       throw new IllegalArgumentException JavaDoc("Allele value being set ("
395                                          + a_newValue
396                                          + ") is not an element of the set of"
397                                          + " permitted values.");
398     }
399   }
400
401   /**
402    * Compares this NumberGene with the specified object (which must also
403    * be a NumberGene) for order, which is determined by the number
404    * value of this Gene compared to the one provided for comparison.
405    *
406    * @param a_other the NumberGene to be compared to this NumberGene
407    * @return a negative integer, zero, or a positive integer as this object
408    * is less than, equal to, or greater than the object provided for comparison
409    *
410    * @throws ClassCastException if the specified object's type prevents it from
411    * being compared to this Gene
412    *
413    * @author Klaus Meffert
414    * @author Johnathan Kool
415    * @since 2.4
416    */

417   public int compareTo(Object JavaDoc a_other) {
418     MapGene otherGene = (MapGene) a_other;
419     // First, if the other gene (or its value) is null, then this is
420
// the greater allele. Otherwise, just use the overridden compareToNative
421
// method to perform the comparison.
422
// ---------------------------------------------------------------
423
if (otherGene == null) {
424       return 1;
425     }
426     else if (otherGene.m_value == null) {
427       // If our value is not null, then we're the greater gene.
428
// ------------------------------------------------------
429
if (m_value != null) {
430         return 1;
431       }
432     }
433     try {
434       int size1 = m_geneMap.size();
435       int size2 = otherGene.m_geneMap.size();
436       if (size1 != size2) {
437         if (size1 < size2) {
438           return -1;
439         }
440         else {
441           return 1;
442         }
443       }
444       else {
445         // Compare geneMap keys and values.
446
Iterator it1 = m_geneMap.keySet().iterator();
447 // Iterator it2 = otherGene.m_geneMap.keySet().iterator();
448
while (it1.hasNext()) {
449           Object JavaDoc key1 = it1.next();
450           if (!otherGene.m_geneMap.keySet().contains(key1)) {
451             Object JavaDoc key2 = otherGene.m_geneMap.keySet().iterator().next();
452             if (Comparable JavaDoc.class.isAssignableFrom(key1.getClass())
453                 && Comparable JavaDoc.class.isAssignableFrom(key2.getClass())) {
454               return ( (Comparable JavaDoc) key1).compareTo(key2);
455             }
456             else {
457               // Arbitrarily return -1
458
return -1;
459             }
460           }
461           Object JavaDoc value1 = m_geneMap.get(key1);
462           Object JavaDoc value2 = otherGene.m_geneMap.get(key1);
463           if (value1 == null && value2 != null) {
464             return -1;
465           }
466           else if (value1 == null && value2 != null) {
467             return -1;
468           }
469           else if (!value1.equals(value2)) {
470             if (value2 == null) {
471               return 1;
472             }
473             else {
474               if (Comparable JavaDoc.class.isAssignableFrom(value1.getClass())
475                   && Comparable JavaDoc.class.isAssignableFrom(value2.getClass())) {
476                 return ( (Comparable JavaDoc) value1).compareTo(value2);
477               }
478               else {
479                 // Arbitrarily return -1
480
return -1;
481               }
482             }
483           }
484         }
485       }
486       if (m_value == null) {
487         if (otherGene.m_value != null) {
488           return 1;
489         }
490         else {
491           return 0;
492         }
493       }
494       Method method = m_value.getClass().getMethod("compareTo",
495           new Class JavaDoc[] {otherGene.m_value.getClass()});
496       Integer JavaDoc i = (Integer JavaDoc) method.invoke(m_value,
497                                           new Object JavaDoc[] {otherGene.m_value});
498       return i.intValue();
499     }
500     catch (InvocationTargetException ex) {
501       ex.printStackTrace();
502       throw new IllegalArgumentException JavaDoc("CompareTo method of the Gene value" +
503                                          " object cannot be invoked.");
504     }
505     catch (IllegalArgumentException JavaDoc ex) {
506       ex.printStackTrace();
507       throw new IllegalArgumentException JavaDoc("The value object of the Gene does" +
508                                          " not have a compareTo method. It" +
509                                          " cannot be compared.");
510     }
511     catch (IllegalAccessException JavaDoc ex) {
512       ex.printStackTrace();
513       throw new IllegalArgumentException JavaDoc("The compareTo method of the Gene" +
514                                          " value object cannot be accessed ");
515     }
516     catch (SecurityException JavaDoc ex) {
517       ex.printStackTrace();
518       throw new IllegalArgumentException JavaDoc("The compareTo method of the Gene" +
519                                          " value object cannot be accessed." +
520                                          " Insufficient permission levels.");
521     }
522     catch (NoSuchMethodException JavaDoc ex) {
523       ex.printStackTrace();
524       throw new IllegalArgumentException JavaDoc("The value object of the Gene does" +
525                                          " not have a compareTo method. It" +
526                                          " cannot be compared.");
527     }
528   }
529
530   /**
531    * @return the internal value of the gene
532    * @since 2.4
533    */

534   protected Object JavaDoc getInternalValue() {
535     return m_value;
536   }
537
538   /**
539    * Modified hashCode() function to return different hashcodes for differently
540    * ordered genes in a chromosome
541    * @return -1 if no allele set, otherwise value return by BaseGene.hashCode()
542    *
543    * @author Klaus Meffert
544    * @since 2.4
545    */

546   public int hashCode() {
547     if (getInternalValue() == null) {
548       return -71;
549     }
550     else {
551       return super.hashCode();
552     }
553   }
554
555   /**
556    * Retrieves a string representation of this Gene's value that may be useful
557    * for display purposes.
558    *
559    * @return a string representation of this Gene's value
560    *
561    * @author Klaus Meffert
562    * @since 2.4
563    */

564   public String JavaDoc toString() {
565     String JavaDoc result = "[";
566     if (m_geneMap.size() < 1) {
567       result += "null";
568     }
569     else {
570       Set keys = m_geneMap.keySet();
571       Iterator keyIterator = keys.iterator();
572       boolean firstTime = true;
573       while (keyIterator.hasNext()) {
574         if (!firstTime) {
575           result += ",";
576         }
577         else {
578           firstTime = false;
579         }
580         Object JavaDoc key = keyIterator.next();
581         String JavaDoc keyString;
582         if (key == null) {
583           keyString = "null";
584         }
585         else {
586           keyString = key.toString();
587         }
588         result += "(" + keyString + ",";
589         Object JavaDoc value = m_geneMap.get(key);
590         String JavaDoc valueString;
591         if (value == null) {
592           valueString = "null";
593         }
594         else {
595           valueString = value.toString();
596         }
597         result += valueString + ")";
598       }
599     }
600     result += "]";
601     return result;
602   }
603 }
604
Popular Tags