summaryrefslogtreecommitdiffstats
path: root/Evolve.hs
blob: a34a3827e8258044471100d1cfa81c02ea59f85a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
module Evolve (Evolvable, evolve, mutate, score, mutateProbability) where

import qualified System.Random as Random
import Data.List (maximumBy)
import qualified Par
import qualified Control.Monad.State as State
import RandomState (splits)
import Data.Function (on)
import qualified Control.Concurrent.Chan as Chan
import System.Timeout (timeout)
import Control.Exception (evaluate)

class Evolvable e where
  mutate :: Random.RandomGen g => e -> State.State g e
  score :: e -> Double

numChildren :: Int
numChildren = 100

printModCount :: Int
printModCount = 100

scoreTimeout :: Int
scoreTimeout = 1000

mutateProbability :: Double
mutateProbability = 0.005

evolve :: (Evolvable e, Show e) => Chan.Chan e -> e -> IO ()
evolve c e = evolve' 0 c e 0

timeoutScore :: Evolvable e => e -> IO Double
timeoutScore e = maybe (-1) id <$> timeout scoreTimeout (evaluate (score e))

evolve' :: (Evolvable e, Show e) => Int -> Chan.Chan e -> e -> Double -> IO ()
evolve' generation chan startState myScore = do gs <- take numChildren . State.evalState splits <$> Random.newStdGen
                                                childrenScores <- ((myScore, startState) :) <$> Par.mapIO scoreChild gs
                                                let (bestScore, bestChild) = maximumBy (compare `on` fst) childrenScores
                                                if generation `mod` printModCount == 0
                                                  then Chan.writeChan chan bestChild
                                                  else return ()
                                                evolve' (succ generation) chan bestChild bestScore
  where scoreChild g = do let myChild = State.evalState (mutate startState) g
                          realScore <- timeoutScore myChild
                          return (realScore, myChild)