This commit is contained in:
Johannes Merl 2024-04-29 10:41:01 +02:00
parent 17ba14882c
commit 4744920468
3 changed files with 59 additions and 34 deletions

View File

@ -1,3 +1,4 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
@ -52,10 +53,16 @@ main =
execParser optionsWithHelp >>= \opts -> do execParser optionsWithHelp >>= \opts -> do
hSetBuffering stdout NoBuffering hSetBuffering stdout NoBuffering
lEE <- shuffledLEE lEE <- shuffledLEE
let env = lE let cfg = GaRunConfig {
let selType = Tournament 3 enviroment = lE,
let run' = run lEE env selType 120 (5 / 100) (populationSize opts) (steps (iterations opts)) initialEvaluator = lEE,
pop' <- runEffect (for run' logCsv) selectionType = Tournament 3,
termination = (steps (iterations opts)),
poulationSize = (populationSize opts),
stepSize = 120,
elitismRatio = 5/100
}
pop' <- runEffect (for (run cfg) logCsv)
lEE' <- calc lEE pop' lEE' <- calc lEE pop'
let (res, _) = bests lEE' 5 pop' let (res, _) = bests lEE' 5 pop'
let lEE' = lEE {training = False} let lEE' = lEE {training = False}

View File

@ -6,7 +6,11 @@
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-} {-# LANGUAGE TupleSections #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
-- | -- |
-- Module : GA -- Module : GA
-- Description : Abstract genetic algorithm -- Description : Abstract genetic algorithm
@ -20,7 +24,7 @@
-- In order to use it for a certain problem, basically, you have to make your -- In order to use it for a certain problem, basically, you have to make your
-- solution type an instance of 'Individual' and then simply call the 'run' -- solution type an instance of 'Individual' and then simply call the 'run'
-- function. -- function.
module GA (Environment, new, population, mutate, crossover1, crossover, nX, Fitness, getR, Evaluator, fitness,fitness', calc, Individual, GA.run, Tournament (..), N, R, Population, steps, bests, runTests) where module GA (Environment (..), Fitness (..), Evaluator (..), Individual (..), GA.run, Tournament (..), N, R, Population, steps, bests, runTests, GaRunConfig (..)) where
import Control.Arrow hiding (first, second) import Control.Arrow hiding (first, second)
import Data.List.NonEmpty ((<|)) import Data.List.NonEmpty ((<|))
@ -47,7 +51,7 @@ type R = Double
-- | -- |
-- An Environment that Individuals of type i can be created from -- An Environment that Individuals of type i can be created from
-- It stores all information required to create and change Individuals correctly -- It stores all information required to create and change Individuals correctly
class (Pretty e, Individual i) => Environment i e | e -> i where class (Pretty e, Individual i) => Environment i e | e -> i, i -> e where
-- | -- |
-- Generates a completely random individual. -- Generates a completely random individual.
new :: e -> RVar i new :: e -> RVar i
@ -84,7 +88,7 @@ class (Pretty e, Individual i) => Environment i e | e -> i where
-- | -- |
-- An Evaluator that Individuals of type i can be evaluated by -- An Evaluator that Individuals of type i can be evaluated by
-- It stores all information required to evaluate an individuals fitness -- It stores all information required to evaluate an individuals fitness
class (Individual i, Fitness r) => Evaluator i e r | i -> e r where class (Individual i, Fitness r) => Evaluator i e r | e -> i r, i -> e where
-- | -- |
-- An individual's fitness. Higher values are considered “better”. -- An individual's fitness. Higher values are considered “better”.
-- --
@ -212,21 +216,25 @@ selectBest eval pElite pop nPop = do
then return elitists then return elitists
else return $ elitists <> (fst $ bests eval (nPop - length elitists) (NE.fromList rest)) else return $ elitists <> (fst $ bests eval (nPop - length elitists) (NE.fromList rest))
run ::
(Individual i, Evaluator i eval r, Environment i env, SelectionType s) => -- This class encapsulates everything needed to run a generic genetic Algorithm
eval -> data GaRunConfig i r eval env t where
env -> GaRunConfig :: (Individual i, Fitness r, Evaluator i eval r, Environment i env, SelectionType t) => {
-- | Mechanism for selecting parents enviroment :: env,
s -> initialEvaluator :: eval,
-- | Number of parents @nParents@ for creating @nParents@ children selectionType :: t,
N -> termination :: (Termination i),
-- | Elitism ratio @pElite@ poulationSize :: N,
R -> stepSize :: N,
-- | Population size elitismRatio :: R
N -> } -> GaRunConfig i r eval env t
Termination i ->
Producer (Int, r) IO (Population i)
run eval env selectionType nParents pElite nPop term = do run :: GaRunConfig i r eval env t -> Producer (Int, r) IO (Population i)
run config@(GaRunConfig _ _ _ _ _ _ _) = do
let eval = initialEvaluator config
let env = enviroment config
let nPop = poulationSize config
mwc <- liftIO createSystemRandom mwc <- liftIO createSystemRandom
let smpl = ((sampleFrom mwc) :: RVar a -> IO a) let smpl = ((sampleFrom mwc) :: RVar a -> IO a)
firstPop <- liftIO $ smpl $ (population env nPop) firstPop <- liftIO $ smpl $ (population env nPop)
@ -234,12 +242,17 @@ run eval env selectionType nParents pElite nPop term = do
return res return res
where where
runIter eval count pop smpl = ( runIter eval count pop smpl = (
if term pop count if (termination config) pop count
then do then do
return pop return pop
else do else do
let env = enviroment config
let nPop = poulationSize config
let selecType = selectionType config
let nParents = stepSize config
let pElite = elitismRatio config
eval <- liftIO $ calc eval pop eval <- liftIO $ calc eval pop
withKids <- liftIO $ smpl $ reproduce eval env selectionType nParents pop withKids <- liftIO $ smpl $ reproduce eval env selecType nParents pop
eval <- liftIO $ calc eval withKids eval <- liftIO $ calc eval withKids
resPop <- liftIO $ smpl $ selectBest eval pElite withKids nPop resPop <- liftIO $ smpl $ selectBest eval pElite withKids nPop
let fBest = fitness' eval $ NE.head $ fst $ bests eval 1 resPop let fBest = fitness' eval $ NE.head $ fst $ bests eval 1 resPop

View File

@ -48,15 +48,20 @@ main :: IO ()
main = main =
execParser optionsWithHelp >>= \opts -> do execParser optionsWithHelp >>= \opts -> do
hSetBuffering stdout NoBuffering hSetBuffering stdout NoBuffering
let seminarEE = prios let cfg = GaRunConfig {
let env = AssignmentEnviroment (students seminarEE, topics seminarEE) enviroment = AssignmentEnviroment (students prios, topics prios),
let selType = Tournament 3 initialEvaluator = prios,
let run' = run seminarEE env selType 120 (5 / 100) (populationSize opts) (steps (iterations opts)) selectionType = Tournament 3,
pop' <- runEffect (for run' logCsv) termination = (steps (iterations opts)),
seminarEE' <- calc seminarEE pop' poulationSize = (populationSize opts),
let (res, _) = bests seminarEE' 5 pop' stepSize = 120,
seminarEE' <- calc seminarEE' res elitismRatio = 5/100
mapM_ (format seminarEE') res }
pop' <- runEffect (for (run cfg) logCsv)
prios' <- calc prios pop'
let (res, _) = bests prios' 5 pop'
prios' <- calc prios' res
mapM_ (format prios') res
where where
format seminarL s = do format seminarL s = do
let f = fitness' seminarL s let f = fitness' seminarL s