Java Library for Genetic Algorithms

int num_chromosomes public Geneticint num_genes_per_chromosome, int num_chromosomes, float crossover_fraction, float mutation_fraction The method sort is used to sort the population of chromosomes in most fit first order. The methods getGene and setGene are used to fetch and change the value of any gene bit in any chromosome. These methods are protected but you will probably not need to override them in derived classes. protected void sort protected boolean getGeneint chromosome, int gene protected void setGeneint chromosome, int gene, int value protected void setGeneint chromosome, int gene, boolean value The methods evolve, doCrossovers, doM utations, and doRemoveDuplicates are utilities for running GA simulations. These methods are protected but you will probably not need to override them in derived classes. protected void evolve protected void doCrossovers protected void doMutations protected void doRemoveDuplicates When you subclass class Genetic you must implement the following abstract method calcF itness that will determine the evolution of chromosomes during the GA sim- ulation. Implement the following method in sub-classes: abstract public void calcFitness; } The class Chromosome represents a bit set with a specified number of bits and a floating point fitness value. 102 class Chromosome { private Chromosome public Chromosomeint num_genes public boolean getBitint index public void setBitint index, boolean value public float getFitness public void setFitnessfloat value public boolean equalsChromosome c } The class ChromosomeComparator implements a Comparator interface and is application specific: it is used to sort a population in “best first” order: class ChromosomeComparator implements ComparatorChromosome { public int compareChromosome o1, Chromosome o2 } The last class ChromosomeComparator is used when using the Java Collection class static sort method. The class Genetic is an abstract class: you must subclass it and implement the method calcF itness that uses an application specific fitness function that you must supply to set a fitness value for each chromosome. This GA library provides the following behavior: • Generates an initial random population with a specified number of bits or genes per chromosome and a specified number of chromosomes in the popu- lation • Ability to evaluate each chromosome based on a numeric fitness function • Ability to create new chromosomes from the most fit chromosomes in the population using the genetic crossover and mutation operations There are two class constructors for Genetic set up a new GA experiment by setting the number of genes or bits per chromosome, and the number of chromosomes in the population. The Genetic class constructors build an array of integers rouletteW heel which is used to weight the most fit chromosomes in the population for choosing the parents 103 of crossover and mutation operations. When a chromosome is being chosen, a ran- dom integer is selected to be used as an index into the rouletteW heel array; the values in the array are all integer indices into the chromosome array. More fit chro- mosomes are heavily weighted in favor of being chosen as parents for the crossover operations. The algorithm for the crossover operation is fairly simple; here is the implementation: public void doCrossovers { int num = intnumChromosomes crossoverFraction; for int i = num - 1; i = 0; i-- { Don’t overwrite the best chromosome from current generation: int c1 = 1 + int rouletteWheelSize - 1 Math.random 0.9999f; int c2 = 1 + int rouletteWheelSize - 1 Math.random 0.9999f; c1 = rouletteWheel[c1]; c2 = rouletteWheel[c2]; if c1 = c2 { int locus = 1+intnumGenesPerChromosome-2 Math.random; for int g = 0; gnumGenesPerChromosome; g++ { if g locus { setGenei, g, getGenec1, g; } else { setGenei, g, getGenec2, g; } } } } } The method doM utations is similar to doCrossovers: we randomly choose chro- mosomes from the population and for these selected chromosomes we randomly “flip” the value of one gene a gene is a bit in our implementation: public void doMutations { int num = intnumChromosomes mutationFraction; for int i = 0; i num; i++ { Don’t overwrite the best chromosome from current generation: int c = 1 + int numChromosomes - 1 Math.random 0.99; 104 int g = int numGenesPerChromosome Math.random 0.99; setGenec, g, getGenec, g; } } We developed a general purpose library in this section for simulating populations of chromosomes that can evolve to a more “fit” population given a fitness function that ranks individual chromosomes in order of fitness. In Section 6.3 we will develop an example GA application by defining the size of a population and the fitness function defined by Equation 6.1.

6.3 Finding the Maximum Value of a Function

We will use the Java library in the last section to develop an example application to find the maximum of the function seen in Figure 6.1 which shows a plot of Equation 6.1 plotted in the interval [0, 10]. While we could find the maximum value of this function by using Newton’s method or even a simple brute force search over the range of the independent variable x, the GA method scales very well to similar problems of higher dimensionality. The GA also helps us to not find just locally optimum solutions. In this example we are working in one dimension so we only need to encode a single variable in a chromo- some. As an example of a higher dimensional system, we might have products of sine waves using 20 independent variables x 1, x2, ..x20. Still, the one-dimensional case seen in Figure 6.1 is a good example for showing you how to set up a GA simulation. Our first task is to characterize the search space as one or more parameters. In general when we write GA applications we might need to encode several parameters in a single chromosome. For example, if a fitness function has three arguments we would encode three numbers in a singe chromosome. In this example problem, we have only one parameter, the independent variable x. We will encode the parameter x using ten bits so we have ten 1-bit genes per chromosome. A good starting place is writing utility method for converting the 10-bit representation to a floating-point number in the range [0.0, 10.0]: float geneToFloatint chromosomeIndex { int base = 1; float x = 0; for int j=0; jnumGenesPerChromosome; j++ { if getGenechromosomeIndex, j { 105 x += base; } base = 2; } After summing up all on bits times their base 2 value, we need to normalize what is an integer in the range of [0,1023] to a floating point number in the approximate range of [0, 10]: x = 102.4f; return x; } Note that we do not need the reverse method We use the GA library from Section 6.2 to create a population of 10-bit chromosomes; in order to evaluate the fitness of each chromosome in a population, we only have to convert the 10-bit represen- tation to a floating-point number for evaluation using the following fitness function Equation 6.1: private float fitnessfloat x { return floatMath.sinx Math.sin0.4f x Math.sin3.0f x; } Table 6.1 shows some sample random chromosomes and the floating point numbers that they encode. The first column shows the gene indices where the bit is “on,” the second column shows the chromosomes as an integer number represented in binary notation, and the third column shows the floating point number that the chromosome encodes. The center column in Table 6.1 shows the bits in order where index 0 is the left-most bit, and index 9 if the right-most bit; this is the reverse of the normal order for encoding integers but the GA does not care: it works with any encoding we use. Once again, GAs work with encodings. “On bits” in chromosome As binary Number encoded 2, 5, 7, 8, 9 0010010111 9.1015625 0, 1, 3, 5, 6 1101011000 1.0449219 0, 3, 5, 6, 7, 8 1001011110 4.7753906 Table 6.1: Random chromosomes and the floating point numbers that they encode Using methods geneT oF loat and f itness we now implement the abstract method calcF itness from our GA library class Genetic so the derived class T estGenetic 106