/* * File: Genome.java * Author: Justin Basilico * Course: PO CS 152: Neural Networks * Assignment: Final Project * Updated: 2001.12.18 * Created: 2001.12.06 * * Description: * This file contains the Genome class, which is just a wrapper around a * Chromosome and its fitness value so that they can be kept together. * * Copyright: Justin Basilico (2001). */ import java.util.Random; /** * Genome class * * This class implements a Genome, which contains a Chromosome and its fitness * value. The fitness value can be updated by passing a FitnessFunction Object * to the updateFitness() method. The Chromosome in the Genome can also be * modified by the mutate() and crossover() methods, which just call the * corresponding methods on the Chromosome. It also implements methods for * cloning and comparing Genomes so that they can be copied and sorted. The * sorting assumes that the fitness value is being minimized so that a better * Genome has a lower fitness value. * * @author Justin Basilico * @version 2001.12.18 * @see Chromosome * @see FitnessFunction */ public class Genome extends Object implements Cloneable, Comparable { /** chromosome * The Chromosome that is represented by this Genome, whose fitness is * stored in it. */ protected Chromosome chromosome = null; /** fitness * The double fitness value of the Chromosome in this Genome. */ protected double fitness = 0.0; /** * Genome basic constructor * * This constructor takes the Chromosome that is to be represented by this * Genome and sets the fitness to the initial value of 0.0. The fitness * should be updated before anything else is done with the Genome since * 0.0 might be the improper value for the fitness. * * @param chromosome The Chromosome that the Genome will represent. * @see Genome.updateFitness(FitnessFunction) */ public Genome( Chromosome chromosome) // Chromosome to store. { this.chromosome = chromosome; this.fitness = 0.0; } /** * Genome copy constructor * * This constructor takes another Genome and does a shallow-copy of that * Genome, using the same Chromosome and fitness value. For deep copies * of the Genome, use the clone() method. * * @param copy The Genome to copy. * @see Genome.clone() */ public Genome( Genome copy) // Genome to copy. { this.chromosome = copy.chromosome; this.fitness = copy.fitness; } /** * updateFitness * * This method takes a FitnessFunction object and updates the fitness * value stored in this Genome by applying the calculateFitness() method * of the given Object to the Chromosome in this Genome. After storing the * fitness in this Genome, it returns the new fitness value. * * @param function The FitnessFunction to use to calculate the fitness of * the Chromosome in this Genome. * @return The new fitness value for the Chromosome. * @see FitnessFunction * @see FitnessFunction.calculateFitness(Chromosome) */ public double updateFitness( FitnessFunction function) // The fitness function. { // Update the fitness value. fitness = function.calculateFitness(chromosome); return fitness; } /** * mutate * * This method takes a mutation rate per element in a Chromosome and a * Random object and applies a mutation to the Chromosome in this Genome * by calling the Chromosome mutate() method and passing the mutation rate * and Random object. * * Since this Genome may be modified during the mutation, the fitness * should be recalculated for this Genome after the mutation is done * before anything else is done with the fitness. This is done by using * the updateFitness() method. * * @param mutationRate The double mutation rate per element in the * Chromosome. * @param random The Random Object for generating random numbers in the * mutation. * @see Chromosome.mutate(double, Random) * @see Genome.updateFitness(FitnessFunction) */ public void mutate( double mutationRate, // Mutation rate per element. Random random) // Random number generator. { // Mutate the Chromosome. chromosome.mutate(mutationRate, random); } /** * crossover * * This method takes another Genome, a crossover rate per element of the * Chromosome, and a Random object. It applies the crossover to the * Chromosome in this Genome and the given Genome. To do this it just * calls the crossover() method on the Chromosome in this Genome, * passing the other parameters to it. * * Since this Genome and the given one may be modified during the * crossover, the fitness should be recalculated for both Genomes after * the crossover is done before anything else is done with the fitness. * This is done by using the updateFitness() method. * * @param other The other Genome to crossover with. * @param crossoverRate The crossover rate per element of the Chromosome, * as a double. * @param random The Random number generator to use to determine the * crossover. * @see Chromosome.crossover(Chromosome, double, Random) * @see Genome.updateFitness(FitnessFunction) */ public void crossover( Genome other, // Genome to crossover with. double crossoverRate, // Crossover rate per element. Random random) // Random number generator. { // Just use the crossover method for the Chromosomes. chromosome.crossover(other.chromosome, crossoverRate, random); } /** * getChromosome * * This method returns the Chromosome Object that this Genome represents. * * @return The Chromosome Object that the Genome represents. */ public Chromosome getChromosome() { return chromosome; } /** * getFitness * * This function returns the fitness value of this Genome, which is the * fitness value of the Chromosome that the Genome represents. * * @return The double fitness value of the Genome. */ public double getFitness() { return fitness; } /** * compareTo * * This method takes another Object (which must be a Genome) and compares * that Genome to this one. If the fitness of the given Genome is less * than the fitness of this Genome, 1 is returned. If they are equal, * 0 is returned. Otherwise, -1 is returned. * * The reason that this comparison is a reversed is that the fitness * value is being minimized in this implementation, so "better" Genomes * have lower fitness values. * * @param targetObj The Object, which must be a Genome, to compare this * Genome with. * @return 1 if this Genome has a lower fitness, 0 if the fitnesses are * equal, and -1 if this one has a higher fitness. * @see java.lang.Comparable */ public int compareTo( Object targetObj) // Target Genome to compare to. { Genome target = (Genome) targetObj; if ( fitness < target.fitness ) return 1; else if ( fitness == target.fitness ) return 0; else return -1; } /** * clone * * This method takes no arguments and returns a copy of the Genome it is * given. It uses the Chromosome clone method and then copies in the * fitness. * * @return A new Genome that is a deep-copy of this Genome. * @see Chromosome.clone() * @see java.lang.Cloneable */ public Object clone() { Genome result = new Genome((Chromosome) chromosome.clone()); result.fitness = fitness; return result; } }