Methinks it is like a Weasel

I'm posting this older code example of a simple evolutionary algorithm to get it off my hard drive :)

I've been interested in evolutionary algorithms for a while now with an idea of using them to solve some interesting puzzles (more of that in a later post, honest).

This is the canonical example provided by Richard Dawkins in his book The Blind Watchmaker which attempts to start with a random series of letters of the right length and by random mutation, generates a quote from Act 3 Scene 2 of Hamlet:

HAMLET

Do you see yonder cloud that’s almost in shape of a camel?

POLONIUS

By th' mass, and ’tis like a camel indeed.

HAMLET

Methinks it is like a weasel.

Interfaces


public interface ICrossover<T>
{
    T Mutate(T instance, double rate);
}


public interface IMutator<T>
{
    T Mutate(T instance, double rate);
}

public interface IPopulationFactory<T>
{
    T Create();

    Collection<T> Create(int populationSize);

    Collection<T> CreateFrom(Collection<T> generation);
}

public interface IFitnessScore<T>
{
    int Score(T instance);
}

public interface IMatchesTarget<T>
{
    bool MatchesTarget(T instance);
}

Implementations


public class WeaselMutator : IMutator<string>
{
    private Random _rng;

    public WeaselMutator()
    {
        this._rng = new Random((int)DateTime.Now.Ticks);
    }

    public string Mutate(string current, double rate)
    {
        return String.Join("", from c in current
                               select _rng.NextDouble() <= rate ? _rng.NextCharacter() : c);
    }
}

public class WeaselPopulationFactory : IPopulationFactory<string>
{
    private Random _rng;

    public WeaselPopulationFactory(int length)
    {
        this.Length = length;
        this._rng = new Random((int)DateTime.Now.Ticks);
    }

    private int Length { get; set; }

    public string Create()
    {
        return this._rng.NextString(this.Length);
    }

    public Collection<string> Create(int populationSize)
    {
        throw new NotImplementedException();
    }

    public Collection<string> CreateFrom(Collection<string> generation)
    {
        throw new NotImplementedException();
    }
}

public class WeaselFitnessScore : IFitnessScore<string>, IMatchesTarget<string>
{
    public WeaselFitnessScore(string target)
    {
        this.Target = target;
    }

    public string Target { get; set; }

    public int Score(string current)
    {
        return this.Target.Zip(current, (a, b) => a == b ? 1 : 0).Sum();
    }

    public bool MatchesTarget(string instance)
    {
        return this.Target == instance;
    }
}

Extension Methods


public static class RandomExtensions
{
    public static char NextCharacter(this Random self)
    {
        const string AllowedChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        return AllowedChars[self.Next() % AllowedChars.Length];
    }

    public static string NextString(this Random self, int length)
    {
        return String.Join("", Enumerable.Repeat(' ', length)
            .Select(c => self.NextCharacter()));
    }
}

Events


public class InitialConditionEventArgs<T> : EventArgs
{
    public InitialConditionEventArgs(T initial, int score)
    {
        this.InitialCondition = initial;
        this.Score = score;
    }

    public T InitialCondition { get; set; }

    public int Score { get; set; }
}

public class FitnessProgressEventArgs<T> : EventArgs
{
    public FitnessProgressEventArgs(int attempt, T best, int score)
    {
        this.Generation = attempt;
        this.Best = best;
        this.Score = score;
    }

    public int Generation { get; set; }

    public T Best { get; set; }

    public int Score { get; set; }
}

public class FinalConditionEventArgs<T> : EventArgs
{
    public FinalConditionEventArgs(int attempt, T final, int score)
    {
        this.Generation = attempt;
        this.FinalCondition = final;
        this.Score = score;
    }

    public int Generation { get; set; }

    public T FinalCondition { get; set; }

    public int Score { get; set; }
}

Algorithm


public class GeneticAlgorithm<T>
{
    public event EventHandler<InitialConditionEventArgs<T>> Start;

    public event EventHandler<FitnessProgressEventArgs<T>> Progress;

    public event EventHandler<FinalConditionEventArgs<T>> Finish;

    public IPopulationFactory<T> Population { get; set; }

    public IMatchesTarget<T> TargetMatch { get; set; }

    public IMutator<T> Mutator { get; set; }

    public IFitnessScore<T> FitnessScore { get; set; }

    public GeneticAlgorithm()
    {
        this.PopulationSize = 100;
        this.MutationRate = 0.05;
        this.GenerationLimit = 100;
    }

    public int PopulationSize { get; set; }

    public double MutationRate { get; set; }

    public int GenerationLimit { get; set; }

    public void Run()
    {
        T parent = this.Population.Create();

        if (this.Start != null)
            this.Start(this, new InitialConditionEventArgs<T>(parent, this.FitnessScore.Score(parent)));

        int attempt = 0;

        while (!this.TargetMatch.MatchesTarget(parent) && attempt < GenerationLimit)
        {
            // Create C mutated strings + the current parent.
            var candidates = (from child in Enumerable.Repeat(parent, PopulationSize)
                              select this.Mutator.Mutate(child, MutationRate))
                              .Concat(Enumerable.Repeat(parent, 1));

            // Sort the strings by the fitness function.
            var sorted = from candidate in candidates
                         orderby this.FitnessScore.Score(candidate) descending
                         select candidate;

            // New parent is the most fit candidate.
            parent = sorted.First();

            ++attempt;

            if (this.Progress != null)
                this.Progress(this, new FitnessProgressEventArgs<T>(attempt, parent, this.FitnessScore.Score(parent)));
        }

        if (this.Finish != null)
            this.Finish(this, new FinalConditionEventArgs<T>(attempt, parent, this.FitnessScore.Score(parent)));
    }
}

Main


class Program
{

    static void Main(string[] args)
    {
        GeneticAlgorithm<string> algo = new GeneticAlgorithm<string>
        {
            PopulationSize = 100,
            MutationRate = 0.05,
            GenerationLimit = 100
        };

        string target = "METHINKS IT IS LIKE A WEASEL";

        algo.Mutator = new WeaselMutator();

        var scorer = new WeaselFitnessScore(target);
        algo.FitnessScore = scorer;
        algo.TargetMatch = scorer;

        algo.Population = new WeaselPopulationFactory(target.Length);

        algo.Start += (obj, e) =>
        {
            Console.WriteLine("START:       {0,20} fitness: {1}", e.InitialCondition, e.Score);
        };

        algo.Progress += (obj, e) =>
        {
            Console.WriteLine("     #{0,6} {1,20} fitness: {2}", e.Generation, e.Best, e.Score);
        };

        algo.Finish += (obj, e) =>
        {
            Console.WriteLine("END: #{0,6} {1,20}", e.Generation, e.FinalCondition);
        };

        //const string target = "METHINKS IT IS LIKE A WEASEL";

        algo.Run();

        Console.ReadKey();
    }
}

Using as many interfaces as I have and using generic types may seem a little like overkill but, as I said, I am hoping to complete a project using some alternate implementations for a more interesting purpose. Stay tuned :)