forked from nsmryan/HEAL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSelection.hs
68 lines (60 loc) · 1.8 KB
/
Selection.hs
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
{-# LANGUAGE BangPatterns #-}
module Selection (
roulette,
tournament,
elitism,
best,
bestInd,
bestFit,
Min(..),
) where
import EAMonad
import Randomly(nextDouble, nextInt, test, choose, chosen)
import Pairable
import Linear as L
import Control.Monad
import Data.Function
import Data.Foldable as F
import Data.Traversable as Tr
import Control.Applicative as A
newtype Min = Min { unMin :: Double } deriving Eq
instance Show Min where
show (Min d) = show d
instance Ord Min where
compare (Min d) (Min d')
| d == d' = EQ
| d >= d' = LT
| otherwise = GT
-- Roulette Wheel Selection.
roulette :: (Linear p) => p (a, Double) -> EAMonad (p a) e
roulette pop = let sumfit = F.sum $ fmap snd pop in do
ds <- Tr.forM pop $ const (nextDouble sumfit)
return $ fmap (select pop) ds
select v !d | isEmpty v = error $ "No selection, fitness remaining: " ++ show d
| remaining <= 0.00001 = i
| otherwise = select (L.tail v) remaining where
(i, f) = L.head v
remaining = d - f
tournament :: (Pairable p, Linear p, Ord b) => p (a, b) -> EAMonad (p a) e
tournament pop = do
p <- chosen pop
p' <- chosen pop
Tr.mapM compete $ pairup $ p <|> p'
compete ((a, f), (a', f')) = do
b <- test 0.75
return $ if (f >= f') == b then a else a'
-- Best individual.
best :: (Linear p, Ord b) => p (a, b) -> (a, b)
best pop = F.maximumBy (\(_, a) (_, a') -> compare a a') pop
bestInd :: (Linear p, Ord b) => p (a, b) -> a
bestInd pop = fst $ best pop
bestFit :: (Linear p, Ord b) => p (a, b) -> b
bestFit pop = snd $ best pop
-- Elitism.
elitism :: (Linear p, Ord b) =>
(p (a, b) -> EAMonad (p (a, b)) e) -> -- generation
p (a, b) -> -- population
EAMonad (p (a, b)) e
elitism gen pop = do
pop' <- gen pop
return $ update 0 (best pop) pop'