/*
 * This file is part of JGAP.
 *
 * JGAP offers a dual license model containing the LGPL as well as the MPL.
 *
 * For licensing information please see the file license.txt included with JGAP
 * or have a look at the top of class org.jgap.Chromosome which representatively
 * includes the JGAP license policy applicable for any file delivered with JGAP.
 */
package org.jgap;

import java.io.*;
import java.lang.reflect.*;
import java.util.*;

import org.jgap.impl.*;
import org.jgap.util.*;

/**
 * Base class for any implementation of interface IChromosome.
 *
 * @author Klaus Meffert
 * @since 3.0
 */
public abstract class BaseChromosome
    implements IChromosome, IInitializer, IPersistentRepresentation, IBusinessKey {
  /** String containing the CVS revision. Read out via reflection!*/
  private final static String CVS_REVISION = "$Revision: 1.15 $";

  /**
   * This field separates gene class name from the gene persistent representation
   * string. '*' does not work properly with URLEncoder!
   */
  public final static String GENE_DELIMITER = "#";

  /**
   * Represents the heading delimiter that is used to separate genes in the
   * persistent representation of Chromosome instances.
   */
  public final static String GENE_DELIMITER_HEADING = "<";

  /**
   * Represents the closing delimiter that is used to separate genes in the
   * persistent representation of Chromosome instances.
   */
  public final static String GENE_DELIMITER_CLOSING = ">";

  /**
   * Separates chromosome-related information.
   */
  public final static String CHROM_DELIMITER = "#";

  /**
   * The configuration object to use
   */
  private Configuration m_configuration;

  /**
   * The array of Genes contained in this Chromosome.
   */
  private Gene[] m_genes;

  private int m_age;

  private int m_operatedOn;

  /**
   * Unique ID of the chromosome that allows to distinct it from other
   * chromosomes. In the best case, this ID is unique worldwide.
   */
  private String m_uniqueID;

  /**
   * In case mutation, crossing over etc. happened, this sequence gives evidence
   * about the parent(s) of the current chromosome.
   */
  private Map m_uniqueIDTemplates;

  /**
   * The only constructor in this class. Sets the immutable configuration.
   *
   * @param a_configuration the configuration to set
   * @throws InvalidConfigurationException if configuration is null
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public BaseChromosome(Configuration a_configuration)
      throws InvalidConfigurationException {
    if (a_configuration == null) {
      throw new InvalidConfigurationException(
          "Configuration to be set must not"
          + " be null!");
    }
    m_configuration = a_configuration;
    if (m_configuration.isUniqueKeysActive()) {
      m_uniqueIDTemplates = new HashMap();
      IJGAPFactory factory = m_configuration.getJGAPFactory();
      if (JGAPFactory.class.isAssignableFrom(factory.getClass())) {
        m_uniqueID = ( (JGAPFactory) (m_configuration.getJGAPFactory())).
            getUniqueKey(getClass().getName());
      }
    }
  }
  /**
   * @return unique ID of the chromosome, which allows to distinct this instance
   * from others, in the best case worldwide
   *
   * @author Klaus Meffert
   * @since 3.5
   */
  public String getUniqueID() {
    return m_uniqueID;
  }

  /**
   * A template is a chromosome that is the logical predecessor of the current
   * chromosome. A template can occur in mutation or crossing over. In the
   * latter case can be at least two template chromosomes. This is why in this
   * setter method the parameter a_index exists.
   *
   * @param a_templateID the unique ID of the template
   * @param a_index the index of the template, e.g. in crossing over for the
   * second candidate chromosome this is 2
   *
   * @author Klaus Meffert
   * @since 3.5
   */
  public void setUniqueIDTemplate(String a_templateID, int a_index) {
    m_uniqueIDTemplates.put(a_index, a_templateID);
  }

  /**
   * @param a_index the index of the template to retrieve the key for
   * @return String
   *
   * @author Klaus Meffert
   * @since 3.5
   */
  public String getUniqueIDTemplate(int a_index) {
    return m_uniqueIDTemplates.get(a_index);
  }

  /**
   * @return the configuration used
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public Configuration getConfiguration() {
    return m_configuration;
  }

  /**
   * Creates and returns a copy of this object.
   *
   * @return a clone of this instance
   * @throws IllegalStateException instead of CloneNotSupportedException
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public abstract Object clone();

  /**
   * Increases the number of evolutionary rounds of chromosome in which it has
   * not been changed by one.
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public void increaseAge() {
    m_age++;
  }

  /**
   * Reset age of chromosome because it has been changed.
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public void resetAge() {
    m_age = 0;
  }

  /**
   * @return 0: Chromosome newly created in this generation. This means it
   * does not need being crossed over with another newly created one
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public int getAge() {
    return m_age;
  }

  /**
   * @param a_age set the age of the chromosome, see BestChromosomesSelector
   * for a use-case
   *
   * @author Klaus Meffert
   * @since 3.3.3
   */
  public void setAge(int a_age) {
    m_age = a_age;
  }

  /**
   * Increase information of number of genetic operations performed on
   * chromosome in current evolution round.
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public void increaseOperatedOn() {
    m_operatedOn++;
  }

  /**
   * Resets the information of how many genetic operators have been performed
   * on the chromosome in the current round of evolution.
   *
   * @author Klaus Meffert
   * @since 3.2
   *
   */
  public void resetOperatedOn() {
    m_operatedOn = 0;
  }

  /**
   * @return number of genetic operations performed on chromosome in current
   * evolution round
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public int operatedOn() {
    return m_operatedOn;
  }

  /**
   * Retrieves the set of genes that make up this Chromosome. This method
   * exists primarily for the benefit of GeneticOperators that require the
   * ability to manipulate Chromosomes at a low level.
   *
   * @return an array of the Genes contained within this Chromosome
   *
   * @author Neil Rotstan
   * @since 1.0
   */
  public synchronized Gene[] getGenes() {
    return m_genes;
  }

  /**
   * Sets the genes for the chromosome.
   *
   * @param a_genes the genes to set for the chromosome
   *
   * @throws InvalidConfigurationException in case constraint checker is
   * provided
   *
   * @author Klaus Meffert
   * @since 3.2 (previously in class Chromosome)
   */
  public void setGenes(Gene[] a_genes)
      throws InvalidConfigurationException {
    m_genes = a_genes;
  }

  /**
   * Returns the Gene at the given index (locus) within the Chromosome. The
   * first gene is at index zero and the last gene is at the index equal to
   * the size of this Chromosome - 1.
   *
   * @param a_desiredLocus index of the gene value to be returned
   * @return Gene at the given index
   *
   * @author Neil Rotstan
   * @since 1.0
   */
  public synchronized Gene getGene(int a_desiredLocus) {
    return m_genes[a_desiredLocus];
  }

  public void setGene(int a_index, Gene a_gene) {
    m_genes[a_index] = a_gene;
  }

  /**
   * Returns the size of this Chromosome (the number of genes it contains).
   * A Chromosome's size is constant and will not change, until setGenes(...)
   * is used.
   *
   * @return number of genes contained within this Chromosome instance
   *
   * @author Neil Rotstan
   * @author Klaus Meffert
   * @since 1.0
   */
  public int size() {
    if (m_genes == null) {
      // only possible when using default constructor
      return 0;
    }
    else {
      return m_genes.length;
    }
  }

  /**
   * Returns a persistent representation of this chromosome, see interface Gene
   * for description. Similar to CompositeGene's routine. But does not include
   * all information of the chromosome (yet).
   *
   * @return string representation of this Chromosome's relevant parts of its
   * current state
   * @throws UnsupportedOperationException
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public String getPersistentRepresentation() {
    StringBuffer b = new StringBuffer();
    // Persist the chromosome's fitness value.
    // ---------------------------------------
    b.append(getFitnessValueDirectly());
    b.append(CHROM_DELIMITER);
    // Persist the genes.
    // ------------------
    b.append(size());
    b.append(CHROM_DELIMITER);
    getGenesPersistentRepresentation(b);
    return b.toString();
  }

  /**
   * @return the persistent representation of the chromosome by considering
   * its genes.
   *
   * @author Klaus Meffert
   */
  public StringBuffer getGenesPersistentRepresentation() {
    StringBuffer b = new StringBuffer();
    getGenesPersistentRepresentation(b);
    return b;
  }

  /**
   * @return business key of the chromosome
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public String getBusinessKey() {
    return getGenesPersistentRepresentation().toString();
  }

  /**
   * Retrieves the persistent representation of the chromosome by considering
   * its genes.
   *
   * @param a_buffer the variable to store the persistent representation in
   *
   * @author Klaus Meffert
   */
  public void getGenesPersistentRepresentation(StringBuffer a_buffer) {
    Gene gene;
    int size = size();
    for (int i = 0; i < size; i++) {
      gene = getGene(i);
      a_buffer.append(GENE_DELIMITER_HEADING);
          a_buffer.append(encode(gene.getClass().getName()
              + GENE_DELIMITER
              + gene.getPersistentRepresentation()));
      a_buffer.append(GENE_DELIMITER_CLOSING);
    }
  }

  protected String encode(String a_string) {
    return StringKit.encode(a_string);
  }

  protected String decode(String a_string) throws UnsupportedEncodingException {
    return StringKit.decode(a_string);
  }

  /**
   * Counterpart of getPersistentRepresentation.
   *
   * @param a_representation the string representation retrieved from a prior
   * call to the getPersistentRepresentation() method
   *
   * @throws UnsupportedRepresentationException
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public void setValueFromPersistentRepresentation(String a_representation)
      throws UnsupportedRepresentationException {
    if (a_representation != null) {
      try {
        List r = split(a_representation);
        String g;
        // Obtain fitness value.
        // ---------------------
        g = decode( (String) r.get(0));
        setFitnessValue(Double.parseDouble(g));
        r.remove(0);/**@todo we can do this faster!*/
        // Obtain number of genes.
        // -----------------------
        g = decode( (String) r.get(0));
        int count = Integer.parseInt(g);
        setGenes(new Gene[count]);
        r.remove(0);/**@todo we can do this faster!*/
        // Obtain the genes.
        // -----------------
        Iterator iter = r.iterator();
        StringTokenizer st;
        String clas;
        String representation;
        Gene gene;
        int index = 0;
        while (iter.hasNext()) {
          g = decode( (String) iter.next());
          st = new StringTokenizer(g, GENE_DELIMITER);
          if (st.countTokens() != 2)
            throw new UnsupportedRepresentationException("In " + g + ", " +
                "expecting two tokens, separated by " + GENE_DELIMITER);
          clas = st.nextToken();
          representation = st.nextToken();
          gene = createGene(clas, representation);
          setGene(index++, gene);
        }
      }
      catch (Exception ex) {
        throw new UnsupportedRepresentationException(ex.toString());
      }
    }
  }

  /**
   * Creates a new Gene instance.

* Taken from CompositeGene. * * @param a_geneClassName name of the gene class * @param a_persistentRepresentation persistent representation of the gene to * create (could be obtained via getPersistentRepresentation) * * @return newly created gene * @throws Exception * * @author Klaus Meffert * @since 3.2 */ protected Gene createGene(String a_geneClassName, String a_persistentRepresentation) throws Exception { Class geneClass = Class.forName(a_geneClassName); Constructor constr = geneClass.getConstructor(new Class[] {Configuration.class}); Gene gene = (Gene) constr.newInstance(new Object[] {getConfiguration()}); gene.setValueFromPersistentRepresentation(a_persistentRepresentation); return gene; } /** * Splits the input a_string into individual gene representations.

* Taken and adapted from CompositeGene. * * @param a_string the string to split * @return the elements of the returned array are the persistent * representation strings of the chromosome's components * @throws UnsupportedRepresentationException * * @author Klaus Meffert * @since 3.2 */ protected static final List split(String a_string) throws UnsupportedRepresentationException { List a = Collections.synchronizedList(new ArrayList()); // Header data. // ------------ int index = 0; StringTokenizer st0 = new StringTokenizer (a_string, CHROM_DELIMITER, false); if (!st0.hasMoreTokens()) { throw new UnsupportedRepresentationException("Fitness value expected!"); } String fitnessS = st0.nextToken(); a.add(fitnessS); index += fitnessS.length(); if (!st0.hasMoreTokens()) { throw new UnsupportedRepresentationException("Number of genes expected!"); } String numGenes = st0.nextToken(); a.add(numGenes); index += numGenes.length(); index += 2; //2 one-character delimiters if (!st0.hasMoreTokens()) { throw new UnsupportedRepresentationException("Gene data missing!"); } // Remove previously parsed content. // --------------------------------- a_string = a_string.substring(index); // Gene data. // ---------- StringTokenizer st = new StringTokenizer (a_string, GENE_DELIMITER_HEADING + GENE_DELIMITER_CLOSING, true); while (st.hasMoreTokens()) { if (!st.nextToken().equals(GENE_DELIMITER_HEADING)) { throw new UnsupportedRepresentationException(a_string + " no open tag"); } String n = st.nextToken(); if (n.equals(GENE_DELIMITER_CLOSING)) { a.add(""); /* Empty token */ } else { a.add(n); if (!st.nextToken().equals(GENE_DELIMITER_CLOSING)) { throw new UnsupportedRepresentationException (a_string + " no close tag"); } } } return a; } }

Ads help maintain this website.