module Chromosome.ANN (ANN, Layer, Node,
eval,
config,
uniformCross,
averageCross,
mutateRandomize,
mutateShift,
fitnessMSE,
averageMSE,
correctExamples,
randomANN)
where
import GA
import Control.Monad.State.Strict
import List
import Random
type ANN = [Layer]
type Layer = [Node]
type Node = [Double]
config = ChromosomeConfig {
fitness = undefined,
mutate = undefined,
cross = undefined
}
correctExamples :: [([Double],[Double])] -> Double -> ANN -> Double
correctExamples examples tolerance ann =
fromIntegral $ sum $ map (correctExample ann tolerance) examples
correctExample :: ANN -> Double -> ([Double],[Double]) -> Int
correctExample ann tolerance example =
numMatching ((<tolerance) . abs) $
rawError ann example
fitnessMSE :: [([Double],[Double])] -> ANN -> Double
fitnessMSE examples ann = 1.0 / averageMSE ann examples
averageMSE :: ANN -> [([Double],[Double])] -> Double
averageMSE ann examples =
average $ map (mse ann) examples
mse :: ANN -> ([Double],[Double]) -> Double
mse ann examples =
average $ map (^2) $ rawError ann examples
rawError :: ANN -> ([Double], [Double]) -> [Double]
rawError ann (ins, outs) =
zipWith () outs $ eval ins ann
mutateRandomize :: Double -> Double -> ANN -> (GAState ANN p) ANN
mutateRandomize rate range ann =
mapM (mapM (mapM rnd)) ann
where rnd = randWeight False rate range
mutateShift :: Double -> Double -> ANN -> (GAState ANN p) ANN
mutateShift rate range ann =
mapM (mapM (mapM rnd)) ann
where rnd = randWeight True rate range
randWeight :: Bool -> Double -> Double -> Double -> (GAState c p) Double
randWeight shiftp rate range weight = do
test <- gaRand (0.0, 1.0)
if test > rate
then return weight
else do
delta <- gaRand (range, range)
return $ delta + (if shiftp then weight else 0.0)
uniformCross :: ANN -> ANN -> (GAState c p) (ANN,ANN)
uniformCross xsss ysss =
zipWithM (zipWithM (zipWithM pickRandom)) xsss ysss >>=
return . unzip . map unzip . map (map unzip)
averageCross :: ANN -> ANN -> (GAState c p) (ANN,ANN)
averageCross n1 n2 =
let retval = zipWith (zipWith (zipWith avg)) n1 n2
in return (retval, retval)
pickRandom :: a -> a -> (GAState c p) (a,a)
pickRandom x y = do
test <- gaRand (False, True)
if test then return (x,y) else return (y,x)
eval :: [Double] -> ANN -> [Double]
eval input [] = input
eval input (x:xs) =
eval (evalLayer input x) xs
evalLayer :: [Double] -> Layer -> [Double]
evalLayer inputs =
map (evalNode inputs)
evalNode :: [Double] -> Node -> Double
evalNode inputs (bias : weights) =
sigmoid $ bias + dotProduct inputs weights
randomANN :: Int -> [Int] -> Double -> (GAState c p) ANN
randomANN _ [] _ = return []
randomANN i (l:ls) r = do
x <- randomLayer i l r
xs <- randomANN l ls r
return $ x : xs
randomLayer :: Int -> Int -> Double -> (GAState c p) Layer
randomLayer i o range = replicateM o $ randomNode i range
randomNode :: Int -> Double -> (GAState c p) Node
randomNode i range = replicateM (i+1) $ gaRand (range,range)
sigmoid :: Double -> Double
sigmoid x = 1.0 / (1.0 + exp (x))
dotProduct :: [Double] -> [Double] -> Double
dotProduct u v = sum $ zipWith (*) u v
avg x y = (x + y) / 2.0
average xs = sum xs / genericLength xs
numMatching p =
foldl (\acc x -> if p x then acc + 1 else acc) 0