edenskel-2.0.0.0: Control/Parallel/Eden/Map.hs
{-# LANGUAGE CPP, ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : Control.Parallel.Eden.Map
-- Copyright : (c) Philipps Universitaet Marburg 2009-2014
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : eden@mathematik.uni-marburg.de
-- Stability : beta
-- Portability : not portable
--
-- This Haskell module defines map-like skeletons for
-- the parallel functional language Eden.
--
-- Depends on GHC. Using standard GHC, you will get a threaded simulation of Eden.
-- Use the forked GHC-Eden compiler from http:\/\/www.mathematik.uni-marburg.de/~eden
-- for a parallel build.
--
-- Eden Group ( http:\/\/www.mathematik.uni-marburg.de/~eden )
module Control.Parallel.Eden.Map (
-- * Custom map skeletons
-- | These skeletons expose many parameters to the user and thus have varying types
parMap, ranch,
farm, farmS, farmB,
offlineFarm, offlineFarmS, offlineFarmB,
-- * Custom map skeletons with explicit placement
-- | Map skeleton versions with explicit placement
parMapAt, ranchAt, farmAt, offlineFarmAt,
-- * Simple map skeleton variants
-- | The map skeletons 'farm' and 'offlineFarm' can be used to define
-- skeletons with the simpler sequential map interface :: (a -> b) -> [a] -> [b]
mapFarmB, mapFarmS, mapOfflineFarmS, mapOfflineFarmB,
-- * Deprecated map skeletons
-- | These skeletons are included to keep old code alive. Use the skeletons above.
farmClassic, ssf, offline_farm, map_par, map_farm, map_offlineFarm, map_ssf
) where
#if defined( __PARALLEL_HASKELL__ )
import Control.Parallel.Eden
#else
import Control.Parallel.Eden.EdenConcHs
#endif
import Control.Parallel.Eden.Auxiliary
import Data.List
-- | Basic parMap Skeleton - one process for each list element. This version takes
-- places for instantiation on particular PEs.
parMapAt :: (Trans a, Trans b) =>
Places -- ^places for instantiation
-> (a -> b) -- ^worker function
-> [a] -- ^task list
-> [b] -- ^result list
parMapAt pos f tasks = spawnAt pos (repeat (process f)) tasks
-- | Basic parMap Skeleton - one process for each list element
parMap :: (Trans a, Trans b) =>
(a -> b) -- ^worker function
-> [a] -- ^task list
-> [b] -- ^result list
parMap = parMapAt [0]
-- | A process ranch is a generalized (or super-) farm. This version takes
-- places for instantiation. Arbitrary input is transformed into a list of inputs
-- for the worker processes (one worker for each transformed value). The worker
-- inputs are processed by the worker function.
-- The results of the worker processes are then reduced using the reduction function.
ranchAt :: (Trans b, Trans c) =>
Places -- ^places for instantiation
-> (a -> [b]) -- ^input transformation function
-> ([c] -> d) -- ^result reduction function
-> (b -> c) -- ^worker function
-> a -- ^input
-> d -- ^output
ranchAt pos transform reduce fs xs =
reduce $ spawnAt pos (repeat $ process fs) (transform xs)
-- | A process ranch is a generalized (or super-) farm. Arbitrary input
-- is transformed into a list of inputs for the worker processes (one worker
-- for each transformed value). The worker inputs are processed by the worker function.
-- The results of the worker processes are then reduced using the reduction function.
ranch :: (Trans b, Trans c) =>
(a -> [b]) -- ^input transformation function
-> ([c] -> d) -- ^result reduction function
-> (b -> c) -- ^worker function
-> a -- ^input
-> d -- ^output
ranch = ranchAt [0]
-- | A farm distributes its input to a number of worker processes.
-- This version takes places for instantiation.
-- The distribution function divides the input list into
-- sublists - each sublist is input to one worker process, the
-- number of worker processes is determined by the number of
-- sublists. The results of the worker processes are
-- then combined using the combination function.
--
-- Use 'map_farm' if you want a simpler interface.
--
farmAt :: (Trans a, Trans b) =>
Places -- ^places for instantiation
-> ([a] -> [[a]]) -- ^input distribution function
-> ([[b]] -> [b]) -- ^result combination function
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
farmAt pos distr combine f tasks = ranchAt pos distr combine (map f) tasks
-- | A farm distributes its input to a number of worker processes.
-- The distribution function divides the input list into
-- sublists - each sublist is input to one worker process, the
-- number of worker processes is determined by the number of
-- sublists. The results of the worker processes are
-- then combined using the combination function.
--
-- Use 'mapFarmS' or 'mapFarmB' if you want a simpler interface.
--
farm :: (Trans a, Trans b) =>
([a] -> [[a]]) -- ^input distribution function
-> ([[b]] -> [b]) -- ^result combination function
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
farm = farmAt [0]
-- | Like the 'farm', but uses a fixed round-robin distribution of tasks.
farmS :: (Trans a, Trans b)
=> Int -- ^number of processes
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
farmS np = farm (unshuffle np) shuffle
-- | Like the 'farm', but uses a fixed block distribution of tasks.
farmB :: (Trans a, Trans b)
=> Int -- ^number of processes
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
farmB np = farm (splitIntoN np) concat
-- | Offline farm with explicit placement (alias self-service farm or
-- direct mapping): Like the farm, but tasks are evaluated inside the
-- workers (less communication overhead). Tasks are mapped inside each
-- generated process abstraction, avoiding evaluating and sending
-- them. This often reduces the communication overhead because
-- unevaluated data is usually much smaller than evaluated data.
--
-- Use 'map_offlineFarm' if you want a simpler interface.
--
-- Notice: The task lists structure has to be completely defined
-- before process instantiation takes place.
--
offlineFarmAt :: Trans b =>
Places -- ^places for instantiation
-> Int -- ^number of processes
-> ([a] -> [[a]]) -- ^input distribution function
-> ([[b]] -> [b]) -- ^result combination function
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
offlineFarmAt pos np distribute combine f xs
= combine $ spawnAt pos (map (rfi (map f)) [select i xs | i <- [0 .. np-1]])
(repeat ())
where select i xs = (distribute xs ++ repeat []) !! i
-- | Offline farm (alias direct mapping): Like the farm, but
-- tasks are evaluated inside the workers (less communication
-- overhead). Tasks are mapped inside each generated process
-- abstraction avoiding evaluating and sending them. This often
-- reduces the communication overhead because unevaluated data is
-- usually much smaller than evaluated data.
--
-- Use 'map_offlineFarm' if you want a simpler interface.
--
-- Notice: The offline farm receives the number of processes to be created
-- as its first parameter.
-- The task lists structure has to be completely defined
-- before process instantiation takes place.
--
offlineFarm :: Trans b =>
Int -- ^number of processes
-> ([a] -> [[a]]) -- ^input distribution function
-> ([[b]] -> [b]) -- ^result combination function
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
offlineFarm = offlineFarmAt [0]
-- | Like the 'offlineFarm', but with fixed round-robin distribution of tasks.
offlineFarmS :: (Trans a, Trans b)
=> Int -- ^number of processes
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
offlineFarmS np = offlineFarm np (unshuffle np) shuffle
-- | Like the 'offlineFarm', but with fixed block distribution of tasks.
offlineFarmB :: (Trans a, Trans b)
=> Int -- ^number of processes
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
offlineFarmB np = offlineFarm np (splitIntoN np) concat
------------------------------------------------------------------------------------
numProc = max (noPe-1) 1
-- | Parallel map variant with map interface using (max (noPe-1) 1) worker processes. Skeletons ending on @S@ use round-robin distribution, skeletons ending on @B@ use block distribution of tasks.
mapFarmS, mapFarmB, mapOfflineFarmS, mapOfflineFarmB :: (Trans a , Trans b) =>
(a -> b) -- ^worker function
-> [a] -- ^task list
-> [b] -- ^result list
mapFarmS = farmS numProc
mapFarmB = farmB numProc
mapOfflineFarmS = offlineFarmS numProc
mapOfflineFarmB = offlineFarmB numProc
-----------------------------DEPRECATED---------------------------------
-- | Deprecated, use the 'farm';
-- @farmClassic@ distributes its input to a number of worker processes.
-- This is the Classic version as described in the Eden standard reference
-- "Parallel Functional Programming in Eden".
-- The distribution function is expected to divide the input list into
-- the given number of sublists. In the new farm the number of sublists is
-- determined only by the distribution function.
--
-- Use 'map_farm' if you want a simpler interface.
{-# DEPRECATED farmClassic "better use farm instead" #-}
farmClassic :: (Trans a, Trans b) =>
Int -- ^number of child processes
-> (Int -> [a] -> [[a]]) -- ^input distribution function
-> ([[b]] -> [b]) -- ^result combination function
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
farmClassic np distribute = farm $ distribute np
-- | Deprecated, use 'offlineFarm';
-- Self service farm. Like the farm, but
-- tasks are evaluated in the workers (less communication overhead).
-- This is the classic version. The distribution function is expected
-- to divide the input list into the given number of sublists. In the
-- new self service farm the number of sublists is determined only by
-- the distribution function.
--
-- Use 'map_ssf' if you want a simpler interface.
--
-- Notice: The task lists structure has to be completely defined
-- before process instantiation takes place.
{-# DEPRECATED ssf "better use offlineFarm instead" #-}
ssf :: forall a b . Trans b =>
Int -- ^number of child processes
-> (Int -> [a] -> [[a]]) -- ^input distribution function
-> ([[b]] -> [b]) -- ^result combination function
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
ssf np distribute = offlineFarm np (distribute np)
-- | Deprecated: Same as 'offlineFarm'.
{-# DEPRECATED offline_farm "better use offlineFarm instead" #-}
offline_farm :: Trans b =>
Int -- ^number of processes
-> ([a] -> [[a]]) -- ^input distribution function
-> ([[b]] -> [b]) -- ^result combination function
-> (a -> b) -- ^mapped function
-> [a] -- ^input
-> [b] -- ^output
offline_farm = offlineFarm
-- | Deprecated: Same as 'parMap'.
{-# DEPRECATED map_par "better use parMap instead" #-}
map_par :: (Trans a , Trans b) =>
(a -> b) -- ^worker function
-> [a] -- ^task list
-> [b] -- ^result list
map_par = parMap
-- | Deprecated: Parallel map variants with map interface using noPe worker processes.
{-# DEPRECATED map_farm, map_offlineFarm, map_ssf "better use mapFarmS or mapOfflineFarmS instead" #-}
map_farm, map_offlineFarm, map_ssf :: (Trans a , Trans b) =>
(a -> b) -- ^worker function
-> [a] -- ^task list
-> [b] -- ^result list
map_farm = farmS noPe
map_offlineFarm = offlineFarmS noPe
map_ssf = map_offlineFarm