OK, so we can simulate individual genetic loci.  Next we need to group them together into individual members of a population of animals.

The next C# class needed is the individual:

public class Individual

An individual is mainly a data collection.  In this simple example we’re going to use an array of loci to encode an individual’s height:

// Default number of loci in height array
const int arraySize = 10;

// The height array
private Locus[] heightLoci = new Locus[arraySize];

Pretty simple stuff.  We have several options on how do decode this array of loci into a height value.  The simplest is to interpret the loci as additive genes.  The idea is that an ‘a’ locus had no effect on height, while an ‘A’ locus adds 1 unit to the individuals height. This allows us to take the locus’ A_Count property and add them together:

///<summary>
/// Gets the height of this individual.
///</summary>
public int Height
{
    get
    {
        // Add up the A_Count values of the loci in the array.
        int height = 0;
        foreach (Locus l in heightLoci)
        {
            height += l.A_Count;
        }
        return height;
    }
}

We could add other data to the individual; sex, age or additional genetic characteristics could all be added to increase the complexity of the simulation.  I might show examples of this another time, but for now we’ll simply store the array of loci affecting height.

The complexity comes in initialising the individual.  We have to randomly assign a locus value to each locus in the individual. We could go off and read a lot about random number generators, hand-crafting our own one with all the latest random number generation methods.  Or we could just use the one that comes with .NET.

We’ll use the basic one. We’re not trying to prove anything scientific here, just show the basic mechanisms of evolution, so the quality of the random number generator isn’t really worth worrying over.

Because we’re using enums for the locus values, we can simply generate numbers between 0 and 2. We’ll do that in the default constructor:

///<summary>
/// Initializes a new instance of the <see cref="T:Individual"/> class.
///</summary>
///<remarks>Initialises the locus array with random values.</remarks>
public Individual()
{
    // Initialise random loci.
    System.Random rand = new Random();

    for (int i = 0; i < arraySize; i++)
    {
        // Locus is taken as random number from 0 to 2
        locus_enum loc = (locus_enum)rand.Next(3);

        // Store frequency of generated loci.
        switch (loc)
        {
            case locus_enum.aa:
                aaCount++;
                break;
            case locus_enum.aA:
                aACount++;
                break;
            case locus_enum.AA:
                AACount++;
                break;
            default:
                break;
        }

        // Generate new locus in array
        heightLoci[i] = new Locus(loc);
    }
}

The System.Random class will generate random numbers sufficient for our needs. By default it will seed itself with the system time so we don’t need to worry about setting it up, we just create the instance and use it.

Essentially we loop through the locus array, setting the locus value to a random number between 0 and 2. This converts easily to our locus_enum enumerated type.

The switch statement in the middle of the method stores the numbers of each type of generated locus in some static variables in the Individual class.  This allows us to check on them for outrageous errors!

We’ll also use a second constructor to enable us to force a locus array into an individual.  This comes in useful for testing and allows us to force mutations in simulations should we wish to do so.

///<summary>
/// Initializes a new instance of the <see cref="T:Individual"/> class.
///</summary>
///<param name="xLoci">The <see cref="Locus"/> array to use to create the individual.</param>
public Individual(Locus[] xLoci)
{
    // Passed array must be same size as default.
    if (xLoci.Length == arraySize)
    {
        heightLoci = xLoci;
    }
    else
    {
        throw new Exception("Incorrect locus array length in Individual(Locus[])");
    }
}

In the main program, I’ve added some simple code to initialise an array of 1000000 individuals.  This forms a simple population.   I have also added a small assembly with some descriptive statistics code which I then use to display frequency data of the heights in the population.

Individual[] population = new Individual[1000000];
DescriptiveStatistics.Histogram histo = new DescriptiveStatistics.Histogram(0, 20, 1);

for(int i = 0; i < 1000000; i++)
{
    population[i] = new Individual();
    histo.Add(population[i].Height);
}

for (int i = 0; i < histo.BucketCount; i++)
{
    Console.WriteLine("{0}t{1}", histo.LimitForBucket(i), histo.CountForBucket(i));
}

I manually copied these into Excel and came out with the following histogram:

Histogram of population height.

Yes, it’s Normally Distributed.

You can get the sourcecode for this blog entry over at the Channel9 Sandbox.

Next time, I’ll go over a little more theory and then we can start mating individuals together, ready to start simulating evolution.

 

If you’re interested in writing software, check out my other blog: Coding at The Coal Face