BaseGene.java :  » Development » jgap-3.4.4 » org » jgap » Java Open Source

Java Open Source » Development » jgap 3.4.4 
jgap 3.4.4 » org » jgap » BaseGene.java
/*
 * 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 org.jgap.util.StringKit;

/**
 * Abstract base class for all genes. Provides default implementations.
 *
 * @author Klaus Meffert
 * @since 2.2
 */
public abstract class BaseGene
    implements Gene, IBusinessKey {
  /** String containing the CVS revision. Read out via reflection!*/
  private final static String CVS_REVISION = "$Revision: 1.27 $";

  /**
   * Delta, useful for comparing doubles and floats.
   */
  public static final double DELTA = 0.0000001;

  /** Energy of a gene, see RFE 1102206*/
  private double m_energy;

  /**
   * Application-specific data that is attached to the Gene. This data may
   * assist the application in labelling this Gene.
   * JGAP ignores the data, aside from allowing it to be set and
   * retrieved and considering it in clone() and compareTo().
   *
   * @since 2.4
   */
  private Object m_applicationData;

  /**
   * Method compareTo(): Should we also consider the application data when
   * comparing? Default is "false" as "true" means a Gene's losing its
   * identity when application data is set differently!
   *
   * @since 2.4
   */
  private boolean m_compareAppData;

  private Configuration m_configuration;

  /**
   * Constants for toString()
   */
  public final static String S_APPLICATION_DATA = "Application data";

  /**
   *
   * @param a_configuration the configuration to use
   * @throws InvalidConfigurationException
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public BaseGene(Configuration a_configuration)
      throws InvalidConfigurationException {
    if (a_configuration == null) {
      throw new InvalidConfigurationException("Configuration must not be null!");
    }
    m_configuration = a_configuration;
  }

  /**
   * Retrieves the allele value represented by this Gene.
   *
   * @return the allele value of this Gene
   * @since 1.0
   */
  public Object getAllele() {
    return getInternalValue();
  }

  /**
   * Retrieves the hash code value for a Gene.
   * Override if another hashCode() implementation is necessary or more
   * appropriate than this default implementation.
   *
   * @return this Gene's hash code
   *
   * @author Neil Rotstan
   * @author Klaus Meffert
   * @since 1.0
   */
  public int hashCode() {
    // If our internal value is null, then return zero. Otherwise,
    // just return the hash code of the allele Object.
    // -----------------------------------------------------------
    if (getInternalValue() == null) {
      return -79;
    }
    else {
      return getInternalValue().hashCode();
    }
  }

  /**
   * Executed by the genetic engine when this Gene instance is no
   * longer needed and should perform any necessary resource cleanup.
   * If you need a special cleanup, override this method.
   *
   * @author Klaus Meffert
   * @since 1.0
   */
  public void cleanup() {
    // No specific cleanup is necessary by default.
    // --------------------------------------------
  }

  /**
   * Retrieves a string representation of this Gene's value that
   * may be useful for display purposes.
   *
   * @return a string representation of this Gene's value
   *
   * @author Klaus Meffert
   * @since 1.0
   */
  public String toString() {
    String representation;
    if (getInternalValue() == null) {
      representation = "null";
    }
    else {
      representation = getInternalValue().toString();
    }
    String appData;
    if (getApplicationData() != null) {
      appData = getApplicationData().toString();
    }
    else {
      appData = "null";
    }
    representation += ", " + S_APPLICATION_DATA + ":" + appData;
    return representation;
  }

  /**
   * @return the size of the gene, i.e the number of atomic elements. Always 1
   * for non-composed Gene types. Override for composed Gene types
   *
   * @author Neil Rotstan
   * @since 1.0
   */
  public int size() {
    return 1;
  }

  /**
   * Compares this Gene with the given object and returns true if the other
   * object is a Gene of the same type and has the same value (allele) as
   * this Gene. Otherwise it returns false.
   *
   * @param a_other the object to compare to this Gene for equality
   * @return true if this Gene is equal to the given object, false otherwise
   *
   * @author Klaus Meffert
   * @since 1.1
   */
  public boolean equals(final Object a_other) {
    try {
      int result = compareTo(a_other);
      if (result == 0) {
        if (isCompareApplicationData()) {
          Gene otherGene = (Gene) a_other;
          int resultAppData = compareApplicationData(getApplicationData(),
              otherGene.getApplicationData());
          return resultAppData == 0;
        }
        else {
          return true;
        }
      }
      else {
        return false;
      }
    } catch (ClassCastException e) {
      // If the other object isn't an Gene of current type
      // (like IntegerGene for IntegerGene's), then we're not equal.
      // -----------------------------------------------------------
      return false;
    }
  }

  /**
   * Each Gene implementation holds its own m_value object keeping the allele
   * value. In your Gene implementation, just return it with this method
   * (see {@link org.jgap.impl.BooleanGene} for example)
   * @return the m_value object
   *
   * @author Klaus Meffert
   * @since 2.2
   */
  protected abstract Object getInternalValue();

  /**
   * @return energy of the gene
   *
   * @author Klaus Meffert
   * @since 2.3
   */
  public double getEnergy() {
    return m_energy;
  }

  /**
   * Sets the energy of the gene
   * @param a_energy the energy to set
   *
   * @author Klaus Meffert
   * @since 2.3
   */
  public void setEnergy(final double a_energy) {
    m_energy = a_energy;
  }

  /**
   * This sets the application-specific data that is attached to this Gene.
   * Attaching application-specific data may be useful for
   * some applications when it comes time to distinguish a Gene from another.
   * JGAP ignores this data functionally.
   *
   * @param a_newData the new application-specific data to attach to this
   * Gene
   *
   * @author Klaus Meffert
   * @since 2.4
   */
  public void setApplicationData(final Object a_newData) {
    m_applicationData = a_newData;
  }

  /**
   * Retrieves the application-specific data that is attached to this Gene.
   * Attaching application-specific data may be useful for
   * some applications when it comes time to distinguish a Gene from another.
   * JGAP ignores this data functionally.
   *
   * @return the application-specific data previously attached to this Gene,
   * or null if there is no data attached
   *
   * @author Klaus Meffert
   * @since 2.4
   */
  public Object getApplicationData() {
    return m_applicationData;
  }

  /**
   * Should we also consider the application data when comparing? Default is
   * "false" as "true" means a Gene is losing its identity when
   * application data is set differently!
   *
   * @param a_doCompare true: consider application data in method compareTo
   *
   * @author Klaus Meffert
   * @since 2.4
   */
  public void setCompareApplicationData(final boolean a_doCompare) {
    m_compareAppData = a_doCompare;
  }

  /*
   * @return should we also consider the application data when comparing?
   *
   * @author Klaus Meffert
   * @since 2.4
   */
  public boolean isCompareApplicationData() {
    return m_compareAppData;
  }

  protected int compareApplicationData(final Object a_appdata1,
                                       final Object a_appdata2) {
    // Compare application data.
    // -------------------------
    if (a_appdata1 == null) {
      if (a_appdata2 != null) {
        return -1;
      }
      else {
        return 0;
      }
    }
    else if (a_appdata2 == null) {
      return 1;
    }
    else {
      // The above code is contained in the following, but for performance
      // issues we keep it here redundantly.
      // -----------------------------------------------------------------
      ICompareToHandler handler = getConfiguration().getJGAPFactory().
          getCompareToHandlerFor(a_appdata1, a_appdata2.getClass());
      if (handler != null) {
        try {
          return ( (Integer) handler.perform(a_appdata1, null, a_appdata2)).
              intValue();
        } catch (Exception ex) {
          throw new Error(ex);
        }
      }
      else {
        return 0;
      }
    }
  }

  /**
   * Optional helper class for checking if a given allele value to be set
   * for a given gene is valid. If not, the allele value may not be set for the
   * gene or the gene type (e.g. IntegerGene) is not allowed in general!
   *
   * @since 2.5 (moved from CompositeGene, where it was since 2.0)
   */
  private IGeneConstraintChecker m_geneAlleleChecker;

  /**
   * Sets the constraint checker to be used for this gene whenever method
   * setAllele(Object) is called.
   * @param a_constraintChecker the constraint checker to be set
   *
   * @author Klaus Meffert
   * @since 2.5 (moved from CompositeGene, where it was since 2.0)
   */
  public void setConstraintChecker(
      final IGeneConstraintChecker a_constraintChecker) {
    m_geneAlleleChecker = a_constraintChecker;
  }

  /**
   * @return IGeneConstraintChecker the constraint checker to be used whenever
   * method setAllele(Object) is called.
   *
   * @author Klaus Meffert
   * @since 2.5 (moved from CompositeGene, where it was since 2.0)
   */
  public IGeneConstraintChecker getConstraintChecker() {
    return m_geneAlleleChecker;
  }

  /**
   * Provides implementation-independent means for creating new Gene
   * instances. The new instance that is created and returned should be
   * setup with any implementation-dependent configuration that this Gene
   * instance is setup with (aside from the actual value, of course). For
   * example, if this Gene were setup with bounds on its value, then the
   * Gene instance returned from this method should also be setup with
   * those same bounds. This is important, as the JGAP core will invoke this
   * method on each Gene in the sample Chromosome in order to create each
   * new Gene in the same respective gene position for a new Chromosome.
   *
   * @return a new Gene instance of the same type and with the same setup as
   * this concrete Gene
   *
   * @author Neil Rostan
   * @author Klaus Meffert
   * @since 2.6 (since 1.0 in IntegerGene)
   */
  public Gene newGene() {
    Gene result = newGeneInternal();
    result.setConstraintChecker(getConstraintChecker());
    result.setEnergy(getEnergy());
    /**@todo clone app.data*/
    result.setApplicationData(getApplicationData());
    return result;
  }

  protected abstract Gene newGeneInternal();

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

  public String getBusinessKey() {
    Object allele = getAllele();
    String result = getClass().getName() + PERSISTENT_FIELD_DELIMITER;
    if (allele == null) {
      return result;
    }
    return result + allele.toString();
  }

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

  protected String decode(String a_string) {
    return StringKit.decode(a_string);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.