Package org.jgap.gp.impl

Source Code of org.jgap.gp.impl.GPProgram

/*
* 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.gp.impl;

import java.io.*;
import java.util.*;
import org.jgap.*;
import org.jgap.gp.*;
import org.jgap.gp.function.*;
import org.jgap.util.*;
import org.jgap.gp.terminal.Argument;

/**
* A GP program contains 1..n ProgramChromosome's.
*
* @author Klaus Meffert
* @since 3.0
*/
public class GPProgram
    extends GPProgramBase implements Serializable, Comparable, ICloneable,
    IBusinessKey {
  /** String containing the CVS revision. Read out via reflection!*/
  private final static String CVS_REVISION = "$Revision: 1.23 $";

  final static String PROGRAMCHROM_DELIMITER_HEADING = "<";

  final static String PROGRAMCHROM_DELIMITER_CLOSING = ">";

  final static String PROGRAMCHROM_DELIMITER = "#";

  /**
   * Holds the chromosomes contained in this program.
   */
  private ProgramChromosome[] m_chromosomes;

  /**
   * Default constructor, only for dynamic instantiation.
   *
   * @throws Exception
   *
   * @author Klaus Meffert
   * @since 3.3.4
   */
  public GPProgram()
      throws Exception {
  }

  /**
   * Master constructor.
   *
   * @param a_conf the configuration to use
   * @param a_types the type of each chromosome, the length is the number of
   * chromosomes
   * @param a_argTypes the types of the arguments to each chromosome, must be an
   * array of arrays, the first dimension of which is the number of chromosomes
   * and the second dimension of which is the number of arguments to the
   * chromosome
   * @param a_nodeSets the nodes which are allowed to be used by each chromosome,
   * must be an array of arrays, the first dimension of which is the number of
   * chromosomes and the second dimension of which is the number of nodes
   * @param a_minDepths contains the minimum depth allowed for each chromosome
   * @param a_maxDepths contains the maximum depth allowed for each chromosome
   * @param a_maxNodes reserve space for a_maxNodes number of nodes
   * @throws InvalidConfigurationException
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public GPProgram(GPConfiguration a_conf, Class[] a_types,
                   Class[][] a_argTypes, CommandGene[][] a_nodeSets,
                   int[] a_minDepths, int[] a_maxDepths, int a_maxNodes)
      throws InvalidConfigurationException {
    super(a_conf);
    m_chromosomes = new ProgramChromosome[a_types.length];
    setTypes(a_types);
    setArgTypes(a_argTypes);
    setNodeSets(a_nodeSets);
    setMaxDepths(a_maxDepths);
    setMinDepths(a_minDepths);
    setMaxNodes(a_maxNodes);
  }

  /**
   * Constructor to initialize a GPProgram with values of another GPProgram.
   *
   * @param a_prog the GPProgram to read the initialization values from
   * @throws InvalidConfigurationException
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public GPProgram(IGPProgram a_prog)
      throws InvalidConfigurationException {
    super(a_prog);
    m_chromosomes = new ProgramChromosome[getTypes().length];
  }

  /**
   * Sort of minimalistic constructor. Use only if you are aware of what you do.
   *
   * @param a_conf the configuration to use
   * @param a_numChromosomes the number of chromosomes to use with this program.
   * @throws InvalidConfigurationException
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public GPProgram(GPConfiguration a_conf, int a_numChromosomes)
      throws InvalidConfigurationException {
    super(a_conf);
    m_chromosomes = new ProgramChromosome[a_numChromosomes];
  }

  /**
   * @param a_index the chromosome to get
   * @return the ProgramChromosome with the given index
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public ProgramChromosome getChromosome(int a_index) {
    IGPProgram ind = m_chromosomes[a_index].getIndividual();
    if (this != ind) {
      m_chromosomes[a_index].setIndividual(this);
    }
    return m_chromosomes[a_index];
  }

  /**
   * Sets the given chromosome at the given index.
   *
   * @param a_index sic
   * @param a_chrom sic
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public void setChromosome(int a_index, ProgramChromosome a_chrom) {
    m_chromosomes[a_index] = a_chrom;
  }

  /**
   * Initialize the chromosomes within this GP program using the grow or the
   * full method.
   *
   * @param a_depth the maximum depth of the chromosome to create
   * @param a_grow true: use grow method; false: use full method
   * @param a_maxNodes maximum number of nodes allowed
   * @param a_fullModeAllowed for each chromosome: true means full mode allowed,
   * otherwise use grow mode
   * @param a_tries maximum number of tries to create a valid program
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public void growOrFull(int a_depth, boolean a_grow, int a_maxNodes,
                         boolean[] a_fullModeAllowed, int a_tries) {
    GPConfiguration conf = getGPConfiguration();
    // The number of chromosomes to create.
    // ------------------------------------
    int size = m_chromosomes.length;
    for (int i = 0; i < size; i++) {
      try {
        // Construct a chromosome with place for a_maxNodes nodes.
        // -------------------------------------------------------
        m_chromosomes[i] = new ProgramChromosome(conf, a_maxNodes, this);
      } catch (InvalidConfigurationException iex) {
        throw new RuntimeException(iex);
      }
      m_chromosomes[i].setArgTypes(getArgTypes()[i]);
      // If there are ADF's in the nodeSet, then set their type according to
      // the chromosome it references.
      // -------------------------------------------------------------------
      int len = getNodeSets()[i].length;
      for (int j = 0; j < len; j++) {
        if (getNodeSets()[i][j] instanceof ADF) {
          ( (ADF) getNodeSets()[i][j]).setReturnType(
              getTypes()[ ( (ADF) getNodeSets()[i][j]).getChromosomeNum()]);
        }
      }
    }
    int depth;
    for (int i = 0; i < size; i++) {
      // Restrict depth to input params.
      // -------------------------------
      if (getMaxDepths() != null && a_depth > getMaxDepths()[i]) {
        depth = getMaxDepths()[i];
      }
      else {
        if (getMinDepths() != null && a_depth < getMinDepths()[i]) {
          depth = getMinDepths()[i];
        }
        else {
          depth = a_depth;
        }
      }
      // Decide whether to use grow mode or full mode.
      // Here, the program is finally created.
      // ---------------------------------------------
      if (a_grow || !a_fullModeAllowed[i]) {
        m_chromosomes[i].growOrFull(i, depth, getType(i), getArgType(i),
                                    getNodeSet(i), true, a_tries);
      }
      else {
        m_chromosomes[i].growOrFull(i, depth, getType(i), getArgType(i),
                                    getNodeSet(i), false, a_tries);
      }
    }
    if (getGPConfiguration().isUseProgramCache()) {
      // Cache fitness value by checking if a program with same
      // representation was computed before.
      // ------------------------------------------------------
      GPProgramInfo pcInfo = getGPConfiguration().readProgramCache(this);
      if (pcInfo == null) {
        pcInfo = putToCache(this);
      }
      else {
        setFitnessValue(pcInfo.getFitnessValue());
      }
    }
  }

  /**
   * Put program to cache.
   *
   * @param a_program the program to put into the cache
   * @return GPProgramInfo info about the program
   *
   * @author Klaus Meffert
   * @since 3.4
   */
  protected GPProgramInfo putToCache(GPProgram a_program) {
    return getGPConfiguration().putToProgramCache(a_program);
  }

  /**
   * Initialize this program by using given chromosomes.
   *
   * @param a_argTypes the types of the arguments to each chromosome, must be an
   * array of arrays, the first dimension of which is the number of chromosomes
   * and the second dimension of which is the number of arguments to the
   * chromosome
   * @param a_nodeSets the nodes which are allowed to be used by each chromosome,
   *
   * @author Klaus Meffert
   * @since 3.2.2
   */
  public void growOrFull(Class[][] a_argTypes, CommandGene[][] a_nodeSets) {
    int size = m_chromosomes.length;
    for (int i = 0; i < size; i++) {
      m_chromosomes[i].setArgTypes(a_argTypes[i]);
      // If there are ADF's in the nodeSet, then set their type according to
      // the chromosome it references.
      // -------------------------------------------------------------------
      int len = getNodeSets()[i].length;
      for (int j = 0; j < len; j++) {
        if (getNodeSets()[i][j] instanceof ADF) {
          ( (ADF) getNodeSets()[i][j]).setReturnType(
              getTypes()[ ( (ADF) getNodeSets()[i][j]).getChromosomeNum()]);
        }
      }
    }
    for (int i = 0; i < size; i++) {
      ProgramChromosome chrom = m_chromosomes[i];
      chrom.setFunctionSet(a_nodeSets[i]);
      CommandGene[] functionSet = chrom.getFunctionSet();
      CommandGene[] newFktSet = new CommandGene[functionSet.length +
          a_argTypes[i].length];
      System.arraycopy(functionSet, 0, newFktSet, 0,
                       functionSet.length);
      for (int ii = 0; ii < a_argTypes[i].length; ii++) {
        try {
          functionSet[a_nodeSets[i].length + ii]
              = new Argument(getGPConfiguration(), ii, a_argTypes[i][ii]);
        } catch (InvalidConfigurationException iex) {
          throw new RuntimeException(iex);
        }
      }
      chrom.redepth();
    }
    if (getGPConfiguration().isUseProgramCache()) {
      // Cache fitness value by checking if a program with same
      // representation was computed before.
      GPProgramInfo pcInfo = getGPConfiguration().readProgramCache(this);
      if (pcInfo == null) {
        pcInfo = putToCache(this);
      }
      else {
        setFitnessValue(pcInfo.getFitnessValue());
      }
    }
  }

  /**
   * @return the number of chromosomes in the program
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public int size() {
    return m_chromosomes.length;
  }

  /**
   * Builds a string that represents the output of the GPProgram in
   * left-hand-notion.
   *
   * @param a_startNode the node to start with
   * @return output in left-hand notion
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public String toString(int a_startNode) {
    if (a_startNode < 0) {
      return "";
    }
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < m_chromosomes.length; i++) {
      if (i > 0) {
        sb.append(" ==> ");
      }
      sb.append(m_chromosomes[i].toString(a_startNode));
    }
    return sb.toString();
  }

  /**
   * Builds a string that represents the normalized output of the GPProgram.
   *
   * @param a_startNode the node to start with
   * @return output in normalized notion
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public String toStringNorm(int a_startNode) {
    if (a_startNode < 0) {
      return "";
    }
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < m_chromosomes.length; i++) {
      if (i > 0) {
        sb.append(" ==> ");
      }
      m_chromosomes[i].setIndividual(this);
      sb.append(m_chromosomes[i].toStringNorm(a_startNode));
    }
    return sb.toString();
  }

  /**
   * Builds a string that represents the debug output of the GPProgram.
   *
   * @return class names of all program chromosomes
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public String toStringDebug() {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < m_chromosomes.length; i++) {
      if (i > 0) {
        sb.append(" ==> ");
      }
      m_chromosomes[i].setIndividual(this);
      sb.append(m_chromosomes[i].toStringDebug());
    }
    return sb.toString();
  }

  /**
   * Executes the given chromosome as an integer function.
   *
   * @param a_chromosomeNum the index of the chromosome to execute
   * @param a_args the arguments to use
   * @return the integer return value
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public int execute_int(int a_chromosomeNum, Object[] a_args) {
    m_chromosomes[a_chromosomeNum].setIndividual(this);
    return m_chromosomes[a_chromosomeNum].execute_int(a_args);
  }

  /**
   * Executes the given chromosome as a float function.
   *
   * @param a_chromosomeNum the index of the chromosome to execute
   * @param a_args the arguments to use
   * @return the floar return value
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public float execute_float(int a_chromosomeNum, Object[] a_args) {
    m_chromosomes[a_chromosomeNum].setIndividual(this);
    return m_chromosomes[a_chromosomeNum].execute_float(a_args);
  }

  /**
   * Executes the given chromosome as a double function.
   *
   * @param a_chromosomeNum the index of the chromosome to execute
   * @param a_args the arguments to use
   * @return the double return value
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public double execute_double(int a_chromosomeNum, Object[] a_args) {
    m_chromosomes[a_chromosomeNum].setIndividual(this);
    return m_chromosomes[a_chromosomeNum].execute_double(a_args);
  }

  /**
   * Executes the given chromosome as a boolean function.
   *
   * @param a_chromosomeNum the index of the chromosome to execute
   * @param a_args the arguments to use
   * @return the boolean return value
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public boolean execute_boolean(int a_chromosomeNum, Object[] a_args) {
    m_chromosomes[a_chromosomeNum].setIndividual(this);
    return m_chromosomes[a_chromosomeNum].execute_boolean(a_args);
  }

  /**
   * Executes the given chromosome as an object function.
   *
   * @param a_chromosomeNum the index of the chromosome to execute
   * @param a_args the arguments to use
   * @return the object return value
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public Object execute_object(int a_chromosomeNum, Object[] a_args) {
    m_chromosomes[a_chromosomeNum].setIndividual(this);
    return m_chromosomes[a_chromosomeNum].execute_object(a_args);
  }

  /**
   * Executes the given chromosome as an object function.
   *
   * @param a_chromosomeNum the index of the chromosome to execute
   * @param a_args the arguments to use
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public void execute_void(int a_chromosomeNum, Object[] a_args) {
    m_chromosomes[a_chromosomeNum].setIndividual(this);
    m_chromosomes[a_chromosomeNum].execute_void(a_args);
  }

  /**
   * Searches for a chromosome that has the given class and returns its index.
   *
   * @param a_chromosomeNum the index of the chromosome to start the search with
   * @param a_class the class to find
   * @return the index of the first chromosome found that is of a_class, or -1
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public int getCommandOfClass(int a_chromosomeNum, Class a_class) {
    for (int i = a_chromosomeNum; i < m_chromosomes.length; i++) {
      int j = m_chromosomes[i].getCommandOfClass(0, a_class);
      if (j >= 0) {
        return j;
      }
    }
    return -1;
  }

  /**
   * Compares the given program to this program.
   *
   * @param a_other the program against which to compare this program
   * @return a negative number if this program is "less than" the given
   * program, zero if they are equal to each other, and a positive number if
   * this program is "greater than" the given program
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public int compareTo(Object a_other) {
    // First, if the other Chromosome is null, then this chromosome is
    // automatically the "greater" Chromosome.
    // ---------------------------------------------------------------
    if (a_other == null) {
      return 1;
    }
    int size = size();
    GPProgram other = (GPProgram) a_other;
    ProgramChromosome[] otherChroms = other.m_chromosomes;
    // If the other Chromosome doesn't have the same number of genes,
    // then whichever has more is the "greater" Chromosome.
    // --------------------------------------------------------------
    if (other.size() != size) {
      return size() - other.size();
    }
    // Next, compare the gene values (alleles) for differences. If
    // one of the genes is not equal, then we return the result of its
    // comparison.
    // ---------------------------------------------------------------
    Arrays.sort(m_chromosomes);
    Arrays.sort(otherChroms);
    for (int i = 0; i < size; i++) {
      int comparison = m_chromosomes[i].compareTo(otherChroms[i]);
      if (comparison != 0) {
        return comparison;
      }
    }
    // Everything is equal. Return zero.
    // ---------------------------------
    return 0;
  }

  /**
   * @return deep clone of the object instance
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public Object clone() {
    try {
      // Min and max depths can be null.
      // -------------------------------
      int[] minDepthsClone;
      if (getMinDepths() != null) {
        minDepthsClone = (int[]) getMinDepths().clone();
      }
      else {
        minDepthsClone = null;
      }
      int[] maxDepthsClone;
      if (getMaxDepths() != null) {
        maxDepthsClone = (int[]) getMaxDepths().clone();
      }
      else {
        maxDepthsClone = null;
      }
      GPProgram result = new GPProgram(getGPConfiguration(),
                                       (Class[]) getTypes().clone(),
                                       (Class[][]) getArgTypes().clone(),
                                       (CommandGene[][]) getNodeSets().clone(),
                                       minDepthsClone,
                                       maxDepthsClone,
                                       getMaxNodes());
      result.setFitnessValue(getFitnessValueDirectly());
      // Try to clone application data.
      // ------------------------------
      Object appData = getApplicationData();
      if (appData != null) {
        ICloneHandler cloner = getGPConfiguration().getJGAPFactory().
            getCloneHandlerFor(appData, null);
        if (cloner != null) {
          result.setApplicationData(cloner.perform(appData, null, null));
        }
        else {
          result.setApplicationData(appData);
        }
      }
      for (int i = 0; i < m_chromosomes.length; i++) {
        if (m_chromosomes[i] == null) {
          break;
        }
        result.m_chromosomes[i] = (ProgramChromosome) m_chromosomes[i].clone();
      }
      return result;
    } catch (Exception ex) {
      throw new CloneException(ex);
    }
  }

  /**
   * @return the persistent representation of the GP program, including all
   * chromosomes
   *
   * @author Klaus Meffert
   * @since 3.3
   */
  public String getPersistentRepresentation() {
    StringBuffer b = new StringBuffer();
    for (ProgramChromosome chrom : m_chromosomes) {
      b.append(PROGRAMCHROM_DELIMITER_HEADING);
      b.append(encode(
          chrom.getClass().getName() +
          PROGRAMCHROM_DELIMITER +
          chrom.getPersistentRepresentation()));
      b.append(PROGRAMCHROM_DELIMITER_CLOSING);
    }
    return b.toString();
  }

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

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

  /**
   * @return hopefully unique key representing the state of the GPProgram
   *
   * @author Klaus Meffert
   * @since 3.4
   */
  public String getBusinessKey() {
    return toStringNorm(0);
  }
}
TOP

Related Classes of org.jgap.gp.impl.GPProgram

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.