EvolutionaryComputing Update
At last! I´ve finished the update of the EvolutionaryComputing namespace. I´ve being thinking about this update for a long time, but because all the work involved in moving from Haddd to Jade I didn´t have time to commit to it until this last week.
This objective with this namespace was to get an easy to use yet powerful solution for genetic algorithms and evolutionary strategies. The evolutionary strategies thing was halted because I lacked a gaussian random number generator, but now I´ve got it, so I´ll do some work on it in the upcoming weeks.
The genetic algorithms on the other side, was more or less finished, and even though not many people have use it, the comments from all of them have being pretty good. I myself like the library a lot (well, it´s mine after all ;)).
But even with that, some "dark" points where lurking there: some things I didn´t end to like, some comments from the people that used it, some bugs and some mistakes I realized later after using it.
Some points:
The IChromosome and IPopulation interfaces are pretty useless. After thinking and arguing about this one, I think I was wrong and it´s true that this interfaces are useless, as their implementation is trivial (you can´t hardly implement a List property without using a List as the field, and so on). I think this problem came from the "over-designing and pattern overloading" I´ve experienced in my work for some time (and my lack of real experience). In the end, I´ve decided to eliminate them, if someone wants more capabilities for those classes, just inherit from them.
The Clone method of Chromosome and Population. This one was harder to realize. I´m used to write the Clone method like this:
public object Clone()
{
MemoryStream memory;
BinaryFormatter formater;
object clone;
using (memory = new MemoryStream())
{
//Serialize ourself
formater = new BinaryFormatter();
formater.Serialize(memory, this);
//Move the memory buffer to the start
memory.Seek(0, SeekOrigin.Begin);
//Undo the serialization in the new clone object
clone = formater.Deserialize(memory);
return clone;
}
}
This aproach has several good properties: it´s very easy and it works very well if everything is Serializable. But it has a big drawback: it´s slow as hell. The Serialize call is very slow (browse a little and you´ll see lots of arguments about this subject).
Most times, the Chromosomes are using value types as their type paremeter T. Value types can just be copied, there´s no need to clone them and waste so much time.
//Best scenario, T is a ValueType
if (typeof(T).IsValueType)
{
newChrom = (Chromosome) MemberwiseClone();
newChrom.Genotype.Clear();
for (int i = 0; i < genotype.Count; i++)
newChrom.Genotype.Add(genotype
); return newChrom;
} Other times the type parameter will be a Cloneable class, so we can call it´s clone method. And in the worst case, we just can use the old method (well, the worst case is that the item is not ValueType, Cloneable or Serializable so the method crashes, but I won´t count that one :p).
Calling Activator.CreateInstance(type). I needed to call this method in some places of the code to create new instances of items and make the code generic. This method is very slow and it does too much for my needs, so I decided to use a MemberwiseClone type of method (I have to test this one more, but it seems things go better).
Selection, Scaling, Crossover. This one has several parts. First, in the selection methods that used the scaling operator (RouletteWheelSelection and SUSSelection), the operator was being called in every selection to create the ScalingMapping. Well, that was overkill, you could just call it the first time and use the result for all the selections. That "bug" has being fixed.
But there´s a strange relation in those three operators: all of them are used in the creation of the offsprings population (you scale the parents if needed, select some parents, cross them to create a children, select, cross, select, cross,...). I changed some code from EvolutionaryAlgorithm class and moved it to the SelectionAlgorithm, so now creating the offsprings it´s only a call like:
//Create the offsprings population
offsprings = selection(parents, numberOffsprings);
A cosmetic change that will make that part a little easier (and more in line with the others operators of the namespace).
Well, that´s all. I have to finish the evolutionary strategies crossover and mutation operators, but I think I´ll rest from evolutionary computing a little and move to other things like a tutorial on how to setup Jade for your own projects (it´s not a very intuitive thing), fixing some error messages and adding some contributions from the community to the source code.