{-# LANGUAGE OverloadedStrings #-} import System.Random import System.Environment import Debug.Trace import Data.List import Control.Monad.Par import Control.DeepSeq import Data.Map (Map) import qualified Data.Map as Map -- ---------------------------------------------------------------------------- -- <> -- <> -- <> -- ---------------------------------------------------------------------------- -- The parallel skeleton -- < Maybe solution ) -- <1> -> ( partial -> [ partial ] ) -- <2> -> partial -- <3> -> [solution] -- <4> -- >> -- <> -- < ( partial -> Maybe solution ) -> ( partial -> [ partial ] ) -> partial -> [solution] parsearch finished refine emptysoln = runPar $ generate emptysoln where generate partial | Just soln <- finished partial = return [soln] | otherwise = do solnss <- parMapM generate (refine partial) return (concat solnss) -- >> -- ---------------------------------------------------------------------------- -- <> -- < [Talk] -> Int -> Int -> [TimeTable] timetable people allTalks maxTrack maxSlot = parsearch finished refine emptysoln where emptysoln = (0, 0, [], [], allTalks, allTalks) finished (slotNo, trackNo, slots, slot, slotTalks, talks) | slotNo == maxSlot = Just slots | otherwise = Nothing clashes :: Map Talk [Talk] clashes = Map.fromListWith union [ (t, ts) | s <- people , (t, ts) <- selects (talks s) ] refine (slotNo, trackNo, slots, slot, slotTalks, talks) | trackNo == maxTrack = [(slotNo+1, 0, slot:slots, [], talks, talks)] | otherwise = [ (slotNo, trackNo+1, slots, t:slot, slotTalks', talks') | (t, ts) <- selects slotTalks , let clashesWithT = Map.findWithDefault [] t clashes , let slotTalks' = filter (`notElem` clashesWithT) ts , let talks' = filter (/= t) talks ] -- >> -- ---------------------------------------------------------------------------- -- Utils -- < [(a,[a])] selects xs0 = go [] xs0 where go xs [] = [] go xs (y:ys) = (y,xs++ys) : go (y:xs) ys -- >> -- ---------------------------------------------------------------------------- -- Benchmarking / Testing bench :: Int -> Int -> Int -> Int -> Int -> StdGen -> ([Person],[Talk],[TimeTable]) bench nslots ntracks ntalks npersons c_per_s gen = (persons,talks, timetable persons talks ntracks nslots) where total_talks = nslots * ntracks talks = map Talk [1..total_talks] persons = mkpersons npersons gen mkpersons :: Int -> StdGen -> [Person] mkpersons 0 g = [] mkpersons n g = Person ('P':show n) (take c_per_s cs) : rest where (g1,g2) = split g rest = mkpersons (n-1) g2 cs = nub [ talks !! n | n <- randomRs (0,ntalks-1) g ] main = do [ a, b, c, d, e ] <- fmap (fmap read) getArgs let g = mkStdGen 1001 let (ss,cs,ts) = bench a b c d e g print ss print (length ts) -- [ a, b ] <- fmap (fmap read) getArgs -- print (head (test2 a b)) test = timetable testPersons cs 2 2 where cs@[c1,c2,c3,c4] = map Talk [1..4] testPersons = [ Person "P" [c1,c2] , Person "Q" [c2,c3] , Person "R" [c3,c4] ] test2 n m = timetable testPersons cs m n where cs = map Talk [1 .. (n * m)] testPersons = [ Person "1" (take n cs) ]