[Haskell-beginners] Genetic algorithm for knapsack problem
Karol Samborski
edv.karol at gmail.com
Mon May 16 09:58:10 CEST 2011
I wrote this for now and it's working pretty well ;)
Any comments?
import AI.SimpleEA
import AI.SimpleEA.Utils
import Control.Monad.Random
import Data.List
import System.Environment (getArgs)
import Control.Monad (unless)
data Item = Item {
mass :: Double,
value :: Double
}
instance Show Item where
show i = "(" ++ show (mass i) ++ "," ++ show (value i) ++ ")"
type Gene = (Bool, Item)
capacity = 10.0
items = [ Item 5.0 0.2
, Item 2.4 0.8
, Item 1.7 1.9
, Item 6.0 0.5
, Item 0.5 0.1
, Item 2.2 1.2
, Item 1.4 7.8
, Item 0.7 1.4
, Item 6.9 0.3
, Item 1.5 0.2
, Item 4.2 0.5
]
genes = [ zip [True, False, True, True, False, True, False, True,
True, True, True ] items
,zip [True, True, False, False, True, True, True, False,
False, True, True ] items
,zip [False, False, False, False, False, False, True, False,
False, True, True ] items
,zip [False, True, False, True, True, True, True, False,
True, True, True ] items
,zip [False, True, False, True, True, False, False, False,
True, False, False] items
]
fitness :: FitnessFunc Gene
fitness g _
| massSum > capacity = 0.0
| otherwise = valSum
where
massSum = foldr (\i s -> s + (mass $ snd i) ) 0.0 $ filter fst g
valSum = foldr (\i s -> s + (value $ snd i) ) 0.0 $ filter fst g
select :: SelectionFunction Gene
select gs = select' (take 4 $ elite gs)
where scaled = zip (map fst gs) (sigmaScale (map snd gs))
select' gs' =
if length gs' >= length gs
then return gs'
else do
p1 <- fitPropSelect scaled
p2 <- fitPropSelect scaled
let newPop = p1:p2:gs'
select' newPop
recombination :: Double -> RecombinationOp Gene
recombination p (g1,g2) = do
t <- getRandomR (0.0, 1.0)
if t < p
then do
r <- getRandomR (0, length g1-1)
return (take r g1 ++ drop r g2, take r g2 ++ drop r g1)
else return (g1,g2)
mutate :: Double -> MutationOp Gene
mutate p g = do
t <- getRandomR (0.0, 1.0)
if t < p
then do
r <- getRandomR (0, length g-1)
return (take r g ++ flipItem (g !! r) : drop (r+1) g)
else return g
where
flipItem (False, i) = (True, i)
flipItem (True, i) = (False, i)
main = do
args <- getArgs
g <- newStdGen
let (g1,g2) = split g
let gs = take 401 $ runEA genes fitness select (recombination
0.75) (mutate 0.01) g2
let fs = avgFitnesses gs
let ms = maxFitnesses gs
let ds = stdDeviations gs
mapM_ print $ zip5 (map head gs) [1..] fs ms ds
unless (null args) $ writeFile (head args) $ getPlottingData gs
Regards,
Karol Samborski
More information about the Beginners
mailing list