/* * File: BinaryChromosome.java * Author: Justin Basilico * Course: PO CS 152: Neural Networks * Assignment: Final Project * Updated: 2001.12.18 * Created: 2001.12.06 * * Description: * * Copyright: Justin Basilico (2001). */ import java.util.Random; /** * BinaryChromosome class * * This class implements a Chromosome that is a string (array) of binary * (boolean) values of a specified length. Crossover is implemented by just * randomly crossing over bits in two Chromosomes, assumed to be the same * length. Mutations are done by just flipping bits in the array. * * @author Justin Basilico * @version 2001.12.08 */ public class BinaryChromosome extends Object implements Chromosome { /** length * The length of the chromosome. */ protected int length = 0; /** chromosome * This contains the genetic code for the BinaryChromosome, which is an * array of boolean values of the given length. */ protected boolean[] chromosome = null; /** * BinaryChromosome length constructor * * This constructor takes a length of a BinaryChromosome to create and * creates a Chromosome of that length, setting all bits in it to false. * * @param length The integer length of the BinaryChromosome to create. */ public BinaryChromosome( int length) // Chromosome length. { this.length = length; this.chromosome = new boolean[this.length]; // Set all bits to false. Utilities.setArrayValue(chromosome, false); } /** * BinaryChromosome length, Random constructor * * This constructor takes the length of a BinaryChromosome to create and * a Random object and creates a chromosome string of that length, * randomly setting each bit to true with a probability of 0.5 by using * the given Random object. * * @param length The integer length of the BinaryChromosome to create. * @param random The Random object for randomly deciding which bits * should be true and false, which it does with a probability 0.5. */ public BinaryChromosome( int length, // Chromosome length. Random random) // Random number generator. { this.length = length; this.chromosome = new boolean[this.length]; // Randomize the chromosome. Utilities.randomizeArray(chromosome, random); } /** * BinaryChromosome array constructor * * This method takes an array of booleans and just uses that as the string * for the BinaryChromosome by just setting it directly as the internal * data. It does not copy the given chromosome data. * * @param chromosome The boolean array that contains the genetic code for * the BinaryChromosome. */ public BinaryChromosome( boolean[] chromosome) // Chromosome data. { this.length = chromosome.length; this.chromosome = chromosome; } /** * BinaryChromosome copy constructor * * This constructor takes another BinaryChromosome and initializes this * BinaryChromosome to be a copy of the given one, which does a full copy * of the given one's code. * * @param copy The BinaryChromosome to copy. */ public BinaryChromosome( BinaryChromosome copy) // BinaryChromosome to copy. { this.length = copy.length; this.chromosome = Utilities.copyArray(copy.chromosome); } /** * randomize * * This method takes a double threshold and a Random object and randomizes * this BinaryChromosome by using the Random object and setting each * bit to true if the value returned by nextDouble() is greater than or * equal to the threshold and false otherwise. This totally changes the * BinaryChromosome. * * @param threshold The threshold for setting values true or false. This * is the percentage chance of a single bit for being true. * @param random The Random object to use to randomize the * BinaryChromosome. * @see Utilities.randomizeArray(double[], Random, double) * @see java.util.Random.nextDouble() */ public void randomize( double threshold, // Random random) // Random number generator. { // Randomize the array. Utilities.randomizeArray(chromosome, random, threshold); } /** * crossover * * This method takes another Chromosome object, a crossover rate per * element in the Chromosome, and a Random object. It applies a crossover * to the Chromosome it is called on and the given Chromosome using the * given rate and random number generator. The result of the crossover is * stored in the two Chromosomes that were being crossed over. * * The Chromosome is assumed to be a BinaryChromosome that must have the * same length as this BinaryChromosome. Crossover is done by using the * Random object switch bits in the two Chromosomes with the given * probability for each bit. The two BinaryChromosomes are changed, so * no value is returned. * * @param otherChrom The BinaryChromosome to do the crossover with. * @param crossoverRate The double crossover rate per element in the * Chromosome. * @param random The Random object to do the random number generation * with. * @see java.util.Random */ public void crossover( Chromosome otherChrom, // Chromosome to crossover. double crossoverRate, // Crossover rate per element. Random random) // Random number generator. { BinaryChromosome other = (BinaryChromosome) otherChrom; if ( length != other.length ) { // Error: The two chromosomes do not have the same length. System.err.println("Error: BinaryChromosome.crossOver(): The two " + "BinaryChromosomes do not have the same length."); return; } boolean temp = false; // Go through each bit and randomly swap some between each Chromosome. for (int i = 0; i < length; i++) { if ( random.nextDouble() < crossoverRate ) { // Swap the values in the Chromosomes. temp = chromosome[i]; chromosome[i] = other.chromosome[i]; other.chromosome[i] = temp; } // else - Don't do the swap. } } /** * mutate * * This method takes a mutation rate per element in the Chromosome and a * Random object. It applies mutation to the Chromosome it is called on by * somehow changing the genes in the Chromosome randomly by using the * given values. No value is returned because the Chromosome itself is to * be mutated. * * The mutation is done by going through each bit and randomly flipping * each one with the given probability by using the given Random object. * * @param mutationRate The double mutation rate per element of the * Chromosome. * @param random The Random object to do the random number generation * with. * @see java.util.Random */ public void mutate( double mutationRate, // Mutation rate per element. Random random) // Random number generator. { // Go through each bit and randomly flip them. for (int i = 0; i < length; i++) { if ( random.nextDouble() < mutationRate ) // Flip this Chromosome bit. chromosome[i] = !chromosome[i]; // else - Don't do the bit flip. } } /** * getValue * * This method takes the index of a bit in the BinaryChromosome and * returns the value at that index (true or false). * * @param index The integer index of the value to get from the * Chromosome. * @return The boolean value of the bit in the BinaryChromosome at the * given index. * @throw NullPointerException If the index is less than 0 or greater * than or equal to the length of the BinaryChromosome. * @see BinaryChromosome.getLength() */ public boolean getValue( int index) // Index to get the value of. { return chromosome[index]; } /** * countNumTrue * * This method returns the number of bits in the BinaryChromosome that * are on (1, true). * * @return The integer number of bits in the BinaryChromosome that are * true (1). */ public int countNumTrue() { // Count the number of true bits. int result = 0; for (int i = 0; i < chromosome.length; i++) if ( chromosome[i] ) // This bit is true. result++; // Return the result. return result; } /** * getLength * * This method returns the length of the Chromosome, in terms of how many * bits it contains. * * @return The length of the BinaryChromosome, which is the length of the * string of bits (the boolean array) it was created for. */ public int getLength() { return length; } /** * clone * * This method returns a deep-copy of the BinaryChromosome it is called * on. * * @return A new BinaryChromosome is a deep-copy of this BinaryChromosome. * @see java.lang.Cloneable */ public Object clone() { return new BinaryChromosome(this); } }