Package jcgp.backend.tests

Source Code of jcgp.backend.tests.ChromosomeTests

package jcgp.backend.tests;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Connection;
import jcgp.backend.population.Input;
import jcgp.backend.population.Mutable;
import jcgp.backend.population.Node;
import jcgp.backend.population.Output;
import jcgp.backend.resources.ModifiableResources;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
*
* Tests which cover the behaviour specified for a chromosome.
*
*  - The chromosome should be able to return a specified node, input or output.
*  - It should be able to return a random Mutable.
*  - It should be able to return a random allowed connection given a column.
*  - It should be able to return a random connection.
*  - It should contain a freely modifiable fitness value.
*  - For truth table evaluations, it should be able to have its inputs set.
*  - For truth table evaluations, the output should return a value according to the inputs.
*  - It should feature a copy method, which creates a deep copy of a specified Chromosome object.
*  - It should be able to return a list of active nodes.
*  - It should contain a method to evaluate whether a given chromosome is identical
*    to it.
*  - Same as above, but only looking at the active portion of a chromosome.
*  WARNING: changing parameters may cause the tests to incorrectly fail!
*
* @author Eduardo Pedroni
*
*/
public class ChromosomeTests {

  private Chromosome chromosome;
  private static ModifiableResources resources;

  @BeforeClass
  public static void setUpBeforeClass() {
    resources = new ModifiableResources();
    resources.setFunctionSet(new TestFunctionSet());
  }

  @Before
  public void setUp() throws Exception {
    chromosome = new Chromosome(resources);
  }

  /**
   *
   */
  @Test
  public void cloneTest() {
    // create a clone, check to see if it really is a clone
    Chromosome clone = new Chromosome(chromosome);

    // compare all elements, one by one
    // check outputs
    for (int o = 0; o < resources.outputs(); o++) {
      // check that no cross-references exist between chromosomes
      assertTrue("Cloned chromosome contains a reference to a member of the original chromosome.",
          clone.getOutput(o) != chromosome.getOutput(o) &&
          clone.getOutput(o).getSource() != chromosome.getOutput(o).getSource());
      // check that the connections are equivalent
      if (clone.getOutput(o).getSource() instanceof Input && chromosome.getOutput(o).getSource() instanceof Input) {
        assertTrue("Outputs did not connect to equivalent inputs.",
            ((Input) clone.getOutput(o).getSource()).getIndex() == ((Input) chromosome.getOutput(o).getSource()).getIndex());
      } else if (clone.getOutput(o).getSource() instanceof Node && chromosome.getOutput(o).getSource() instanceof Node) {
        assertTrue("Outputs did not connect to equivalent nodes.",
            ((Node) clone.getOutput(o).getSource()).getRow() == ((Node) chromosome.getOutput(o).getSource()).getRow() &&
            ((Node) clone.getOutput(o).getSource()).getColumn() == ((Node) chromosome.getOutput(o).getSource()).getColumn());
      } else {
        fail("Output source types did not match.");
      }
    }
    // check nodes, rows first
    for (int row = 0; row < resources.rows(); row++) {
      for (int column = 0; column < resources.columns(); column++) {
        // check that nodes are not pointers to the same instance
        assertTrue("Both chromosomes contain a reference to the same node.", clone.getNode(row, column) != chromosome.getNode(row, column));
        // check that both nodes reference their own position in the grid correctly
        assertTrue("Equivalent nodes self-reference differently.", clone.getNode(row, column).getRow() == chromosome.getNode(row, column).getRow() &&
            clone.getNode(row, column).getColumn() == chromosome.getNode(row, column).getColumn());
        // check that the two nodes have the same function
        assertTrue("Equivalent nodes have different functions.", clone.getNode(row, column).getFunction() == chromosome.getNode(row, column).getFunction());

        // compare each connection
        for (int connection = 0; connection < resources.arity(); connection++) {
          // first look at whether they are actually the same instance
          assertTrue("Nodes are connected to the same connection instance.",
              clone.getNode(row, column).getConnection(connection) !=  chromosome.getNode(row, column).getConnection(connection));

          // if the connections aren't the same instance, check that their addresses are the same
          if (clone.getNode(row, column).getConnection(connection) instanceof Input &&
              chromosome.getNode(row, column).getConnection(connection) instanceof Input) {

            assertTrue("Nodes did not connect to equivalent inputs.",
                ((Input) clone.getNode(row, column).getConnection(connection)).getIndex() ==
                ((Input) chromosome.getNode(row, column).getConnection(connection)).getIndex());

          } else if (clone.getNode(row, column).getConnection(connection) instanceof Node &&
              chromosome.getNode(row, column).getConnection(connection) instanceof Node) {

            assertTrue("Nodes did not connect to equivalent nodes.",
                ((Node) clone.getNode(row, column).getConnection(connection)).getRow() ==
                ((Node) chromosome.getNode(row, column).getConnection(connection)).getRow() &&

                ((Node) clone.getNode(row, column).getConnection(connection)).getColumn() ==
                ((Node) chromosome.getNode(row, column).getConnection(connection)).getColumn());

          } else {
            fail("Connection types did not match.");
          }
        }
      }
    }

    // check cloning given a known topology
    chromosome = createKnownConfiguration();
    clone = new Chromosome(chromosome);
   
    Integer[] testInputs = new Integer[] {5, 8, 4};
    chromosome.setInputs((Object[]) testInputs);
    clone.setInputs((Object[]) testInputs);

    // check that both chromosomes have the same outputs
    for (int i = 0; i < resources.outputs(); i++) {
      assertTrue("Incorrect output returned", ((Integer) chromosome.getOutput(i).calculate()) == ((Integer) clone.getOutput(i).calculate()));
    }

    // mutate an output in clone, check that the same node in chromosome produces a different output
    clone.getOutput(1).setSource(clone.getInput(2));

    assertTrue("Mutation affected nodes in both chromosomes.",
        clone.getOutput(1).calculate() != chromosome.getOutput(1).calculate());

  }
  /**
   *
   */
  @Test
  public void fitnessTest() {
    // set a fitness value, check if returned value is the same
    chromosome.setFitness(10);
    assertTrue("Incorrect fitness returned.", chromosome.getFitness() == 10);
  }

  /**
   *
   */
  @Test
  public void randomConnectionTest() {
    // get random connections with column 0, check that they are all inputs
    for (int i = 0; i < 10000; i++) {
      boolean connectionReturn = chromosome.getRandomConnection(0) instanceof Input;
      assertTrue("Connection is not an input.", connectionReturn);
    }

    // get random connections with the last column as reference, check that they're all within range
    int connectionNodes = 0, connectionOutOfRange = 0, connectionInputs = 0, connectionPicks = 100000;
    int chosenColumn = resources.columns() - 1;
    for (int i = 0; i < connectionPicks; i++) {
      Connection c = chromosome.getRandomConnection(chosenColumn);
      if (c instanceof Node) {
        connectionNodes++;
        if (((Node) c).getColumn() >= chosenColumn) {
          connectionOutOfRange++;
        }
        assertTrue("Connection is not allowed : " + ((Node) c).getColumn(), ((Node) c).getColumn() < chosenColumn && ((Node) c).getColumn() < chosenColumn);
      } else if (c instanceof Input) {
        connectionInputs++;
      } else {
        fail("Return is neither Node nor Input.");

     
    }
    System.out.println("Out of " + connectionPicks + " connections picked from " + ((chosenColumn >= resources.levelsBack()) ? resources.levelsBack() : chosenColumn) * resources.rows() +
        " allowed nodes and " + resources.inputs() + " inputs, " + connectionNodes + " were nodes and " + connectionInputs + " were inputs.");

    System.out.println("Node/input ratio: " + (chosenColumn >= resources.levelsBack() ? resources.levelsBack() : chosenColumn) * (double) resources.rows() / (double) resources.inputs() +
        ", picked ratio: " + (double) connectionNodes / (double) connectionInputs);

    System.out.println(connectionOutOfRange + " nodes that disrespected levels back were picked.");
  }
  /**
   *
   */
  @Test
  public void randomMutableTest() {
    // get mutable elements, check Node to Output ratio
    int mutablePicks = 100000;
    int mutableNodes = 0, mutableOutputs = 0;
    for (int i = 0; i < mutablePicks; i++) {
      Mutable m = chromosome.getRandomMutable();

      if (m instanceof Node) {
        mutableNodes++;
      } else if (m instanceof Output) {
        mutableOutputs++;
      } else {
        fail("Return is neither Node nor Output.");
      }
    }
    System.out.println("Out of " + mutablePicks + " mutable elements picked from " + resources.nodes() +
        " nodes and " + resources.outputs() + " outputs, " + mutableNodes + " were nodes and " +
        mutableOutputs + " were outputs.");
    System.out.println("Node/output ratio: " + (double) resources.nodes() / (double) resources.outputs() +
        ", picked ratio: " + (double) mutableNodes / (double) mutableOutputs + "\n");
  }

  /**
   *
   */
  @Test
  public void getOutputsTest() {
    chromosome = createKnownConfiguration();

    chromosome.setInputs(5, 8, 4);

    Integer output0 = (Integer) chromosome.getOutput(0).calculate();
    Integer output1 = (Integer) chromosome.getOutput(1).calculate();
   
    // with this configuration, the outputs should be 13 and 25.
    assertTrue("Incorrect output returned: " + output0, output0 == 13.0);
    assertTrue("Incorrect output returned: " + output1, output1 == 25.0);
  }

  /**
   *
   */
  @Test
  public void setInputTest() {
    // set input values, check that acquired values are correct
    Integer[] testInputs = new Integer[resources.inputs()];
    for (int i = 0; i < resources.inputs(); i++) {
      testInputs[i] = i * 2 - 3;
    }
    chromosome.setInputs((Object[]) testInputs);
    for (int i = 0; i < resources.inputs(); i++) {
      assertTrue("Incorrect input returned.", ((Integer) chromosome.getInput(i).getValue()) == i * 2 - 3);
    }
  }

  /**
   *
   */
  @Test
  public void getNodeTest() {
    // get all nodes one by one, check that they are all correct
    for (int r = 0; r < resources.rows(); r++) {
      for (int c = 0; c < resources.columns(); c++) {
        assertTrue("Incorrect node returned.", chromosome.getNode(r, c).getColumn() == c &&
            chromosome.getNode(r, c).getRow() == r);
      }
    }
  }

  /**
   *
   */
  @Test
  public void activeNodeTest() {
    // active node detection happens recursively, the user only calls a single method
    // set connections to a known configuration
    chromosome = createKnownConfiguration();
   
    assertTrue("Active node missing from list.", chromosome.getActiveNodes().contains(chromosome.getNode(0, 0)));
    assertTrue("Active node missing from list.", chromosome.getActiveNodes().contains(chromosome.getNode(1, 1)));
    assertTrue("Active node missing from list.", chromosome.getActiveNodes().contains(chromosome.getNode(1, 2)));
   
    chromosome.printNodes();
   
    assertTrue("List has the wrong number of nodes: " + chromosome.getActiveNodes(), chromosome.getActiveNodes().size() == 3);
  }

  /**
   *
   */
  @Test
  public void compareActiveTest() {
    // create a clone of the chromosome, compare active nodes - should return true
    Chromosome c = new Chromosome(chromosome);
    assertTrue("Active nodes did not match.", chromosome.compareActiveGenesTo(c));
    assertTrue("Symmetry not obeyed.", c.compareActiveGenesTo(chromosome));

    // create a new random chromosome, this time they should not match
    c = new Chromosome(resources);
    assertTrue("Active nodes did match.", !chromosome.compareActiveGenesTo(c));
  }

  /**
   *
   */
  @Test
  public void compareTest() {
    // create a clone of the chromosome, compare - should return true
    Chromosome c = new Chromosome(chromosome);
    assertTrue("Chromosomes did not match.", chromosome.compareGenesTo(c));
    assertTrue("Symmetry not obeyed.", c.compareGenesTo(chromosome));

    // create a new random chromosome, this time they should not match
    c = new Chromosome(resources);
    assertTrue("Chromosomes did match.", !chromosome.compareGenesTo(c));
  }
  /**
   * Utility for creating a chromosome of known configuration.
   * Topology is 3x3, with 3 inputs and 2 outputs.
   * Given inputs 5, 8 and 4 outputs should be 13 and 25.
   *
   * Active nodes (r, c): [0, 0], [1, 1], [1, 2]
   *
   * @return the configured chromosome
   */
  private Chromosome createKnownConfiguration() {
    // with a small topology, build a chromosome of known connections and check outputs
    resources.setColumns(3);
    resources.setRows(3);
    resources.setInputs(3);
    resources.setOutputs(2);
    resources.setLevelsBack(3);

    Chromosome c = new Chromosome(resources);

    c.getNode(0, 0).initialise(resources.getFunction(0), c.getInput(0), c.getInput(1));
    c.getNode(1, 1).initialise(resources.getFunction(0), c.getNode(0, 0), c.getInput(1));
    c.getNode(1, 2).initialise(resources.getFunction(0), c.getNode(1, 1), c.getInput(2));

    c.getOutput(0).setSource(c.getNode(0, 0));
    c.getOutput(1).setSource(c.getNode(1, 2));
   
    return c;
  }
}
TOP

Related Classes of jcgp.backend.tests.ChromosomeTests

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.