Due Wednesday, 2009-02-04
Download
these 9 Python modules and two data files.
You will create a new module, genome.py and will
also edit thing.py and world.py.
Submit all files that you create or edit.
biomorph program
Before running the program, you may have to edit
the first line in biomorph.py so that the path
points to Python 2.5 or 2.6 on your system.
Once this is in place, you should be able to run the program
by doing 'biomorph.py' from within the directory
where the program resides.
If this doesn't work, email me.
The program runs in two modes, depending on what arguments you pass
to biomorph.py.
An argument following -w specifies a "world" in which various things live and die.
An argument following -x specifies an experiment to be run in a neural network.
You will only have to worry about the "world" mode for this assignment.
The argument following -w should be the name of a file in the same directory as the program.
Start with the file evol that is provided.
This file specifies a number of parameters that control how the program is set up and how it runs.
Each is separated by a blank line.
Comments can appear in the file, but don't include equal signs within them.
Any parameter that does not appear in the file gets a default value.
THINGS is a dictionary specifying which things there are in the world and how many of each.
For each type, you can specify an initial number ("init"), a
minimum number ("min"), a maximum number ("max"),
an amount to increase on each time step ("growth").
For Bunnies and Kitties, you can also specify "senses" (see below for possibilities).
For Bunnies, you can also specify whether learning and/or evolution is to take place (but don't change these for this assignment).
Among the strength-related parameters, the only ones you might want to change are INIT_STRENGTH, which is the strength that new Critters (Bunnies and Kitties) start with, and LIFE_EXPECT, which controls the length of the lifetime of Critters.
The reinforcement values control changes in the strength of Bunnies when various things happen.
STEP_COST is the cost of living one time step.MOVE_COST is the cost incurred with a move.STEP_COST is the cost incurred with a turn.BUMP_COST is the cost incurred for bumping into a wall.EAT_COST is the cost incurred for eating (or attempting to eat).CROWDING_COST is the cost incurred for overlapping with another Bunny.CHEWED_COST is the cost incurred when the Bunny is chewed on by a Kitty.REPRO_AGING is how much is added to the Bunny's age when it reproduces.FOOD_VALUE is the proportion of a Veggie's strength that a Bunny gains when it
eats the Veggie.
Three parameters control reproduction.
MATING_REFRACTORY is how many time steps a Bunny has to wait before mating again after it mates with another Bunny.MAX_EXPECTED_CHILDREN controls the probability of mating.MAX_MATE_PROB controls the probability of copying.
The main window of the program displays the current state of the
world and has menus for controlling evolution, the number of steps that
happen when you click on "Run", and some display properties and
buttons for running the network once ("Step") and multiple times
("Run") and for restoring the initial number of each thing ("Reinit").
All of the graphics methods for this window are in world.py.
Since some Tkinter methods are used to calculate sensory input, the
graphics can never actually be turned off completely.
Unless you select "Always update graphics" in the "View" menu,
the display won't update until the end of a run, however.
You probably will not have to worry about any of the code in
world.py, except for the mate() method in World
(see below).
Once you have defined show() in the Genome class (see below), then
selecting "Show Genomes after Run" will cause all of the Genomes to be displayed when a run ends.
The heart of the program is the thing module, which
defines the hierarchy of Thing classes, in particular,
Bunny, Kitty, and Veggie.
Each thing has an associated Tkinter Canvas object,
identified by its id attribute.
Control over the number of things of each type that are created
at the beginning and updated during a run happens via the
values in the THINGS dictionary.
All Orgs have the potential to reproduce themselves, but
this is turned off for Veggies and Kittys
in the current version.
Each Bunny and Kitty has a neural network
(defined in Network.py) that controls how it behaves.
The number of input units is figured on the basis of the sensor(s) the
agent has, and the number of output units is figured on the basis
of the number of possible actions.
Each network consists of two Layers of units.
Clicking on a Bunny or Kitty brings up a window that displays its neural network.
Pressing the mouse on an output unit in this window shows the weights into it from the input
units and the bias unit (displayed in the lower left corner).
On each time step, each Critter calls its attend_state() method, which
generates input from its sensor(s) (defined in Sense.py).
By default Bunnies start with two sensors, a Touch sensor that records whether something is
in a narrow region around it, and a Feel sensor, a sort of whisker that sticks out its mouth and tells it what is directly in front of it.
Each of these sensors can detect four "textures" (those of Veggies, Walls, Bunnies, and Kitties), and the presence or absence of these values is passed to the neural network input layer (8 units).
Kittys have a Smell sensor, which can detect the presence of three "smells" within a large region around it (those of Kitties, Veggies, and Bunnies; Walls don't smell).
You can see what regions the sensors respond to by selecting "Show senses" in the "View" menu.
Bunnies and Kitties select an action stochastically on the basis of their sensory input;
that is, the activations of the output units of their neural networks are treated as probabilities.
Bunnies have four possible actions: move, turn, hide, and
eat; Kitties have all of these except hide.
Moving is a move in the direction of the Critter's heading with a magnitude that is proportional to its strength.
Turning is a 60° rotation in a clockwise or counterclockwise direction; the direction is selected randomly.
All of the actions are methods in the Critter class.
An eat action succeeds if the food item belongs to the right class (Veggie for Bunnies, Bunny for Kitties, and the food item is within a small radius of the end of the Critter's mouth.
The neural network of Kitties is hard-wired so that they behave "smartly": eating when they smell Bunnies, turning or moving otherwise.
All Orgs have a genome attribute, assigned
in the method set_genome.
This defaults to None, and you will have to change it
in the Bunny class to implement evolution.
Bunnies can reproduce in two ways, through copying
and mating.
Which happens is controlled by the "Evolve" menu.
Selecting "No reproduction" causes no reproduction at all to take place.
Selecting "Copy without evolving" causes copying of Bunnies to take place,
but the new genomes are generated randomly.
Selecting "Evolve by copying" causes causes copying of Bunnies to take place,
and the new genomes are copies of the old (with mutation).
Selecting "Evolve by mating" causes mating of Bunnies to take place,
and the genomes of the offspring are created from their parent's genomes through
crossover.
(Evolutionary) copying should copy the parent genome and mutate it.
This already happens in the copy() method in the Bunny
class; you don't have to edit it.
Mating should produce two offspring from two parents, applying
crossover to produce the new genomes.
This happens in the mate() method in the World class.
You will have to edit this method.
When you run the world, some statistics are displayed in the shell, including the mean and maximum strengths for each type of Thing after every 100 time steps (though these numbers will only be of interest for Bunnies).
genome.py, define the
Genome class.
This must at least have an __init__() method that takes a critter as its single argument (in addition to self),
an initialize() method that sets the length of the
genome and assigns initial random values,
a copy() method that yields a new Genome
that is a copy of this one with random bits mutated,
and a show() method that displays the genome.
All of these methods are called in thing.py or
world.py.
You will also need a way to assign the weights and biases in the neural network from the values in the genome.
The Network class has two methods you will probably want to use:
get_n_weights() and assign_weights().
You will also need to uncomment the from genome import *
line in thing.py
and the line in the __init__ method for Bunny
that assigns the genome attribute to a new instance
of Genome.
mate() in world.py so that it does the
right thing.
THINGS dictionary creates a relatively world in which the number of Bunnies and Veggies is fixed and there are not Kitties.
Given this world and the other values in evol,
show that evolution with reproduction by copying exhibits significant improvement over no evolution
and tha evolution by mating exhibits some improvement over no evolution
(considering either mean strength or maximum strength or both).
INIT_STRENGTH, to make things "easier" for the Bunnies.
If so, explain what settings you used.