PPaste!

Parallel div conq

Home - All the pastes - Authored by Thooms

Raw version

 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
69
70
71
72
73
74
75
import Data.List
import System.Random
import Criterion.Main
import Control.Monad.Par
import Control.Exception (evaluate)

parDivConq :: NFData b
           => (a -> Bool) -- test if problem is small enough
           -> (a -> [a])  -- or (a -> (a,a)), to split the problem into smaller ones
           -> (a -> b)    -- solver for sequential
           -> ([b] -> b)  -- or ((b,b) -> b), merge sub-solutions ...
           -> a           -- input
           -> Par b
parDivConq smallEnough splitInputs seqSolver merge input =
  if smallEnough input then return (seqSolver input)
  else do
    let ins = splitInputs input
    outs <- parMapM (parDivConq smallEnough splitInputs seqSolver merge) ins
    return $ merge outs

divConq :: NFData b
        => (a -> Bool) -- test if problem is small enough
        -> (a -> [a])  -- or (a -> (a,a)), to split the problem into smaller ones
        -> (a -> b)    -- solver for sequential
        -> ([b] -> b)  -- or ((b,b) -> b), merge sub-solutions ...
        -> a           -- input
        -> b           -- output
divConq smallEnough splitInputs seqSolver merge input =
  runPar $ parDivConq smallEnough splitInputs seqSolver merge input

mergeTwo :: Ord a => [a] -> [a] -> [a]
mergeTwo xs [] = xs
mergeTwo [] ys = ys
mergeTwo (x:xs) (y:ys) =
  if y < x then y : mergeTwo (x:xs) ys
  else x : mergeTwo xs (y:ys)

splitInTwo :: [a] -> ([a], [a])
splitInTwo [] = error "Cannot split two lists"
splitInTwo elements =
  let
    size = length elements
    middle  = size `div` 2
  in
    splitAt middle elements

seqFusionSort :: Ord a => [a] -> [a]
seqFusionSort [] = []
seqFusionSort [x] = [x]
seqFusionSort xs =
  let
    (as, bs) = splitInTwo xs
    sortedA = seqFusionSort as
    sortedB = seqFusionSort bs
  in
    mergeTwo sortedA sortedB

parFusionSort :: (NFData a, Ord a) => Int -> [a] -> [a]
parFusionSort sizeThreshold = divConq smallEnough splitInputs seqFusionSort (foldl mergeTwo [])
  where
    smallEnough :: [a] -> Bool
    smallEnough elements = length elements < sizeThreshold

    splitInputs :: [a] -> [[a]]
    splitInputs elements =
      let (xs, ys) = splitInTwo elements in
        [xs, ys]

main :: IO ()
main = do
  let n = 10^(7 :: Int)
  let elements = (take n (randoms (mkStdGen 211570155)) :: [Int] )
  putStrLn "Begin sort"
  _ <- evaluate $ parFusionSort (10^(6 :: Int)) elements
  putStrLn "Finished sorting."