001: /*
002: * This file is part of JGAP.
003: *
004: * JGAP offers a dual license model containing the LGPL as well as the MPL.
005: *
006: * For licensing information please see the file license.txt included with JGAP
007: * or have a look at the top of class org.jgap.Chromosome which representatively
008: * includes the JGAP license policy applicable for any file delivered with JGAP.
009: */
010: package org.jgap.impl;
011:
012: import java.util.*;
013: import org.jgap.*;
014: import gnu.trove.*;
015:
016: /**
017: * ATTENTION: This class is preliminary and subject of future adaptations! Use
018: * with care or wait for a more mature version we are working on.
019: * <p>
020: * Creates a gene instance in which individual alleles have both a label (key)
021: * and a value with a distinct meaning. For example, IntegerGene only allows
022: * for values having a continuous range, and does not have a function where it
023: * is possible to specify setValue...
024: *
025: * @author Johnathan Kool (RSMAS, University of Miami)
026: * @since 2.4
027: */
028: public class SetGene extends BaseGene implements
029: IPersistentRepresentation {
030: /** String containing the CVS revision. Read out via reflection!*/
031: private final static String CVS_REVISION = "$Revision: 1.18 $";
032:
033: private THashSet m_geneSet = new THashSet();
034:
035: private Object m_value;
036:
037: /**
038: * Default constructor.<p>
039: * Attention: The configuration used is the one set with the static method
040: * Genotype.setConfiguration.
041: *
042: * @throws InvalidConfigurationException
043: */
044: public SetGene() throws InvalidConfigurationException {
045: this (Genotype.getStaticConfiguration());
046: }
047:
048: /**
049: * @param a_conf the configuration to use
050: *
051: * @throws InvalidConfigurationException
052: *
053: * @author Klaus Meffert
054: * @since 3.0
055: */
056: public SetGene(final Configuration a_conf)
057: throws InvalidConfigurationException {
058: super (a_conf);
059: }
060:
061: protected Gene newGeneInternal() {
062: try {
063: return new SetGene(getConfiguration());
064: } catch (InvalidConfigurationException iex) {
065: throw new IllegalStateException(iex.getMessage());
066: }
067: }
068:
069: /**
070: * Adds a potential allele value to the collection.
071: *
072: * @param a_value the Integer value to be added
073: */
074: public void addAllele(final Object a_value) {
075: m_geneSet.add(a_value);
076: }
077:
078: /**
079: * Add a set of potential allele values to the collection
080: *
081: * @param a_alleles the set of alleles to be added
082: */
083: public void addAlleles(final Collection a_alleles) {
084: m_geneSet.addAll(a_alleles);
085: }
086:
087: /**
088: * Removes a potential allele or set of alleles from the collection.
089: *
090: * @param a_key the unique value(s) of the object(s) to be removed
091: */
092: public void removeAlleles(final Object a_key) {
093: m_geneSet.remove(a_key);
094: }
095:
096: /**
097: * Sets the allele value to be a random value using a defined random number
098: * generator.
099: *
100: * @author Johnathan Kool
101: *
102: * @param a_numberGenerator RandomGenerator
103: */
104: public void setToRandomValue(final RandomGenerator a_numberGenerator) {
105: m_value = m_geneSet.toArray()[a_numberGenerator
106: .nextInt(m_geneSet.size())];
107: }
108:
109: /**
110: * See interface Gene for description of applyMutation.
111: *
112: * For this kind of gene, providing an index and a magnitude have no
113: * significance because the individual allele forms are independent
114: * of one another. In mutating, they can only cange from one form to
115: * another. It may be possible to weight the likelihood of mutation
116: * to different forms, but that will not be implemented here.
117: *
118: * @param a_index ignored here
119: * @param a_percentage ignored here
120: *
121: * @author Klaus Meffert
122: * @author Johnathan Kool
123: * @since 2.4
124: */
125: public void applyMutation(final int a_index,
126: final double a_percentage) {
127: RandomGenerator rn;
128: if (getConfiguration() != null) {
129: rn = getConfiguration().getRandomGenerator();
130: } else {
131: rn = getConfiguration().getJGAPFactory()
132: .createRandomGenerator();
133: }
134: setToRandomValue(rn);
135: }
136:
137: /**
138: * Sets the value and internal state of this Gene from the string
139: * representation returned by a previous invocation of the
140: * getPersistentRepresentation() method. This is an optional method but,
141: * if not implemented, XML persistence and possibly other features will not
142: * be available. An UnsupportedOperationException should be thrown if no
143: * implementation is provided.
144: *
145: * @param a_representation the string representation retrieved from a
146: * prior call to the getPersistentRepresentation() method
147: * @throws UnsupportedRepresentationException if this Gene implementation
148: * does not support the given string representation
149: *
150: * @author Neil Rostan
151: * @since 1.0
152: */
153: public void setValueFromPersistentRepresentation(
154: String a_representation)
155: throws UnsupportedRepresentationException {
156: if (a_representation != null) {
157: StringTokenizer tokenizer = new StringTokenizer(
158: a_representation, PERSISTENT_FIELD_DELIMITER);
159: // Make sure the representation contains the correct number of
160: // fields. If not, throw an exception.
161: // -----------------------------------------------------------
162: if (tokenizer.countTokens() < 3) {
163: throw new UnsupportedRepresentationException(
164: "The format of the given persistent representation "
165: + "is not recognized: it must contain at least three tokens.");
166: }
167: String valueRepresentation = tokenizer.nextToken();
168: // First parse and set the representation of the value.
169:
170: // ----------------------------------------------------
171: if (valueRepresentation.equals("null")) {
172: m_value = null;
173: } else {
174: try {
175: m_value = new Integer(Integer
176: .parseInt(valueRepresentation));
177: } catch (NumberFormatException e) {
178: throw new UnsupportedRepresentationException(
179: "The format of the given persistent representation "
180: + "is not recognized: field 1 does not appear to be "
181: + "an integer value.");
182: }
183: }
184: // Parse the potential categories.
185: // -------------------------------
186: Integer allele;
187: while (tokenizer.hasMoreTokens()) {
188: try {
189: allele = new Integer(Integer.parseInt(tokenizer
190: .nextToken()));
191: m_geneSet.add(allele);
192: } catch (NumberFormatException e) {
193: throw new UnsupportedRepresentationException(
194: "The format of the given persistent representation "
195: + "is not recognized: a member of the list of eligible values "
196: + "does not appear to be an integer value.");
197: }
198: }
199: }
200: }
201:
202: /**
203: * Retrieves a string representation of this Gene that includes any
204: * information required to reconstruct it at a later time, such as its
205: * value and internal state. This string will be used to represent this
206: * Gene in XML persistence. This is an optional method but, if not
207: * implemented, XML persistence and possibly other features will not be
208: * available. An UnsupportedOperationException should be thrown if no
209: * implementation is provided.
210: *
211: * @return a string representation of this Gene's current state
212: *
213: * @throws UnsupportedOperationException to indicate that no implementation
214: * is provided for this method
215: *
216: * @author Neil Rostan
217: * @since 1.0
218: */
219: public String getPersistentRepresentation()
220: throws UnsupportedOperationException {
221: // The persistent representation includes the value, lower bound,
222: // and upper bound. Each is separated by a colon.
223: // --------------------------------------------------------------
224: Iterator it = m_geneSet.iterator();
225: StringBuffer strbf = new StringBuffer();
226: while (it.hasNext()) {
227: strbf.append(PERSISTENT_FIELD_DELIMITER);
228: strbf.append(it.next().toString());
229: }
230: return m_value.toString() + strbf.toString();
231: }
232:
233: /**
234: * Sets the value (allele) of this Gene to the new given value. This class
235: * expects the value to be an instance of current type (e.g. Integer).
236: *
237: * @param a_newValue the new value of this Gene instance.
238: *
239: * @author Johnathan Kool
240: */
241: public void setAllele(Object a_newValue) {
242: if (m_geneSet.contains(a_newValue)) {
243: m_value = a_newValue;
244: } else {
245: throw new IllegalArgumentException(
246: "Allele value being set is not an "
247: + "element of the set of permitted"
248: + " values.");
249: }
250: }
251:
252: /**
253: * Compares this NumberGene with the specified object (which must also
254: * be a NumberGene) for order, which is determined by the number
255: * value of this Gene compared to the one provided for comparison.
256: *
257: * @param other the NumberGene to be compared to this NumberGene
258: * @return a negative integer, zero, or a positive integer as this object
259: * is less than, equal to, or greater than the object provided for comparison
260: *
261: * @throws ClassCastException if the specified object's type prevents it
262: * from being compared to this NumberGene
263: *
264: * @author Klaus Meffert
265: * @author Johnathan Kool
266: * @since 2.4
267: */
268: public int compareTo(Object other) {
269: SetGene otherGene = (SetGene) other;
270: // First, if the other gene (or its value) is null, then this is
271: // the greater allele. Otherwise, just use the overridden compareToNative
272: // method to perform the comparison.
273: // ---------------------------------------------------------------
274: if (otherGene == null) {
275: return 1;
276: } else if (otherGene.m_value == null) {
277: // If our value is also null, then we're the same. Otherwise,
278: // this is the greater gene.
279: // ----------------------------------------------------------
280: return m_value == null ? 0 : 1;
281: } else {
282: ICompareToHandler handler = getConfiguration()
283: .getJGAPFactory().getCompareToHandlerFor(m_value,
284: m_value.getClass());
285: if (handler != null) {
286: try {
287: return ((Integer) handler.perform(m_value, null,
288: otherGene.m_value)).intValue();
289: } catch (Exception ex) {
290: throw new Error(ex);
291: }
292: } else {
293: return 0;
294: }
295: }
296: }
297:
298: /**
299: * @return the internal value of the gene
300: * @since 2.4
301: */
302: protected Object getInternalValue() {
303: return m_value;
304: }
305:
306: /**
307: * Modified hashCode() function to return different hashcodes for differently
308: * ordered genes in a chromosome
309: * @return -67 if no allele set, otherwise value return by BaseGene.hashCode()
310: *
311: * @author Klaus Meffert
312: * @since 2.4
313: */
314: public int hashCode() {
315: if (getInternalValue() == null) {
316: return -67;
317: } else {
318: return super.hashCode();
319: }
320: }
321: }
|