Tutorials‎ > ‎

Tutorial 6: Using local genetic algorithm goals

Jenes offers the possibility to use local genetic algorithm goals. The global goal is that used by GeneticAlgorithm during the evolution of the population in its main sequence of stages. Instead, local goal is that used by the single stage (e.g. A sequence contained in a parallel branch, etc..). This tutorials shows how to solve the knapsack problem defining two different parallel sequences with different inner goals. The aim of the knapsack problem is to maximize the total utility of the items within the bag without exceeding the maximum capacity of the bag. We have n items each one with has a footprint and an utility value.

Package:
jenes.tutorial.problem6

Files:
KnapsackProblem.java
KnapsackGA.java

1. Choose a problem suitable chromosome and create the initial population

A candidate solution is a set of items with a weight and a utility. The solutions are coded using a boolean chromosome. The boolean values tells if an item is present or not inside the bag. For example if the i-th gene is true, then the i-th item is in the bag. A chromosome with all the genes having a false value represents an empty bag, while a chromosome with all the genes having a true value represents a bag with all the possible items.
053     public KnapsackGA( int popsize, int generations, double[] utilities, double[] weights) {
054         supernew Population<BooleanChromosome>(new Individual<BooleanChromosome>(new BooleanChromosome(utilities.length)), popsize), generations);

 

2. Set-up the genetic algorithm

We implement the KnapsackGA class by subclassing GeneticAlgorithm and implementing the evaluation method.
097     public double getUtilityOf(Individual<BooleanChromosome> individual) {
098         BooleanChromosome chrom = individual.getChromosome();
099         double utility = 0.0;
100         int size = chrom.length();
101         for(int i = 0; i < size; ++i){
102             utility += chrom.getValue(i) ? this.utilities[i] : 0.0;
103         }
104         return utility;
105     }
106    
107     public double getWeightOf(Individual<BooleanChromosome> individual) {
108         BooleanChromosome chrom = individual.getChromosome();
109         double weight=0.0;
110         int size = chrom.length();
111         for(int i = 0; i < size; ++i){
112             weight += chrom.getValue(i) ? this.weights[i] : 0.0;
113         }
114         return weight;
115     }
116    
117     @Override
118     protected void evaluateIndividual(Individual<BooleanChromosome> individual) {
119         double utility = getUtilityOf(individual);
120         double weight = getWeightOf(individual);
121         individual.setScore(utility);
122         individual.setLegal(weight <= this.capacity);
123     }
The fitness of each solution is equal to the sum of the utilities of the items it contains. If the total weight exceeds the capacity of the bag, then the individual is set as illegal.

3. Choose the operators to be used by genetic algorithm and add them as stages in the ga

We decide to process differently legal and illegal individuals. Therefore we create a sequence, called seq_legal, to process legal individual and a sequence, called seq_illegal, to process illegal individuals. These sequences have the same body ( tournament selector, one point crossover and simple mutator ), but different goals. Infact, the goal of seq_legal is to maximize the fitness of the legal individuals, while that of seq_illegal is to minimize the fitness of the illegal individuals in order to remove excess items and make the individual legal.
We evolve in parallel legal and illegal individuals and at each generation we pass the legal solutions to seq_legal and the illegal solutions to seq_illegal through the use of an exclusive dispenser
.
059         Parallel<BooleanChromosome> parallel =
060                 new Parallel<BooleanChromosome>(new ExclusiveDispenser<BooleanChromosome>(2){
061            
062             @Override
063             public int distribute(Individual<BooleanChromosome> ind) {
064                 return ind.isLegal() ? :1;
065             }
066            
067         });
068        
069         Sequence<BooleanChromosome> seq_legal = new Sequence<BooleanChromosome>();
070         seq_legal.appendStage(new TournamentSelector<BooleanChromosome>(2));
071         seq_legal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));
072         seq_legal.appendStage(new SimpleMutator<BooleanChromosome>(0.02));
073        
074         Sequence<BooleanChromosome> seq_illegal = new Sequence<BooleanChromosome>();
075         seq_illegal.appendStage(new TournamentSelector<BooleanChromosome>(2));
076         seq_illegal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));
077         seq_illegal.appendStage(new SimpleMutator<BooleanChromosome>(0.02));
078        
079         parallel.add(seq_legal);
080         parallel.add(seq_illegal);
081        
082         this.addStage(parallel);
083        
084         seq_legal.setBiggerIsBetter(true);
085         seq_illegal.setBiggerIsBetter(false);

4. Customize the genetic algorithm


To start the evolution KnapsackGA needs the utilities and the weights arrays (both with the same length) and the maximum bag capacity. The code is showed below.
053     public KnapsackGA( int popsize, int generations, double[] utilities, double[] weights) {
054         supernew Population<BooleanChromosome>(new Individual<BooleanChromosome>(new BooleanChromosome(utilities.length)), popsize), generations);
055         
056         this.utilities = utilities;
057         this.weights = weights;
058         
059         Parallel<BooleanChromosome> parallel =
060                 new Parallel<BooleanChromosome>(new ExclusiveDispenser<BooleanChromosome>(2){
061             
062             @Override
063             public int distribute(Individual<BooleanChromosome> ind) {
064                 return ind.isLegal() ? :1;
065             }
066             
067         });
068         
069         Sequence<BooleanChromosome> seq_legal = new Sequence<BooleanChromosome>();
070         seq_legal.appendStage(new TournamentSelector<BooleanChromosome>(2));
071         seq_legal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));
072         seq_legal.appendStage(new SimpleMutator<BooleanChromosome>(0.02));
073         
074         Sequence<BooleanChromosome> seq_illegal = new Sequence<BooleanChromosome>();
075         seq_illegal.appendStage(new TournamentSelector<BooleanChromosome>(2));
076         seq_illegal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));
077         seq_illegal.appendStage(new SimpleMutator<BooleanChromosome>(0.02));
078         
079         parallel.add(seq_legal);
080         parallel.add(seq_illegal);
081         
082         this.addStage(parallel);
083         
084         seq_legal.setBiggerIsBetter(true);
085         seq_illegal.setBiggerIsBetter(false);
086     }