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;
011:
012: import java.io.*;
013: import java.lang.reflect.*;
014: import java.util.*;
015:
016: import org.jgap.util.*;
017:
018: /**
019: * Base class for any implementation of interface IChromosome.
020: *
021: * @author Klaus Meffert
022: * @since 3.0
023: */
024: public abstract class BaseChromosome implements IChromosome,
025: IInitializer, IPersistentRepresentation, IBusinessKey {
026: /** String containing the CVS revision. Read out via reflection!*/
027: private final static String CVS_REVISION = "$Revision: 1.11 $";
028:
029: /**
030: * This field separates gene class name from the gene persistent representation
031: * string. '*' does not work properly with URLEncoder!
032: */
033: public final static String GENE_DELIMITER = "#";
034:
035: /**
036: * Represents the heading delimiter that is used to separate genes in the
037: * persistent representation of Chromosome instances.
038: */
039: public final static String GENE_DELIMITER_HEADING = "<";
040:
041: /**
042: * Represents the closing delimiter that is used to separate genes in the
043: * persistent representation of Chromosome instances.
044: */
045: public final static String GENE_DELIMITER_CLOSING = ">";
046:
047: /**
048: * Separates chromosome-related information.
049: */
050: public final static String CHROM_DELIMITER = "#";
051:
052: /**
053: * The configuration object to use
054: */
055: private Configuration m_configuration;
056:
057: /**
058: * The array of Genes contained in this Chromosome.
059: */
060: private Gene[] m_genes;
061:
062: private int m_age;
063:
064: private int m_operatedOn;
065:
066: /**
067: * The only constructor in this class. Sets the immutable configuration.
068: *
069: * @param a_configuration the configuration to set
070: * @throws InvalidConfigurationException if configuration is null
071: *
072: * @author Klaus Meffert
073: * @since 3.0
074: */
075: public BaseChromosome(Configuration a_configuration)
076: throws InvalidConfigurationException {
077: if (a_configuration == null) {
078: throw new InvalidConfigurationException(
079: "Configuration to be set must not" + " be null!");
080: }
081: m_configuration = a_configuration;
082: }
083:
084: /**
085: * @return the configuration used
086: *
087: * @author Klaus Meffert
088: * @since 3.0
089: */
090: public Configuration getConfiguration() {
091: return m_configuration;
092: }
093:
094: /**
095: * Creates and returns a copy of this object.
096: *
097: * @return a clone of this instance
098: * @throws IllegalStateException instead of CloneNotSupportedException
099: *
100: * @author Klaus Meffert
101: * @since 3.0
102: */
103: public abstract Object clone();
104:
105: /**
106: * Increases the number of evolutionary rounds of chromosome in which it has
107: * not been changed by one.
108: *
109: * @author Klaus Meffert
110: * @since 3.2
111: */
112: public void increaseAge() {
113: m_age++;
114: }
115:
116: /**
117: * Reset age of chromosome because it has been changed.
118: *
119: * @author Klaus Meffert
120: * @since 3.2
121: */
122: public void resetAge() {
123: m_age = 0;
124: }
125:
126: /**
127: * @return 0: Chromosome newly created in this generation. This means it
128: * does not need being crossed over with another newly created one
129: *
130: * @author Klaus Meffert
131: * @since 3.2
132: */
133: public int getAge() {
134: return m_age;
135: }
136:
137: /**
138: * Increase information of number of genetic operations performed on
139: * chromosome in current evolution round.
140: *
141: * @author Klaus Meffert
142: * @since 3.2
143: */
144: public void increaseOperatedOn() {
145: m_operatedOn++;
146: }
147:
148: /**
149: * Resets the information of how many genetic operators have been performed
150: * on the chromosome in the current round of evolution.
151: *
152: * @author Klaus Meffert
153: * @since 3.2
154: *
155: */
156: public void resetOperatedOn() {
157: m_operatedOn = 0;
158: }
159:
160: /**
161: * @return number of genetic operations performed on chromosome in current
162: * evolution round
163: *
164: * @author Klaus Meffert
165: * @since 3.2
166: */
167: public int operatedOn() {
168: return m_operatedOn;
169: }
170:
171: /**
172: * Retrieves the set of genes that make up this Chromosome. This method
173: * exists primarily for the benefit of GeneticOperators that require the
174: * ability to manipulate Chromosomes at a low level.
175: *
176: * @return an array of the Genes contained within this Chromosome
177: *
178: * @author Neil Rotstan
179: * @since 1.0
180: */
181: public synchronized Gene[] getGenes() {
182: return m_genes;
183: }
184:
185: /**
186: * Sets the genes for the chromosome.
187: * @param a_genes the genes to set for the chromosome
188: *
189: * @throws InvalidConfigurationException in case constraint checker is
190: * provided
191: *
192: * @author Klaus Meffert
193: * @since 3.2 (previously in class Chromosome)
194: */
195: public void setGenes(Gene[] a_genes)
196: throws InvalidConfigurationException {
197: m_genes = a_genes;
198: }
199:
200: /**
201: * Returns the Gene at the given index (locus) within the Chromosome. The
202: * first gene is at index zero and the last gene is at the index equal to
203: * the size of this Chromosome - 1.
204: *
205: * @param a_desiredLocus index of the gene value to be returned
206: * @return Gene at the given index
207: *
208: * @author Neil Rotstan
209: * @since 1.0
210: */
211: public synchronized Gene getGene(int a_desiredLocus) {
212: return m_genes[a_desiredLocus];
213: }
214:
215: public void setGene(int a_index, Gene a_gene) {
216: m_genes[a_index] = a_gene;
217: }
218:
219: /**
220: * Returns the size of this Chromosome (the number of genes it contains).
221: * A Chromosome's size is constant and will not change, until setGenes(...)
222: * is used.
223: *
224: * @return number of genes contained within this Chromosome instance
225: *
226: * @author Neil Rotstan
227: * @author Klaus Meffert
228: * @since 1.0
229: */
230: public int size() {
231: if (m_genes == null) {
232: // only possible when using default constructor
233: return 0;
234: } else {
235: return m_genes.length;
236: }
237: }
238:
239: /**
240: * Returns a persistent representation of this chromosome, see interface Gene
241: * for description. Similar to CompositeGene's routine. But does not include
242: * all information of the chromosome (yet).
243: *
244: * @return string representation of this Chromosome's relevant parts of its
245: * current state
246: * @throws UnsupportedOperationException
247: *
248: * @author Klaus Meffert
249: * @since 3.2
250: */
251: public String getPersistentRepresentation() {
252: StringBuffer b = new StringBuffer();
253: // Persist the chromosome's fitness value.
254: // ---------------------------------------
255: b.append(getFitnessValueDirectly());
256: b.append(CHROM_DELIMITER);
257: // Persist the genes.
258: // ------------------
259: b.append(size());
260: b.append(CHROM_DELIMITER);
261: getGenesPersistentRepresentation(b);
262: return b.toString();
263: }
264:
265: public StringBuffer getGenesPersistentRepresentation() {
266: StringBuffer b = new StringBuffer();
267: getGenesPersistentRepresentation(b);
268: return b;
269: }
270:
271: /**
272: * @return business key of the chromosome
273: *
274: * @author Klaus Meffert
275: * @since 3.2
276: */
277: public String getBusinessKey() {
278: return getGenesPersistentRepresentation().toString();
279: }
280:
281: public void getGenesPersistentRepresentation(StringBuffer a_buffer) {
282: Gene gene;
283: int size = size();
284: for (int i = 0; i < size; i++) {
285: gene = getGene(i);
286: a_buffer.append(GENE_DELIMITER_HEADING);
287: a_buffer.append(encode(gene.getClass().getName()
288: + GENE_DELIMITER
289: + gene.getPersistentRepresentation()));
290: a_buffer.append(GENE_DELIMITER_CLOSING);
291: }
292: }
293:
294: protected String encode(String a_string) {
295: return StringKit.encode(a_string);
296: }
297:
298: protected String decode(String a_string)
299: throws UnsupportedEncodingException {
300: return StringKit.decode(a_string);
301: }
302:
303: /**
304: * Counterpart of getPersistentRepresentation.
305: *
306: * @param a_representation the string representation retrieved from a prior
307: * call to the getPersistentRepresentation() method
308: *
309: * @throws UnsupportedRepresentationException
310: *
311: * @author Klaus Meffert
312: * @since 3.2
313: */
314: public void setValueFromPersistentRepresentation(
315: String a_representation)
316: throws UnsupportedRepresentationException {
317: if (a_representation != null) {
318: try {
319: List r = split(a_representation);
320: String g;
321: // Obtain fitness value.
322: // ---------------------
323: g = decode((String) r.get(0));
324: setFitnessValue(Double.parseDouble(g));
325: r.remove(0);
326: /**@todo we can do this faster!*/
327: // Obtain number of genes.
328: // -----------------------
329: g = decode((String) r.get(0));
330: int count = Integer.parseInt(g);
331: setGenes(new Gene[count]);
332: r.remove(0);
333: /**@todo we can do this faster!*/
334: // Obtain the genes.
335: // -----------------
336: Iterator iter = r.iterator();
337: StringTokenizer st;
338: String clas;
339: String representation;
340: Gene gene;
341: int index = 0;
342: while (iter.hasNext()) {
343: g = decode((String) iter.next());
344: st = new StringTokenizer(g, GENE_DELIMITER);
345: if (st.countTokens() != 2)
346: throw new UnsupportedRepresentationException(
347: "In "
348: + g
349: + ", "
350: + "expecting two tokens, separated by "
351: + GENE_DELIMITER);
352: clas = st.nextToken();
353: representation = st.nextToken();
354: gene = createGene(clas, representation);
355: setGene(index++, gene);
356: }
357: } catch (Exception ex) {
358: throw new UnsupportedRepresentationException(ex
359: .toString());
360: }
361: }
362: }
363:
364: /**
365: * Creates a new Gene instance.<p>
366: * Taken from CompositeGene.
367: *
368: * @param a_geneClassName name of the gene class
369: * @param a_persistentRepresentation persistent representation of the gene to
370: * create (could be obtained via getPersistentRepresentation)
371: *
372: * @return newly created gene
373: * @throws Exception
374: *
375: * @author Klaus Meffert
376: * @since 3.2
377: */
378: protected Gene createGene(String a_geneClassName,
379: String a_persistentRepresentation) throws Exception {
380: Class geneClass = Class.forName(a_geneClassName);
381: Constructor constr = geneClass
382: .getConstructor(new Class[] { Configuration.class });
383: Gene gene = (Gene) constr
384: .newInstance(new Object[] { getConfiguration() });
385: gene
386: .setValueFromPersistentRepresentation(a_persistentRepresentation);
387: return gene;
388: }
389:
390: /**
391: * Splits the input a_string into individual gene representations.<p>
392: * Taken and adapted from CompositeGene.
393: *
394: * @param a_string the string to split
395: * @return the elements of the returned array are the persistent
396: * representation strings of the chromosome's components
397: * @throws UnsupportedRepresentationException
398: *
399: * @author Klaus Meffert
400: * @since 3.2
401: */
402: protected static final List split(String a_string)
403: throws UnsupportedRepresentationException {
404: List a = Collections.synchronizedList(new ArrayList());
405: // Header data.
406: // ------------
407: int index = 0;
408: StringTokenizer st0 = new StringTokenizer(a_string,
409: CHROM_DELIMITER, false);
410: if (!st0.hasMoreTokens()) {
411: throw new UnsupportedRepresentationException(
412: "Fitness value expected!");
413: }
414: String fitnessS = st0.nextToken();
415: a.add(fitnessS);
416: index += fitnessS.length();
417: if (!st0.hasMoreTokens()) {
418: throw new UnsupportedRepresentationException(
419: "Number of genes expected!");
420: }
421: String numGenes = st0.nextToken();
422: a.add(numGenes);
423: index += numGenes.length();
424:
425: index += 2; //2 one-character delimiters
426:
427: if (!st0.hasMoreTokens()) {
428: throw new UnsupportedRepresentationException(
429: "Gene data missing!");
430: }
431:
432: // Remove previously parsed content.
433: // ---------------------------------
434: a_string = a_string.substring(index);
435:
436: // Gene data.
437: // ----------
438: StringTokenizer st = new StringTokenizer(a_string,
439: GENE_DELIMITER_HEADING + GENE_DELIMITER_CLOSING, true);
440: while (st.hasMoreTokens()) {
441: if (!st.nextToken().equals(GENE_DELIMITER_HEADING)) {
442: throw new UnsupportedRepresentationException(a_string
443: + " no open tag");
444: }
445: String n = st.nextToken();
446: if (n.equals(GENE_DELIMITER_CLOSING)) {
447: a.add(""); /* Empty token */
448: } else {
449: a.add(n);
450: if (!st.nextToken().equals(GENE_DELIMITER_CLOSING)) {
451: throw new UnsupportedRepresentationException(
452: a_string + " no close tag");
453: }
454: }
455: }
456: return a;
457: }
458:
459: }
|