Introduction to Genetic Algorithms


In this assignment, you will work with partially-completed code for a genetic algorithm, adding crossover, selection and mutation operators. You will also implement a fitness function for the n-queens problem and evaluate the effectiveness of these operators and the difficulty of the corresponding problems. While there is not a lot of code to write for this assignment, doing this analysis may take you some time.

In this assignment, you will study the performance of a genetic algorithm at solving three problems of increasing difficulty: the pattern problem, the traveling salesman problem, and the n queens problem. I have provided the bulk of the code for you, but there are a few methods remaining for you to implement.

About the code

This code demonstrates a Pythonic technique known as "mixins". This should be familiar to you if you've used Lisp or Scheme; Java's interface system is somewhat similar.

Mixins take advantage of Python's support for multiple inheritance to "mix in" behavior from several unrelated classes. In our case, we'll use it to deal with one of the common frustrations involving GAs: all the different choices for implementing the algorithm. We will mix in behavior from four different classes: We also need a class to contain the problem knowledge, which includes a fitness function, a method to generate an initial population, and a method to mutate chromosomes. I have provided two of these, along with an abstract base class. This architecture may seem complicated, but it allows us to easily try out different combinations of elitism, crossover and selection mechanisms without editing, recompiling, or generating config files. Instead, we create a mixin that inherits the specific classes whose behavior we want to incorporate. For example, let's suppose we want to solve the "all-ones" problem: find a bitstring with all ones in it. This is easy, but will help us get going.

We start by making a fitness function:
>>> def allOnes(chr) :
     return len([x for x in chr.bitstring if x == '1'])
Now, we create a BitStringProblem. Let's suppose we want each individual to be of length 20.
import BitStringGAProblem
b = BitStringGAProblem.BitStringGAProblem(allOnes,20)
Lastly, we build a solver for this problem. Let's suppose we want to use deterministic elitism, single-point crossover, and roulette selection. We would do:
>>> class mySolver(GA.GA, Elitism.DeterministicElites, Crossover.OnePointStringCrossover, Selector.RouletteSelector):
...     pass
This creates a class called mySolver that "mixes in" the behavior we want. We then create an instance of this class, pass it the problem we want to solve, and run it.
>>> m=mySolver(b)
>>> m.run()
(output omitted)
Run contains a number of optional arguments:

So what code do I need to write, exactly?

You will need to write the following functions / classes: TournamentSelection is pretty striaghtforward; GreedyCrossover is more challenging. (There are some hints in Crossover.py). You might want to get comfortable running the code first and start working on the next question, and then return to this at the end.

What files are provided?

Once I've written the code, then what?

A challenge with GAs is knowing what parameters to use and what methodologies to choose. To address this, you should perform a set of experiments and prepare a report that summarizes your results. You should consider the following problems:

There are lots of potential experiments to perform; rather than explicitly list them all, I have provided some broad guidelines. Within these guidelines, you may choose how to explore the effect of different choices. You may want to focus on the time needed to discover a solution, the quality of the solution found, or both. You are free to modify or extend the code however you like, including adding functionality to capture or log partial results, print out answers, or add additional features. Please include a README that describes any changes you have made.

Suggested Experiments: You may choose to do some or all of these experiments, or others that you find interesting. Quality is more important than quantity; a smaller number of carefully-crafted experiments with clear conclusions is more interesting than a large number of shallow experiments.

What to turn in

You should create a subdirectory in your cs662 subversion directory called assignment4. This directory should contain all of the code used for your experiments (including the code you need to write!)

In addition, this directory should contain a report (in Word or PDF) that describes your experiments. Make sure you include enough detail that your experiments can be replicated (e.g. all relevant paramter settings -- I should be able to use your code to run the same experiments easily by looking at your report). I would strongly recommend including a graph for each experiment. You may use whatever graphing software you like, but please be sure that your graphs are clear and legible. You should also make sure that you explain the results of your experiments. Don't just say "graph 3 shows compares roulette selection and tournament selection" - explain what your conclusions are.

You will be graded on the thoroughness, quality, and presentation of your experiments. Typical ways students are marked down are unclear or incomplete graphs, little or no explanation of results, and a lack of depth in experiments. Perfect English is not expected, but we do need to be able to understand what you are trying to say.

How will this be graded

Half the grade for this assignment will be the code you need to write, half will be for the report that you create.