A year ago, I mentioned that I always write a cGA implementation when I learn a new language. Then, I was trying to get back to fluent in Haskell. A couple of days ago, Martin Pelikan just did the same and wanted to compare implementations. So, what did I do? I looked for my implementation to post it here.
I took a look at the code and change a couple of things, but I can say that the Haskell implementation is the shortest working implementation that I have ever written in any language. It is shorter than the versions I wrote in Scala and Erlang. Python could get awkwardly compressed using some functional flavor to get close to this, but dynamic typing… C, C++, Java, Go and other friends, are far away when you look in the rear Haskell mirror. Anyway, the code below implements cGA for binary strings. You chose the population size, the number of bits, and the evaluation function. Also, some of the constructs are simple and elegant that do not need much explanation (not to mention maintainability…)
import Data.List.Split import System.Random diffBinaryIndividuals popSize ind1 ind2 = map (\ (x, y) -> if x == y then 0 else (2 * x - 1) / popSize) $ zip ind1 ind2 updateBinaryModel f popSize model ind1 ind2 = zipWith (+) model update where f1 = f ind1 f2 = f ind2 update = if f1 > f2 then diffBinaryIndividuals popSize ind1 ind2 else diffBinaryIndividuals popSize ind2 ind1 sampleTwoBinaryIndividuals model gen = chunksOf l $ zipWith (\ m r -> if r < m then 1 else 0) (model ++ model) rnds where rnds = take (2 * l) (randoms gen :: [Float]) l = length model cgaStepForBinaryIndividuals f model popSize gen = updateBinaryModel f popSize model ind1 ind2 where ind1 : ind2 : [] = sampleTwoBinaryIndividuals model gen hasModelConverged model = all (\x -> x > 0.9 || x < 0.1) model cga _ _ model | hasModelConverged model = return model cga f popSize model = do gen <- newStdGen res <- (cga f popSize (cgaStepForBinaryIndividuals f model popSize gen)) return res
And you can see it in action below solving 5-bit and 50-bit OneMax problems.
> cga (sum) 1000 (take 5 $ repeat 0.5) [0.90099484,0.9029948,0.9029948,0.9019948,0.9209946] > cga (sum) 1000 (take 50 $ repeat 0.5) [0.9209946,0.9279945,0.96899396,0.96899396,0.95399415,0.9259945,0.9419943,0.96299404,0.9589941,0.9419943,0.93799436,0.9519942,0.9109947,0.94599426,0.95399415,0.9449943,0.94799423,0.964994,0.9199946,0.93199444,0.9429943,0.9569941,0.95499414,0.96999395,0.9369944,0.9579941,0.96199405,0.9429943,0.96099406,0.9359944,0.967994,0.9209946,0.9449943,0.966994,0.9329944,0.95499414,0.96999395,0.9449943,0.90799475,0.9579941,0.95299417,0.93999434,0.94699425,0.9179946,0.9559941,0.90099484,0.9359944,0.9339944,0.9339944,0.9359944]