-1

I have the following function which is calculating the fitness of each individual in Genetic algorithm. Fitness function is taking very much time so that for each individual in population, it is taking a whole lot of time.

Individual fittest = individuals.get(0);
        for (int i = 0; i < individuals.size(); i++) {
            if (fittest.getFitness() >= getIndividual(i).getFitness()) {
                fittest = getIndividual(i);
            }
        }
        return fittest;

I am trying the following parallel version but it is worse than sequential execution.

return
individuals.parallelStream().min(Comparator.comparing(GeneticAlgorithm::getFitness)).get();

Any help in calculating fitness of different individuals in parallel. Thanks

  • 2
    this will help [Should I always use a parallel stream when possible?](https://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible) – deadshot Mar 28 '21 at 05:34
  • 1
    You have provided no details or numbers about your claims of "taking more time". And you have not asked a specific question. – Basil Bourque Mar 28 '21 at 05:36
  • Does this answer your question? [Should I always use a parallel stream when possible?](https://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible) – Charlie Armstrong Mar 28 '21 at 05:40
  • Thanks for the response. getFitness() function is taking 500-600 millisecond in calculating fitness of one individual. I have 50 individuals in my population and running 100 generations. So it total it is calculating fitness .5 x 50 x 100 seconds on average. So 100 generations are taking one hour approximately. Can you please guide me how can I run the same method using parallel stream. I want to get the individual whose fitness is minimum. – Asad Rehman Mar 28 '21 at 05:41
  • 1
    Using `Comparator.comparing` in this way is recomputing the fitness of each individual every time it does an individual comparison, instead of "saving" the fitness of the current best. – Louis Wasserman Mar 28 '21 at 06:03
  • @LouisWasserman Thanks. Any alternative that can improve the performance? – Asad Rehman Mar 28 '21 at 06:15
  • In `Individual` class, you can calculate fitness whenever setter method of any parameter, affecting fitness formula, gets called. Store it in a field in same class. This way you can do fitness operations faster on lot of people. Only toll would be modifying individual will be little bit slow, but modifications don't happen often. – the Hutt Mar 28 '21 at 06:19
  • @onkarruikar I couldn't get your point. Actually it have to calculate fitness for each new solution. After crossover function, we get new solution so we need their fitness. Similarly after mutation, we also need to calculate newly generated solutions fitness. It would be great if it has some parallel execution. – Asad Rehman Mar 28 '21 at 06:54
  • How do you implement the crossover function and the mutation function? Do they create new `Individual`s or do they change the existing individuals? – Thomas Kläger Mar 28 '21 at 07:23
  • @AsadRehman I've elaborated my suggestion in answer section. – the Hutt Mar 28 '21 at 07:40
  • @ThomasKläger They change the existing individuals. And resultants are of course becomes new individuals. – Asad Rehman Mar 28 '21 at 08:11
  • 1
    @onkarruikar Thank you so much Sir. I am checking this. – Asad Rehman Mar 28 '21 at 08:11

2 Answers2

0

If you take a long time to getFitness(), you should minimize its call.

Individual fittest = individuals.get(0);
int /* or long or double ? */ minFittness = fittest.getFitness();
for (int i = 0; i < individuals.size(); i++) {
    Individual current = getIndividual(i);
    int /* or long or double ? */ currentFitness = current.getFitness();
    if (minFittness >= currentFitness) {
        fittest = current;
        minFittness = currentFitness;
    }
}
return fittest;

This halves the number of calls.

0

Just a suggestion. Refer below code.
In Individual class, store calculated fitness. This way you don't have to calculate it every time. You can calculate fitness whenever setter method of any parameter, affecting fitness formula, gets called.
Also, for each solution you can calculate fitness for all individuals at once in a parallel stream as shown in the code.

public class Test {

    public static void main(String[] args) throws Exception {
        List<Individual> allSpecimens = new ArrayList<>();
        allSpecimens.add(new Individual("a", 50, 4));
        allSpecimens.add(new Individual("b", 45, 3));
        
        //after each solution or mutation run following code
        allSpecimens.stream().parallel().forEach(s -> {
            s.setFitness(GenericAlgorithm.getFitness(s));
        });
        
        //find fittest like this
        //this should be fater now
        Individual fittest  = allSpecimens.stream()
                                .min(Comparator.comparing(Individual::getFitness)).get();
    }
    
    
}

class GenericAlgorithm {
    public static double getFitness(Individual specimen) {
        return specimen.getWeight()/specimen.getHeight();
    }
}

class Individual{
    private String name;
    private int height;
    private int weight;
    
    //cache calculated fitness
    private double fitness;
    
    
    public Individual(String name, int weight, int height) {
        this.name = name;
        this.weight = weight;
        this.height = height;
        //calculate every time you modify a parameter
        //remove this if you calculate fitness on all at once
        this.fitness = GenericAlgorithm.getFitness(this);  
    }
    
    public void setHeightAndWeight(int newHeight, int newWeight) {
        this.height = newHeight;
        this.weight = newWeight;
        //calculate every time you modify a parameter
        this.fitness = GenericAlgorithm.getFitness(this);
    }
    
    public double getFitness(){
        //there is no calculations here 
        //so it is faster now
        return fitness;
    }
    
    public void setFitness(double fitness) {
        this.fitness = fitness;
    }
    
    public int getHeight() {
        return height;
    }

    public String getName() {
        return name;
    }

    public int getWeight() {
        return weight;
    }

}
the Hutt
  • 16,980
  • 2
  • 14
  • 44