Search code examples
javagenetic-algorithmgenetic-programming

Genetic Algorithm Fitness Score Issue


I am trying to write a java program that generates a population of random characters and eventually lands at an inputted string to simulate something like the infinite monkey theorem (https://en.wikipedia.org/wiki/Infinite_monkey_theorem). The issue I am having is as I am testing it, all of the starting population have a fitness level of 0 so nothing gets added to the mating pool during the natural selection process. Here is what the project entails.

Target: the string "Hello"

Mutation Rate: 0.01

Population Max: 100 DNA objects each containing a char[] array for the genes.

Here is my function for calculating the fitness:

public void calcFitness(String target){
        double score = 0.0;
        for(int i = 0; i < this.genes.length; i++){
            if(this.genes[i] == target.charAt(i)){
                score++;
            }
        }
        this.fitness = score/this.genes.length;
    }

I am new to genetic programming and not sure what I am doing wrong, any help would be appreciated and any tips or insight about genetic programming would also be appreciated.

EDIT

Here is the code for the selection process:

 public void naturalSelection(){
        ArrayList<DNA> selection = new ArrayList<>();
        Random rand = new Random();
        String child = "";
        DNA[] newPop = new DNA[popMax];
        for(int i = 0; i < population.length; i++){
            for(int j = 0; j < population[i].getFitness(); j++){
                selection.add(population[i]);
            }
        }
        for(int i = 0; i < selection.size(); i++){
            int parentSelect = rand.nextInt(selection.size());
            DNA parent1 = selection.get(parentSelect);
            child = parent1.split(true);
            parentSelect = rand.nextInt(selection.size());
            DNA parent2 = selection.get(parentSelect);
            child += parent2.split(false);
            newPop[i] = new DNA(child);
        }
        double mutation = rand.nextDouble();
        if(mutation < this.mutationRate){
            this.population = swapMutation(newPop);
            calcFittest();
        }
        else{
            this.population = newPop;
            calcFittest();
        }
    }

Where swap mutation swaps two random chars if mutation occurs.


Solution

  • I would suggest using a fitness function that measures distance from a candidate to the target string. You would then minimise overall fitness instead of maximising.

    To do this:

    public void calcFitness(String target){
        double score = 0.0;
        for(int i = 0; i < this.genes.length; i++){
            score += Math.abs((int)this.genes[i] - (int)target.charAt(i));
        }
        this.fitness = score / this.genes.length;
    }
    

    This should work better because it will differentiate each candidate much better. Without seeing the random string generator you are using it is hard to say but it is likely that the number of possible candidates is astronomical with a very low chance that any of them score a single point with your fitness function.

    Might also be worth pointing out that your code is likely part of a Genetic Algorithm rather than Genetic Programming.

    If you want to improve the selection I would recommend as an easy to program technique Tournament Selection - choose n random individuals from the population and then select the best fitness individual from the n individuals. This gives better candidates a higher chance of being selected than other individuals and has the added bonus that you don't need to calculate fitness for every individual in a population.