packages feed

SimpleEA 0.1.1 → 0.2

raw patch · 3 files changed

+45/−34 lines, 3 filesdep +mersenne-random-pure64PVP ok

version bump matches the API change (PVP)

Dependencies added: mersenne-random-pure64

API changes (from Hackage documentation)

- AI.SimpleEA: runEA :: [Genome a] -> FitnessFunc a -> SelectionFunction a -> RecombinationOp a -> MutationOp a -> StdGen -> [[(Genome a, Fitness)]]
+ AI.SimpleEA: runEA :: [Genome a] -> FitnessFunc a -> SelectionFunction a -> RecombinationOp a -> MutationOp a -> PureMT -> [[(Genome a, Fitness)]]
- AI.SimpleEA: type MutationOp a = Genome a -> Rand StdGen (Genome a)
+ AI.SimpleEA: type MutationOp a = Genome a -> Rand PureMT (Genome a)
- AI.SimpleEA: type RecombinationOp a = (Genome a, Genome a) -> Rand StdGen (Genome a, Genome a)
+ AI.SimpleEA: type RecombinationOp a = (Genome a, Genome a) -> Rand PureMT (Genome a, Genome a)
- AI.SimpleEA: type SelectionFunction a = [(Genome a, Fitness)] -> Rand StdGen [Genome a]
+ AI.SimpleEA: type SelectionFunction a = [(Genome a, Fitness)] -> Rand PureMT [Genome a]
- AI.SimpleEA.Utils: fitPropSelect :: [(a, Fitness)] -> Rand StdGen a
+ AI.SimpleEA.Utils: fitPropSelect :: RandomGen g => [(a, Fitness)] -> Rand g a
- AI.SimpleEA.Utils: randomGenomes :: (Random a, Enum a) => Int -> a -> a -> StdGen -> [Genome a]
+ AI.SimpleEA.Utils: randomGenomes :: (RandomGen g, Random a, Enum a) => Int -> Int -> a -> a -> Rand g [Genome a]
- AI.SimpleEA.Utils: tournamentSelect :: [(a, Fitness)] -> Int -> Rand StdGen a
+ AI.SimpleEA.Utils: tournamentSelect :: [(a, Fitness)] -> Int -> Rand PureMT a

Files

AI/SimpleEA.hs view
@@ -29,8 +29,12 @@ ) where  import Control.Monad.Random+import System.Random.Mersenne.Pure64 +-- | An individual's fitness is simply a number. type Fitness = Double++-- | A genome is a list (e.g. a 'String'). type Genome a = [a]  -- | A fitness functions assigns a fitness score to a genome. The rest of the@@ -41,14 +45,15 @@ -- | A selection function is responsible for selection. It takes pairs of -- genomes and their fitness and is responsible for returning one or more -- individuals.-type SelectionFunction a = [(Genome a, Fitness)] -> Rand StdGen [Genome a]+type SelectionFunction a = [(Genome a, Fitness)] -> Rand PureMT [Genome a]  -- | A recombination operator takes two /parent/ genomes and returns two -- /children/.-type RecombinationOp a = (Genome a, Genome a) -> Rand StdGen (Genome a, Genome a)+type RecombinationOp a = (Genome a, Genome a) -> Rand PureMT (Genome a, Genome a) --- | A mutation operator takes a genome and returns an altered copy of it.-type MutationOp a        = Genome a -> Rand StdGen (Genome a)+-- | A mutation operator takes a genome and returns (a possibly altered) copy+-- of it.+type MutationOp a = Genome a -> Rand PureMT (Genome a)  -- | Runs the evolutionary algorithm with the given start population. This will -- produce an infinite list of generations and 'take' or 'takeWhile' should be@@ -70,7 +75,7 @@   SelectionFunction a ->   RecombinationOp a ->   MutationOp a ->-  StdGen ->+  PureMT ->   [[(Genome a,Fitness)]] runEA startPop fitFun selFun recOp mutOp g =   let p = zip startPop (map (`fitFun` startPop) startPop)@@ -82,7 +87,7 @@   FitnessFunc a ->   RecombinationOp a ->   MutationOp a ->-  Rand StdGen [[(Genome a, Fitness)]]+  Rand PureMT [[(Genome a, Fitness)]] generations !pop selFun fitFun recOp mutOp = do     -- first, select parents for the new generation     newGen <- selFun pop@@ -98,7 +103,7 @@      return $ pop : nextGens -doRecombinations :: [Genome a] -> RecombinationOp a -> Rand StdGen [Genome a]+doRecombinations :: [Genome a] -> RecombinationOp a -> Rand PureMT [Genome a] doRecombinations []      _   = return [] doRecombinations [_]     _   = error "odd number of parents" doRecombinations (a:b:r) rec = do@@ -115,21 +120,24 @@ >import AI.SimpleEA >import AI.SimpleEA.Utils >+>import System.Random.Mersenne.Pure64 >import Control.Monad.Random >import Data.List >import System.Environment (getArgs) >import Control.Monad (unless) -The @numOnes@ function will function as our 'FitnessFunc' and simply returns the number of @1@'s-in the string.+The @numOnes@ function will function as our 'FitnessFunc' and simply returns+the number of @1@'s in the string. It ignores the rest of the population (the+second parameter) since the fitness is not relative to the other individuals in+the generation.  >numOnes :: FitnessFunc Char >numOnes g _ = (fromIntegral . length . filter (=='1')) g  The @select@ function is our 'SelectionFunction'. It uses sigma-scaled, fitness-proportionate selection. 'sigmaScale' is defined in 'SimpleEA.Utils'. By first taking the four-best genomes (by using the @elite@ function) we get elitism, making sure that-maximum fitness never decreases.+best genomes (by using the @elite@ function) we make sure that maximum fitness+never decreases ('elitism').  >select :: SelectionFunction Char >select gs = select' (take 4 $ elite gs)@@ -143,9 +151,9 @@ >                     let newPop = p1:p2:gs' >                     select' newPop -Crossover consists of finding a crossover point along the length of the genomes-and swapping what comes after between the two genomes. The parameter @p@-determines the likelihood of crossover taking place.+Crossover is done by finding a crossover point along the length of the genomes+and swapping what comes after that point between the two genomes. The parameter+@p@ determines the likelihood of crossover taking place.  >crossOver :: Double -> RecombinationOp Char >crossOver p (g1,g2) = do@@ -156,7 +164,8 @@ >           return (take r g1 ++ drop r g2, take r g2 ++ drop r g1) >       else return (g1,g2) -Mutation flips a random bit along the length of the genome with probability @p@.+The mutation operator @mutate@ flips a random bit along the length of the+genome with probability @p@.  >mutate :: Double -> MutationOp Char >mutate p g = do@@ -179,10 +188,9 @@  >main = do >    args <- getArgs->    g <- newStdGen->    let (g1,g2) = split g->    let p = take 100 $ randomGenomes 20 '0' '1' g1->    let gs = take 101 $ runEA p numOnes select (crossOver 0.75) (mutate 0.01) g2+>    g <- newPureMT+>    let (p,g') = runRand (randomGenomes 100 20 '0' '1') g+>    let gs = take 101 $ runEA p numOnes select (crossOver 0.75) (mutate 0.01) g' >    let fs = avgFitnesses gs >    let ms = maxFitnesses gs >    let ds = stdDeviations gs
AI/SimpleEA/Utils.hs view
@@ -19,9 +19,10 @@   , getPlottingData ) where -import Control.Monad (liftM)+import Control.Monad (liftM, replicateM) import Control.Monad.Random import Data.List (genericLength, zip4, sortBy, nub, elemIndices, sort)+import System.Random.Mersenne.Pure64 (PureMT) import AI.SimpleEA  -- |Returns the average fitnesses for a list of generations.@@ -48,12 +49,12 @@           mean    = sum p/len           sqDiffs = map (\n -> (n-mean)**2) p --- |Returns an infinite list of random genomes of length @len@ made of elements--- in the range @[from,to]@-randomGenomes :: (Random a, Enum a) => Int -> a -> a -> StdGen -> [Genome a]-randomGenomes len from to = do-    l <- randomRs (from,to)-    return $ nLists len l+-- |Returns a list of @len@ random genomes who has length @genomeLen@ made of+-- elements in the range @[from,to]@.+randomGenomes :: (RandomGen g, Random a, Enum a) => Int -> Int -> a -> a -> Rand g [Genome a]+randomGenomes len genomeLen from to = do+    l <- replicateM (len*genomeLen) $ getRandomR (from,to)+    return $ nLists genomeLen l     where nLists :: Int -> [a] -> [[a]]           nLists _ [] = []           nLists n ls = take n ls : nLists n (drop n ls)@@ -76,7 +77,7 @@ -- |Fitness-proportionate selection: select a random item from a list of (item, -- score) where each item's chance of being selected is proportional to its -- score-fitPropSelect :: [(a, Fitness)] -> Rand StdGen a+fitPropSelect :: (RandomGen g) => [(a, Fitness)] -> Rand g a fitPropSelect xs = do     let xs' = zip (map fst xs) (scanl1 (+) $ map snd xs)     let sumScores = (snd . last) xs'@@ -84,7 +85,7 @@     return $ (fst . head . dropWhile ((rand >) . snd)) xs'  -- |Performs tournament selection amoing @size@ individuals and returns the winner-tournamentSelect :: [(a, Fitness)] -> Int -> Rand StdGen a+tournamentSelect :: [(a, Fitness)] -> Int -> Rand PureMT a tournamentSelect xs size = do     let l = length xs     rs <- liftM (take size . nub) $ getRandomRs (0,l-1)
SimpleEA.cabal view
@@ -1,7 +1,7 @@ name:               SimpleEA-category:			AI+category:           AI build-type:         Simple-version:            0.1.1+version:            0.2 synopsis:           Simple evolutionary algorithm framework. description:        Simple framework for running an evolutionary algorithm by                     providing selection, recombination, and mutation operators.@@ -11,15 +11,17 @@ author:             Erlend Hamberg maintainer:         ehamberg@gmail.com stability:          experimental-tested-with:        GHC==7.0.1+tested-with:        GHC==7.4.1 homepage:           http://www.github.com/ehamberg/simpleea/ cabal-version:       >=1.6   Library-    build-depends:      base >=4 && < 5, MonadRandom-    ghc-options:        -Wall -fno-warn-name-shadowing -fno-warn-orphans-    exposed-modules:    AI.SimpleEA, AI.SimpleEA.Utils+    build-depends:   base >=4 && < 5,+                     MonadRandom,+                     mersenne-random-pure64 >= 0.2 && < 0.3+    ghc-options:     -Wall -fno-warn-name-shadowing -fno-warn-orphans+    exposed-modules: AI.SimpleEA, AI.SimpleEA.Utils  source-repository head   type:     git