Lab 02: It's Alive!
Please submit this lab to the same Lab2 homework slot,
we will keep adding to it for the next few assignments.
Phase 4: Polish
Once you're done with phase 3, you can work on some finishing touches.
Add the following to the Population class
int getBestIndex()
Return the index of the Individual object with the highest fitness value.
float getBestFitness()
Return the highest fitness value from the population.
float getAvgFitness()
Return the average fitness value of the population.
void drawHighlight(int cols, int rows, int gridSize, int offset, int index, color c)
void drawHighlight(int index, color c)
Draws a rectangle outline around the individual at pop[index], using color c.
5 is a reasonable stroke weight value to use for this.
For each of these, remember to exclude pop[0] in your calculations.
Modify the matingSeason method such that it keeps
the best individual from one generation to the next.
Add the following to the main driver file:
Keep track of the number of generations elapsed.
(reset this value if the population gets ramdomized again).
Each time matingSeason() gets called, print out the following information:
Generation 1
Best fitness: 0.10204082
Avg fitness: 0.04882347
If you like, you can use the nf() function to format your fitness values more nicely
Modify draw to use pop.drawHighlight() to draw a box around the best individual.
You can also draw a box around individual 0 to show that it's the target.
Phase 3: Tuesday 4/5:
We will be adding selection and mating to our genetic algorithm.
We need to create a selection function that will pick random Individuals,
but is more likely to return fitter ones. We will then use this to create a
new generation of Individuals (a new Population) made by mating and mutating randomly selected
Individuals from the previous generation.
Since Individual 0 will be our target, it should be copied over unchanged,
and should not be involved in the mating process.
Add the following methods to your Population class:
Individual select()
Return a randomly selected Individual for the pop array.
Individual objects with higher fitnesses should be more likely to be selected.
We will use the Roulette Wheel Selection algorthm to do this. (see the notes for a detailed explanation).
Make sure that select does not return the 0th Individual object!
You may need to alter how you calculate totalFitness to exclude the 0th individual.
Population matingSeason()
Create a new Population the same size as the current one, do not create random individuals.
Copy over the 0th Individual
Copy over the mutationRate
For all other spots in the new population:
Use select to select 2 current members of the population.
(remember: select() SHOULD NOT return the 0th individual)
Use mate to create a new Individual.
Run mutate on the newly created Individual.
Add the new Individual to the new Population
Return the new Population
Add the following to keyPressed in the main drive file from the previous assignment:
if (key == 'm') {
pop = pop.matingSeason();
pop.setFitness(pop.get(0));
println(pop.totalFitness);
}
Phase 2: Monday 4/4:
To corral your Individuals, create a Population class with the following features:
Individual pop[]: Array of Individual objects that make up the population.
float totalFitness: Combined fitness of all members of the population
float mutationRate: Mutation rate to be used by all Individual objects in the population.
Methods:
Constructor Population(int popSize)
Initialize the instance variables appropriately.
Do not construct any Individual objects, but do instantiate the array.
Set mutationRate to 5%.
void randomPop()
Instantiate a random Individual object to each element in pop.
void drawPopGrid(int cols, int rows, int gridSize, int offset, boolean showFitness)
// Call display on each Individual in pop using the parameters to arrange them in a grid cols x rows large. (this arrangment is the same as in lab 01).
// gridSize is the size of each grid square in pixels
// offset is the gridline width, in pixels
Individual get(int index)
Return the Individual object at pop[index].
void setFitness(Individual target)
Set the fitness value of each Individual object in pop based off of target.
Calculate totalFitness during this process.
Please use this for your driver file:
int POP_COLS = 6;
int POP_ROWS = 5;
int OFFSET = 1;
int POP_SIZE = POP_COLS * POP_ROWS;
int GRID_SIZE = int(pow(2, Individual.SIZE_GENE_LENGTH+1) - 1);
Population pop;
void settings() {
size(POP_COLS*GRID_SIZE + (POP_COLS-1)*OFFSET,
POP_ROWS*GRID_SIZE + (POP_ROWS-1)*OFFSET);
}//settings
void setup() {
pop = new Population(POP_SIZE);
makePopulation();
}//setup
void draw() {
background(255);
pop.drawPopGrid(POP_COLS, POP_ROWS, GRID_SIZE, OFFSET, true);
drawGrid();
}//draw
void keyPressed() {
if (key == 'p') {
makePopulation();
}
}//keypressed
void makePopulation() {
pop.randomPop();
pop.setFitness(pop.get(0));
println("Total fitness: ", pop.totalFitness);
}//makepopulation()
void drawGrid() {
stroke(0);
for (int i=1; i < POP_COLS; i++) {
int x = i * (GRID_SIZE + OFFSET);
line(x, 0, x, height-1);
}//row dividers
for (int i=1; i < POP_ROWS; i++) {
int y = i * (GRID_SIZE + OFFSET);
line(0, y, width-1, y);
}//column dividers
}//drawGrid