KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.*;
13 import org.jgap.*;
14
15 /**
16  * A Gene implementation that supports a double values for its allele.
17  * Upper and lower bounds may optionally be provided to restrict the range
18  * of legal values allowed by this Gene instance.<p>
19  * Partly copied from IntegerGene.
20  *
21  * @author Klaus Meffert
22  * @since 1.1
23  */

24 public class DoubleGene
25     extends NumberGene implements IPersistentRepresentation {
26   /** String containing the CVS revision. Read out via reflection!*/
27   private final static String JavaDoc CVS_REVISION = "$Revision: 1.37 $";
28
29   /**
30    * The upper bounds of values represented by this Gene. If not explicitly
31    * provided by the user, this should be set to Double.MAX_VALUE.
32    */

33   private double m_upperBound;
34
35   /**
36    * The lower bounds of values represented by this Gene. If not explicitly
37    * provided by the user, this should be set to Double.MIN_VALUE
38    */

39   private double m_lowerBound;
40
41   /**
42    * Constructs a new DoubleGene with default settings. No bounds will
43    * be put into effect for values (alleles) of this Gene instance, other
44    * than the standard range of double values.<p>
45    * Attention: The configuration used is the one set with the static method
46    * Genotype.setConfiguration.
47    * @throws InvalidConfigurationException
48    *
49    * @author Neil Rotstan
50    * @author Klaus Meffert
51    * @since 1.1
52    */

53   public DoubleGene()
54       throws InvalidConfigurationException {
55     this(Genotype.getStaticConfiguration());
56   }
57
58   /**
59    * Constructs a new DoubleGene with default settings. No bounds will
60    * be put into effect for values (alleles) of this Gene instance, other
61    * than the standard range of double values.
62    * @param a_config the configuration to use
63    * @throws InvalidConfigurationException
64    *
65    * @author Klaus Meffert
66    * @since 3.0
67    */

68   public DoubleGene(final Configuration a_config)
69       throws InvalidConfigurationException {
70     this(a_config, - (Double.MAX_VALUE / 2),
71          Double.MAX_VALUE / 2);
72   }
73
74   /**
75    * Constructs a new DoubleGene with the specified lower and upper
76    * bounds for values (alleles) of this Gene instance.
77    *
78    * @param a_config the configuration to use
79    * @param a_lowerBound the lowest value that this Gene may possess,
80    * inclusive
81    * @param a_upperBound the highest value that this Gene may possess,
82    * inclusive
83    * @throws InvalidConfigurationException
84    *
85    * @author Klaus Meffert
86    * @since 2.0
87    */

88   public DoubleGene(final Configuration a_config, final double a_lowerBound,
89                     final double a_upperBound)
90       throws InvalidConfigurationException {
91     super(a_config);
92     m_lowerBound = a_lowerBound;
93     m_upperBound = a_upperBound;
94   }
95
96   /**
97    * Provides an implementation-independent means for creating new Gene
98    * instances.
99    *
100    * @return a new Gene instance of the same type and with the same
101    * setup as this concrete Gene
102    *
103    * @author Klaus Meffert
104    * @since 1.1
105    */

106   protected Gene newGeneInternal() {
107     try {
108       DoubleGene result = new DoubleGene(getConfiguration(), m_lowerBound,
109                                          m_upperBound);
110       return result;
111     }
112     catch (InvalidConfigurationException iex) {
113       throw new IllegalStateException JavaDoc(iex.getMessage());
114     }
115   }
116
117   /**
118    * Retrieves a string representation of this Gene that includes any
119    * information required to reconstruct it at a later time, such as its
120    * value and internal state. This string will be used to represent this
121    * Gene in XML persistence. This is an optional method but, if not
122    * implemented, XML persistence and possibly other features will not be
123    * available. An UnsupportedOperationException should be thrown if no
124    * implementation is provided.
125    *
126    * @return a string representation of this Gene's current state.
127    *
128    * @author Klaus Meffert
129    * @since 1.1
130    */

131   public String JavaDoc getPersistentRepresentation() {
132     // The persistent representation includes the value, lower bound,
133
// and upper bound. Each is separated by a colon.
134
// --------------------------------------------------------------
135
String JavaDoc s;
136     if (getInternalValue() == null) {
137       s = "null";
138     }
139     else {
140       s = getInternalValue().toString();
141     }
142     return s + PERSISTENT_FIELD_DELIMITER + m_lowerBound
143         + PERSISTENT_FIELD_DELIMITER + m_upperBound;
144   }
145
146   /**
147    * Sets the value and internal state of this Gene from the string
148    * representation returned by a previous invocation of the
149    * getPersistentRepresentation() method. This is an optional method but,
150    * if not implemented, XML persistence and possibly other features will not
151    * be available. An UnsupportedOperationException should be thrown if no
152    * implementation is provided.
153    *
154    * @param a_representation the string representation retrieved from a
155    * prior call to the getPersistentRepresentation() method
156    *
157    * @throws UnsupportedOperationException to indicate that no implementation
158    * is provided for this method
159    * @throws UnsupportedRepresentationException if this Gene implementation
160    * does not support the given string representation
161    *
162    * @author Klaus Meffert
163    * @since 1.1
164    */

165   public void setValueFromPersistentRepresentation(String JavaDoc a_representation)
166       throws UnsupportedRepresentationException {
167     if (a_representation != null) {
168       StringTokenizer tokenizer =
169           new StringTokenizer(a_representation,
170                               PERSISTENT_FIELD_DELIMITER);
171       // Make sure the representation contains the correct number of
172
// fields. If not, throw an exception.
173
// -----------------------------------------------------------
174
if (tokenizer.countTokens() != 3) {
175         throw new UnsupportedRepresentationException(
176             "The format of the given persistent representation " +
177             "is not recognized: it does not contain three tokens.");
178       }
179       String JavaDoc valueRepresentation = tokenizer.nextToken();
180       String JavaDoc lowerBoundRepresentation = tokenizer.nextToken();
181       String JavaDoc upperBoundRepresentation = tokenizer.nextToken();
182       // First parse and set the representation of the value.
183
// ----------------------------------------------------
184
if (valueRepresentation.equals("null")) {
185         setAllele(null);
186       }
187       else {
188         try {
189           setAllele(new Double JavaDoc(Double.parseDouble(valueRepresentation)));
190         }
191         catch (NumberFormatException JavaDoc e) {
192           throw new UnsupportedRepresentationException(
193               "The format of the given persistent representation " +
194               "is not recognized: field 1 does not appear to be " +
195               "a double value.");
196         }
197       }
198       // Now parse and set the lower bound.
199
// ----------------------------------
200
try {
201         m_lowerBound =
202             Double.parseDouble(lowerBoundRepresentation);
203       }
204       catch (NumberFormatException JavaDoc e) {
205         throw new UnsupportedRepresentationException(
206             "The format of the given persistent representation " +
207             "is not recognized: field 2 does not appear to be " +
208             "a double value.");
209       }
210       // Now parse and set the upper bound.
211
// ----------------------------------
212
try {
213         m_upperBound =
214             Double.parseDouble(upperBoundRepresentation);
215       }
216       catch (NumberFormatException JavaDoc e) {
217         throw new UnsupportedRepresentationException(
218             "The format of the given persistent representation " +
219             "is not recognized: field 3 does not appear to be " +
220             "a double value.");
221       }
222     }
223   }
224
225   /**
226    * Retrieves the double value of this Gene, which may be more convenient in
227    * some cases than the more general getAllele() method.
228    *
229    * @return the double value of this Gene
230    * @since 1.1
231    */

232   public double doubleValue() {
233     return ( (Double JavaDoc) getAllele()).doubleValue();
234   }
235
236   /**
237    * Sets the value (allele) of this Gene to a random Double value between
238    * the lower and upper bounds (if any) of this Gene.
239    *
240    * @param a_numberGenerator the random number generator that should be used
241    * to create any random values. It's important to use this generator to
242    * maintain the user's flexibility to configure the genetic engine to use the
243    * random number generator of their choice
244    *
245    * @author Klaus Meffert
246    * @since 1.1
247    */

248   public void setToRandomValue(RandomGenerator a_numberGenerator) {
249     // maps the randomly determined value to the current bounds.
250
// ---------------------------------------------------------
251
setAllele(new Double JavaDoc( (m_upperBound - m_lowerBound) *
252                          a_numberGenerator.nextDouble() + m_lowerBound));
253   }
254
255   /**
256    * Compares to objects by first casting them into their expected type
257    * (e.g. Integer for IntegerGene) and then calling the compareTo-method
258    * of the casted type.
259    * @param o1 first object to be compared, always is not null
260    * @param o2 second object to be compared, always is not null
261    * @return a negative integer, zero, or a positive integer as this object
262    * is less than, equal to, or greater than the object provided for comparison
263    *
264    * @since 1.1
265    */

266   protected int compareToNative(Object JavaDoc o1, Object JavaDoc o2) {
267     return ( (Double JavaDoc) o1).compareTo( (Double JavaDoc) o2);
268   }
269
270   /**
271    * Maps the value of this DoubleGene to within the bounds specified by
272    * the m_upperBounds and m_lowerBounds instance variables. The value's
273    * relative position within the double range will be preserved within the
274    * bounds range (in other words, if the value is about halfway between the
275    * double max and min, then the resulting value will be about halfway
276    * between the upper bounds and lower bounds). If the value is null or
277    * is already within the bounds, it will be left unchanged.
278    *
279    * @author Neil Rotstan
280    * @author Klaus Meffert
281    * @since 1.1
282    */

283   protected void mapValueToWithinBounds() {
284     if (getAllele() != null) {
285       Double JavaDoc d_value = ( (Double JavaDoc) getAllele());
286       // If the value exceeds either the upper or lower bounds, then
287
// map the value to within the legal range. To do this, we basically
288
// calculate the distance between the value and the double min,
289
// then multiply it with a random number and then care that the lower
290
// boundary is added.
291
// ------------------------------------------------------------------
292
if (d_value.doubleValue() > m_upperBound ||
293           d_value.doubleValue() < m_lowerBound) {
294         RandomGenerator rn;
295         if (getConfiguration() != null) {
296           rn = getConfiguration().getRandomGenerator();
297         }
298         else {
299           rn = new StockRandomGenerator();
300         }
301         setAllele(new Double JavaDoc(rn.nextDouble()
302                              * (m_upperBound - m_lowerBound) + m_lowerBound));
303       }
304     }
305   }
306
307   /**
308    * See interface Gene for description.
309    * @param index ignored (because there is only 1 atomic element)
310    * @param a_percentage percentage of mutation (greater than -1 and smaller
311    * than 1)
312    *
313    * @author Klaus Meffert
314    * @since 1.1
315    */

316   public void applyMutation(int index, double a_percentage) {
317     double range = (m_upperBound - m_lowerBound) * a_percentage;
318     double newValue = doubleValue() + range;
319     setAllele(new Double JavaDoc(newValue));
320   }
321
322   /**
323    * Modified hashCode() function to return different hashcodes for differently
324    * ordered genes in a chromosome.
325    * @return -3 if no allele set, otherwise value return by BaseGene.hashCode()
326    *
327    * @author Klaus Meffert
328    * @since 2.2
329    */

330   public int hashCode() {
331     if (getInternalValue() == null) {
332       return -3;
333     }
334     else {
335       return super.hashCode();
336     }
337   }
338
339   /**
340    * @return string representation of this Gene's value that may be useful for
341    * display purposes
342    *
343    * @author Klaus Meffert
344    * @since 2.4
345    */

346   public String JavaDoc toString() {
347     String JavaDoc s = "DoubleGene(" + m_lowerBound + "," + m_upperBound + ")"
348         + "=";
349     if (getInternalValue() == null) {
350       s += "null";
351     }
352     else {
353       s += getInternalValue().toString();
354     }
355     return s;
356   }
357
358   /**
359    * @return the lower bound set
360    * @author Klaus Meffert
361    * @since 3.0
362    */

363   public double getLowerBound() {
364     return m_lowerBound;
365   }
366
367   /**
368    * @return the upper bound set
369    * @author Klaus Meffert
370    * @since 3.0
371    */

372   public double getUpperBound() {
373     return m_upperBound;
374   }
375 }
376
Popular Tags