[Haskell-beginners] Randomness woes
Erlend Hamberg
ehamberg at gmail.com
Sun Jan 10 12:25:20 EST 2010
Hello, everyone.
I'm experimenting with making a simple genetic algorithm test in Haskell and
have some questions about how to “propagate” randomness to the various
functions and about how to do the final iteration. I have used MonadRandom
which already have simplified the program quite a bit. The main functions in
my program are:
(Fitness is a Double, Genome is String of ones and zeros)
------------------------------------------------------------------------
-- calculates the fitness of the given genome
fitness :: Genome -> Fitness
-- takes a genome and a list of booleans and flips the bits according to the
-- bool list
mutate :: Genome -> [Bool] -> Genome
-- takes two genomes and swap the genes after the given point
crossOver :: (Genome, Genome) -> Int -> Genome
-- takes two genoms and a mutation rate and returns a new genome
reproduce :: (RandomGen g) => (Genome, Genome) -> Double -> Rand g (Genome)
-- takes a list of genomes and their corresponding fitness and creates a new
-- population by selecting two individuals by roulette wheel selection and
-- create an offspring until the new population is the same size as the
-- original
makePopulation :: (RandomGen g) => [(Genome, Fitness)] -> Rand g [Genome]
-- takes a list of genomes and creates the next generation by using makePop
nextGeneration :: (RandomGen g) => [Genome] -> Rand g [Genome]
-- returns a list of random genomes each with a given number of genes. used to
-- create the initial population
randomGenomes :: (RandomGen g) => Int -> Int -> Rand g [Genome]
-- picks a random element from a list of (a, “score”). elements with a higher
-- score are more likely to be picked
rouletteSelect :: (RandomGen g) => [(a, Double)] -> Rand g a
------------------------------------------------------------------------
I have two concerns about my architecture. The first one is that I have
several “layers” of randomness: The main function will call makePopulation
which in turn will call rouletteSelect and reproduce. The latter will then
call mutate, which also involves randomness. As can be seen above, I have
rewritten mutate to take a list of booleans so that I can use getRandomRs in
reproduce instead of having to have yet another layer of
g <- getSplit
let genome' = evalRand (mutate genome) g
Handling the random generator explicitly like this feels a bit ugly. Or is
this okay?
Calling getSplit and then evalRand recursively is what I do in makePopulation,
to make a new population. I would greatly appreciate comments on how this
“should” be done. I realise that I could just get a list of random numbers in
makePopulation and then use this as a source of randomness for the called
functions, but I fear that this would just lead to inelegant code managing
(chunks of) this list.
My second stumbling point is how to produce a list of successive generations.
I made the following test function to try to achieve this:
generations :: (RandomGen g) => [Genome] -> g -> [[Genome]]
generations pop g =
pop : generations (evalRand (nextGeneration pop) g1) g2
where (g1,g2) = split g
However, it doesn't feel right at all to do it like this. It also seems that
the fitness values of all generations except the first one are identical,
which is a good indication that that approach won't work. :-)
The full program, as it is now, can be found here:
http://hpaste.org/fastcgi/hpaste.fcgi/view?id=15782
The problem the algorithm is trying to solve can be found here:
http://www.ai-junkie.com/ga/intro/gat3.html
I'm grateful for all comments and suggestions, but mainly the two
aforementioned points.
--
Erlend Hamberg
“Everything will be ok in the end. If its not ok, its not the end.”
GPG/PGP: 0xAD3BCF19
45C3 E2E7 86CA ADB7 8DAD 51E7 3A1A F085 AD3B CF19
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
Url : http://www.haskell.org/pipermail/beginners/attachments/20100110/fa9f57cb/attachment.bin
More information about the Beginners
mailing list