Homework 5: evolution

Due Sunday, 21 November, 23:59.

General instructions

In this assignment you will implement evolution in a population of critters, using a genetic algorithm. You will be working with the Genome and Evolver classes. You can submit the two files separately.

Go to the Vincent page for the class to upload the files.

The model

Sensing and acting

As in the last assignment, each critter has the ability to touch all 6 cells around it and to know the texture of these cells. There are four textures: EMPTY, SOFT (for plants), FUZZY (for critters that can't mate), and HARD (for critters that can mate). (There are no rocks in the world we will work with.) Also as in the last assignment, the brain's sense() method returns an array, though this time they are integers, either 0.0 or 1.0. The representation of the sensory input assigns 4 positions in the array to each touchable cell, one position for each of the 4 distinguishable textures, 24 positions in all. The numbers in the array returned by sense() represent the cells around the critter starting from the cell in front of it and moving clockwise around it. So the first 4 numbers represent the cell in front of the critter, the second 4 numbers represent the cell that is 60 degrees clockwise from the critter's heading, etc.

Selecting an action

After calling sense(), the critter chooses an action on the basis of the state that it gets. It makes the decision either randomly (set in the world file or with the "Decide randomly" button) or using the knowledge that is encoded in its genome. When the decision is made according to the genome, it is deterministic, unlike in the Q learning assignments, unless there is a tie.

Each critter has its own genome, corresponding to the memory in the last two assignments. The genome is an array of booleans, representing bits. State positions (cells around the critter), state values (textures), and actions are represented locally in the genome, but states are represented in distributed fashion. That is, each state takes the form of a state value for each state position, and for each of these combinations, the genome specifies values for all possible actions. I'll refer to each value for the association between a state position, state value, and action as a "trait". The default number of possible trait values is 4 (0 to 3), and each of these is represented using two bits in the genome. Thus the length of each genome is (number of state positions) * (number of state values) * (number of actions) * (number of bits per trait). For the default values of each of these quantities given in propDefaults, this is 6 * 4 * 7 * 2 = 336 genes.

Given a particular state returned by the touch sensor, for each possible action the genome provides a value (trait) for each of the state positions (cells). So the value associated with each action in the state is the sum of these values (six of them in the default case), and the "best action" for the state is the action with the highest sum. In case of a tie, the genome randomly picks an action.

As before, the execution of an action results in a reinforcement. If the reinforcement is negative, the action can only be successfully executed if the critter has enough strength to compensate for the reinforcement. The reinforcement is added to the critter's strength, which is not allowed to exceed its initial value (100) or to go below 0.

Evolution

Critters can mate, as well as eat, move, and turn, though, as with eating, mating is not an explicit (selected) action. Critters can be in a "matable" or non-"matable" state. When they are matable, they appear magenta and can be distinguished by touch sensors from non-matable critters. Matable critters can mate with other matable critters. Matability depends on strength (which must be greater than -mateCost) and how recently the critter either mated last or was born (affected by the parameter matingRefractory).

When a matable critter attempts to a cell with another matable critter, mating is initiated (in the Evolver class). The two weakest critters in the population are selected. The genomes of these critters are replaced by the result of applying crossover to the genomes of the mating parents. Mutation is the applied to these new genomes. Finally, reincarnation is completed; the offspring are given the initial settings that new critters get.

The program

This version of the program performs evolution (incomplete until you've done your part) if evolve is true in the world file. Otherwise it performs Q learning using neural nets, as in the last assignment. The documentation for the classes, especially Genome, Evolver, and Utils, should tell you about the methods you need.

In addition, this version of the program has three new kinds of windows to help you see what is going on.

There are also four new buttons. The two buttons at the bottom control whether decisions are made randomly or "intelligently", that is, according to the memory (for learning) or the genome (for evolution) and whether initial genomes are "perfect", that is, specifically designed for optimal actions with a touch sensor, or random (as they should be for evolution). The "Reinitialize" button creates a new population from scratch, using whatever values are in the world file that was loaded when the program was started up, note that the values represented by the two buttons at the bottom have priority over whatever is in the world file. The "Change props" button reloads the values in the world file, without creating a new population. You can use this see how evolved critters fare in a harsher environment.

Specific instructions

Start by downloading the version of the program that you will use for this assignment. Also download the completed program if you want to see how it should work when it is done. Use the world file evol1. You might want to copy it because you will be editing some of the parameters in it.

  1. Fix getBestTrait() in Genome. While working on this method, you will want to set the perfectGenomes parameter to true. (You can either do this in the world file or with the button.) First make sure you are familiar with the other methods in this class; you will need some of them for getBestTrait(). You will also probably need binaryToInt() in Utils. Do not go on to the next part until you are sure this works.
  2. Fix crossover() and mutate() in Evolver. These are both called in mate(), which you don't have to change. Both methods are already there, but they do nothing. Again you will need to call some of the methods in Genome.
  3. The default properties provided in evol1 specify a relatively nasty world that an evolving population of critters normally fails to survive in. However, as you can test, a population that decides randomly can survive. But adjusting some of the parameters in the world file, show how you can create a more benign world in which evolving critters can survive and how you can incrementally change the world to be more and more challenging but also tolerable by your evolving population. In comments at the top of one of your Java files, or in a separate text file, explain how you did this, summarizing the results.

Home

Calendar

Coursework & grading

Assignments

Lecture notes

Other resources


IU home

IU CS home

Contact instructor