Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module Main (main) where
- import Data.Char
- import Data.List
- import System.Random
- import Control.Monad
- import Control.Monad.State
- import Data.Function (on)
- targetStr = "Methinks it is like a weasel"
- targetLen = 28
- populationSize = 500
- replaceProbability = 1 / fromIntegral targetLen
- getRandom func
- = do (val, gen') <- liftM func get
- put gen'
- return val
- strDiff :: String -> Int
- strDiff = sum . zipWith (\ a b -> if a == b then 0 else 1) targetStr
- rndString :: State StdGen String
- rndString = replicateM targetLen rndChar
- rndChar :: State StdGen Char
- rndChar = getRandom (randomR (' ', '~'))
- rndMutateChar :: Char -> State StdGen Char
- rndMutateChar input
- = do roll <- getRandom (randomR (0, 1))
- if (roll :: Double) <= replaceProbability then rndChar else
- return input
- rndMutateStr :: String -> State StdGen String
- rndMutateStr = mapM rndMutateChar
- crossoverStrings :: String -> String -> State StdGen String
- crossoverStrings str1 str2
- = mapM
- (\ x ->
- do b <- getRandom random
- return (if b then fst x else snd x))
- (zip str1 str2)
- uniqueRandoms :: Int -> State StdGen [Int]
- uniqueRandoms = go []
- where go acc targetLen
- | length acc == targetLen = return acc
- | otherwise =
- do randVal <- getRandom (randomR (0, populationSize - 1))
- go (if randVal `notElem` acc then randVal : acc else acc) targetLen
- choose a b = fst (if on (<=) snd a b then a else b)
- chooseR a b = fst (if on (>) (snd . snd) a b then a else b)
- withoutCrossover ::[(String, Int)] -> Int -> State StdGen (String, Int)
- withoutCrossover population count
- = do [i1, i2] <- liftM (map (population !!)) (uniqueRandoms 2)
- childStr <- rndMutateStr (choose i1 i2)
- let childDiff = strDiff childStr
- if childDiff == 0 then return (childStr, count) else
- do [r1, r2] <- liftM (map (ap (,) (population !!))) (uniqueRandoms 2)
- let (start, _ : end) = splitAt (chooseR r1 r2) population
- let newPopulation = start ++ ((childStr, childDiff) : end)
- withoutCrossover newPopulation (count + 1)
- withCrossover ::[(String, Int)] -> Int -> State StdGen (String, Int)
- withCrossover population count
- = do [i1, i2, i3, i4] <- liftM (map (population !!)) (uniqueRandoms 4)
- let parentA = choose i1 i2
- let parentB = choose i3 i4
- crossoverStr <- crossoverStrings parentA parentB
- childStr <- rndMutateStr crossoverStr
- let childDiff = strDiff childStr
- if childDiff == 0 then return (childStr, count + 1) else
- do [r1, r2] <- liftM (map (ap (,) (population !!))) (uniqueRandoms 2)
- let (start, _ : end) = splitAt (chooseR r1 r2) population
- let newPopulation = start ++ ((childStr, childDiff) : end)
- withCrossover newPopulation (count + 1)
- main
- = do gen <- newStdGen
- let individuals = replicate populationSize (fst (runState rndString gen))
- let individualFitnesses = map (ap (,) strDiff) individuals
- newStdGen >>= print . fst .
- runState (withoutCrossover individualFitnesses populationSize)
- newStdGen >>= print . fst .
- runState (withCrossover individualFitnesses populationSize)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement