All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgap.gp.impl.BranchTypingCross Maven / Gradle / Ivy

Go to download

JGAP is a Genetic Algorithms and Genetic Programming component provided as a Java framework.

The newest version!
/*
 * 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 org.jgap.*;
import org.jgap.gp.*;

/**
 * Crossing over for GP ProgramChromosomes.
 *
 * @author Klaus Meffert
 * @since 3.0
 */
public class BranchTypingCross
    extends CrossMethod implements Serializable, Comparable, Cloneable {
  /** String containing the CVS revision. Read out via reflection!*/
  private final static String CVS_REVISION = "$Revision: 1.19 $";

  private boolean m_simpleChromosomeSelection;

  /**
   * Standard constructor.
   *
   * @param a_config the configuration to use
   */
  public BranchTypingCross(GPConfiguration a_config) {
    this(a_config, false);
  }

  /**
   *
   * @param a_config the configuration to use
   * @param a_simpleChromosomeSelection true: plainly select chromosomes,
   * false: select chromosomes proportionally to their size (=number of nodes
   * within a chromosome)
   *
   * @author Klaus Meffert
   * @since 3.4
   */
  public BranchTypingCross(GPConfiguration a_config,
          boolean a_simpleChromosomeSelection) {
    super(a_config);
    m_simpleChromosomeSelection = a_simpleChromosomeSelection;
  }

  /**
   * Crosses two individuals. A random chromosome is chosen for crossing based
   * on the proportion of nodes in each chromosome in the first individual.
   *
   * @param a_i1 the first individual to cross
   * @param a_i2 the second individual to cross
   * @return an array of the two resulting individuals
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public IGPProgram[] operate(final IGPProgram a_i1,
                              final IGPProgram a_i2) {
    try {
      int chromosomeNum;
      if (!m_simpleChromosomeSelection) {
        // Determine which chromosome we'll cross, probabilistically determined
        // by the sizes of the chromosomes of the first individual.
        // This is equivalent to Koza's branch typing.
        // Advantage over plain selection: proportion of the chromosomes' sizes
        // is cared about.
        // --------------------------------------------------------------------
        int[] sizes = new int[a_i1.size()];
        int totalSize = 0;
        for (int i = 0; i < a_i1.size(); i++) {
          // Size of a chromosome = number of nodes.
          // ---------------------------------------
          sizes[i] = a_i1.getChromosome(i).getSize(0);
          totalSize += sizes[i];
        }
        int nodeNum = getConfiguration().getRandomGenerator().nextInt(
                totalSize);
        // Select the chromosome in which node "nodeNum" resides.
        // ------------------------------------------------------
        for (chromosomeNum = 0; chromosomeNum < a_i1.size(); chromosomeNum++) {
          nodeNum -= sizes[chromosomeNum];
          if (nodeNum < 0) {
            break;
          }
        }
      } else {
        // Select a chromosome directly.
        // -----------------------------
        chromosomeNum = getConfiguration().getRandomGenerator().
                nextInt(a_i1.size());
      }
      // Cross the selected chromosomes.
      // -------------------------------
      /**@todo try to ensure uniqueness for unique commands:
       * after selecting first node, check if there is a unique node in the sub
       * tree. If so, check if it appears in the sub tree of the second node.
       */
      ProgramChromosome[] newChromosomes = doCross(
          a_i1.getChromosome(chromosomeNum),
          a_i2.getChromosome(chromosomeNum));
      // Create the new individuals by copying the uncrossed chromosomes
      // and setting the crossed chromosome. There's no need to deep-copy
      // the uncrossed chromosomes because they don't change. That is,
      // even if two individuals' chromosomes point to the same chromosome,
      // the only change in a chromosome is crossing, which generates
      // deep-copied chromosomes anyway.
      // ------------------------------------------------------------------
      IGPProgram[] newIndividuals = {
          new GPProgram(a_i1), new GPProgram(a_i1)};
      for (int i = 0; i < a_i1.size(); i++)
        if (i != chromosomeNum) {
          // Unchanged, not crossed, chromosomes.
          // ------------------------------------
          newIndividuals[0].setChromosome(i, a_i1.getChromosome(i));
          newIndividuals[1].setChromosome(i, a_i2.getChromosome(i));
        }
        else {
          // The crossed chromosomes.
          // ------------------------
          newIndividuals[0].setChromosome(i, newChromosomes[0]);
          newIndividuals[1].setChromosome(i, newChromosomes[1]);
        }
      return newIndividuals;
    } catch (InvalidConfigurationException iex) {
      return null;
    }
  }

  /**
   * Crosses two chromsomes using branch-typing.
   * A random point in the first chromosome is chosen, with a certain probability
   * it will be a function and with a rest probability it will be a terminal. A
   * random point in the second chromosome is chosen using the same probability
   * distribution, but the node chosen must be of the same type as the chosen
   * node in the first chromosome.
   * If a suitable point in the second chromosome couldn't be found then the
   * chromosomes are not crossed.
   * If a resulting chromosome's depth is larger than the maximum crossover
   * depth then that chromosome is simply copied from the original
   * rather than crossed.
   *
   * @param a_c0 the first chromosome to cross
   * @param a_c1 the second chromosome to cross
   * @return an array of the two resulting chromosomes
   * @throws InvalidConfigurationException
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  protected ProgramChromosome[] doCross(ProgramChromosome a_c0,
                                        ProgramChromosome a_c1)
      throws InvalidConfigurationException {
    ProgramChromosome[] c = {
        a_c0, a_c1};
    // Choose a point in c1.
    // ---------------------
    int p0;
    RandomGenerator random = getConfiguration().getRandomGenerator();
    if (random.nextFloat() < getConfiguration().getFunctionProb()) {
      // Choose a function.
      // ------------------
      int nf = a_c0.numFunctions();
      if (nf == 0) {
        // No functions there.
        // -------------------
        return c;
      }
      int fctIndex = random.nextInt(nf);
      p0 = a_c0.getFunction(fctIndex);
    }
    else {
      // Choose a terminal.
      // ------------------
      p0 = a_c0.getTerminal(random.nextInt(a_c0.numTerminals()));
      // Mutate the command's value.
      // ----------------------------
      CommandGene command = a_c0.getNode(p0);
      if (random.nextDouble() <= getConfiguration().getMutationProb()) {
        if (IMutateable.class.isInstance(command)) {
          IMutateable term = (IMutateable) command;
          command = term.applyMutation(0, 0.3d);
          if (command != null) {
            // Check if mutant's function is allowed.
            // --------------------------------------
            if (a_c0.getCommandOfClass(0, command.getClass()) >= 0) {
              a_c0.setGene(p0, command);
            }
          }
        }
      }
    }
    // Choose a point in c2 matching the type and subtype of p0.
    // ---------------------------------------------------------
    int p1;
    CommandGene nodeP0 = a_c0.getNode(p0);
    Class type_ = nodeP0.getReturnType();
    int subType = nodeP0.getSubReturnType();
    if (random.nextFloat() < getConfiguration().getFunctionProb()) {
      // Choose a function.
      // ------------------
      int nf = a_c1.numFunctions(type_, subType);
      if (nf == 0) {
        // No functions of that type.
        // --------------------------
        return c;
      }
      p1 = a_c1.getFunction(random.nextInt(nf), type_, subType);
    }
    else {
      // Choose a terminal.
      // ------------------
      int nt = a_c1.numTerminals(type_, subType);
      if (nt == 0) {
        // No terminals of that type.
        // --------------------------
        return c;
      }
      p1 = a_c1.getTerminal(random.nextInt(a_c1.numTerminals(type_, subType)),
                          type_, subType);
      // Mutate the command's value.
      // ----------------------------
      CommandGene command = a_c1.getNode(p1);
      if (random.nextDouble() <= getConfiguration().getMutationProb()) {
        if (IMutateable.class.isInstance(command)) {
          IMutateable term = (IMutateable) command;
          command = term.applyMutation(0, 0.3d);
          if (command != null) {
            // Check if mutant's function is allowed.
            // --------------------------------------
            if (a_c0.getCommandOfClass(0, command.getClass()) >= 0) {
              a_c1.setGene(p1, command);
            }
          }
        }
      }
    }
    /**@todo solve in general*/
    if (org.jgap.gp.function.SubProgram.class.isAssignableFrom(a_c1.getFunctions()[p1].getClass())) {
      ((IMutateable)a_c1.getFunctions()[p1]).applyMutation(0, 0.5d);
    }
    int s0 = a_c0.getSize(p0); //Number of nodes in c0 from index p0
    int s1 = a_c1.getSize(p1); //Number of nodes in c1 from index p1
    int d0 = a_c0.getDepth(p0); //Depth of c0 from index p0
    int d1 = a_c1.getDepth(p1); //Depth of c1 from index p1
    int c0s = a_c0.getSize(0); //Number of nodes in c0
    int c1s = a_c1.getSize(0); //Number of nodes in c1
    // Check for depth constraint for p1 inserted into c0.
    // ---------------------------------------------------
    if (d0 - 1 + d1/*s1*/ > getConfiguration().getMaxCrossoverDepth()
        || c0s - p0 - s0 < 0
        || p0 + s1 + c0s - p0 - s0 >= a_c0.getFunctions().length) {
      // Choose the other parent.
      // ------------------------
      c[0] = a_c1;
    }
    else {
      c[0] = new ProgramChromosome(getConfiguration(),
                                   a_c0.getFunctions().length,
                                   c[0].getFunctionSet(),
                                   c[0].getArgTypes(),
                                   a_c0.getIndividual());
      System.arraycopy(a_c0.getFunctions(), 0, c[0].getFunctions(), 0, p0);
      System.arraycopy(a_c1.getFunctions(), p1, c[0].getFunctions(), p0, s1);
      System.arraycopy(a_c0.getFunctions(), p0 + s0, c[0].getFunctions(),
                       p0 + s1, c0s - p0 - s0);
      c[0].redepth();
    }
    // Check for depth constraint for p0 inserted into c1.
    // ---------------------------------------------------
    if (d1 - 1 + d0/*s0*/ > getConfiguration().getMaxCrossoverDepth()
        || c1s - p1 - s1 < 0
        || p1 + s0 + c1s - p1 - s1 >= a_c1.getFunctions().length) {
      // Choose the other parent.
      // ------------------------
      c[1] = a_c0;
    }
    else {
      c[1] = new ProgramChromosome(getConfiguration(),
                                   a_c1.getFunctions().length,
                                   c[1].getFunctionSet(),
                                   c[1].getArgTypes(),
                                   a_c1.getIndividual());
      System.arraycopy(a_c1.getFunctions(), 0, c[1].getFunctions(), 0, p1);
      System.arraycopy(a_c0.getFunctions(), p0, c[1].getFunctions(), p1, s0);
      System.arraycopy(a_c1.getFunctions(), p1 + s1, c[1].getFunctions(),
                       p1 + s0, c1s - p1 - s1);
      c[1].redepth();
    }
    return c;
  }

  /**
   * The compareTo-method.
   *
   * @param a_other the other object to compare
   * @return 0 or 1 in this case, as BranchTypingCross objects keep no state
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public int compareTo(Object a_other) {
    BranchTypingCross other = (BranchTypingCross) a_other;
    if (other == null) {
      return 1;
    }
    return 0;
  }

  /**
   * The equals-method.
   *
   * @param a_other the other object to compare
   * @return always true for non-null BranchTypingCross objects because they
   * keep no state
   *
   * @author Klaus Meffert
   * @since 3.0
   */
  public boolean equals(Object a_other) {
    try {
      BranchTypingCross other = (BranchTypingCross) a_other;
      if (other == null) {
        return false;
      }
      else {
        return true;
      }
    } catch (ClassCastException cex) {
      return false;
    }
  }

  /**
   * @return deep clone of this instance
   *
   * @author Klaus Meffert
   * @since 3.2
   */
  public Object clone() {
    BranchTypingCross result = new BranchTypingCross(getConfiguration());
    return result;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy