Parallelizing evaluation and pointwise addition of lists - haskell
I have the following code:
normalHands :: [[[Char]]]
normalHands = -- a very long list
sevenHeads :: [[[Char]]]
sevenHeads = -- a very long list
countYakus :: [Int]
countYakus = foldr countYaku [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] (normalHands ++ sevenHeads) where
countYaku hand [p,oP,dT,aS,cS,fS,sO,cF,cT,dM,aO,tOAK,tP,sT,sF,f] =
-- involves pointwise addition of lists. The length of the accumulator is not changed.
How should I parallelize this? I tried the following:
import Control.Concurrent
import Control.Concurrent.QSem
import Control.Monad
import Data.List
--...
main :: IO ()
main = let
[pinfu, onePair, dragonTriplet, allSimples,
colorfulSequences, fullSequence, semiOrphans, concealedFour, colorfulTriplets, dragonsMinor, allOrphans, threeOfAKind,
twoPairs, semiTerminals, semiFlush, flush] = countYakus
in do
qSem <- newQSem 0
forkIO $ putStrLn ("0: " ++ show pinfu ++ ' ' : show onePair) >> signalQSem qSem
forkIO $ putStrLn ("1: " ++ show dragonTriplet ++ ' ' : show allSimples) >> signalQSem qSem
forkIO $ putStrLn ("2: " ++ show colorfulSequences ++ ' ' : show fullSequence) >> signalQSem qSem
forkIO $ putStrLn ("3: " ++ show semiOrphans ++ ' ' : show concealedFour) >> signalQSem qSem
forkIO $ putStrLn ("4: " ++ show colorfulTriplets ++ ' ' : show dragonsMinor) >> signalQSem qSem
forkIO $ putStrLn ("5: " ++ show allOrphans ++ ' ' : show threeOfAKind) >> signalQSem qSem
forkIO $ putStrLn ("6: " ++ show twoPairs ++ ' ' : show semiTerminals) >> signalQSem qSem
forkIO $ putStrLn ("7: " ++ show semiFlush ++ ' ' : show flush) >> signalQSem qSem
sequence_ $ replicate 8 (waitQSem qSem)
I compiled this with -O2 +RTS -N8, but despite I have 8 cores, my system monitor clearly shows that this code is being run in only one core. I guess it's because of normalHands ++ sevenHeads. So what is the correct way to parallelize this?
EDIT: Exploiting the associativity and commutativity of pointwise addition, I tried this:
countYakus :: [[[Char]]] -> [Int]
countYakus = foldl' countYaku [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] where
-- ...
divideList :: Int -> [a] -> [[a]]
divideList 0 _ = []
divideList n xs = let
(ys,zs) = splitAt n xs
in if null zs
then coZip ys (replicate n [])
else coZip ys (divideList n zs)
where
coZip :: [a] -> [[a]] -> [[a]]
coZip [] yss = yss
coZip (x:xs) (ys:yss) = (x:ys) : coZip xs yss
main :: IO ()
main = do
acc <- newIORef [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
mapM_ (\hands -> forkIO . atomicModifyIORef' acc $ \cs -> (zipWith (+) cs $ countYakus hands, ())) $ divideList 8 (normalHands ++ sevenHeads)
cs <- readIORef acc
mapM_ (putStrLn . show) cs
But it still runs only on one core.
EDIT 2: I tried using MVar:
main :: IO ()
main = do
acc <- newIORef [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
mVar <- newEmptyMVar
mapM_ (\hands -> forkIO $ putMVar mVar (countYakus hands)) $ divideList 8 (normalHands ++ sevenHeads)
replicateM_ 8 $ do
xs <- takeMVar mVar
ys <- readIORef acc
writeIORef acc (zipWith (+) xs ys)
cs <- readIORef acc
mapM_ (putStrLn . show) cs
But it still runs on only one core.
Related
What's preventing IO flush in my code?
I tried solving this, and the following is trial stuff. When I test this in ghci with hSetBuffering stdout NoBuffering, solveAct 1, 15 10, ghci showed few lines of results and blocked much time, and showed rest result at once. How can I see the intermediate results in real time? import Control.Monad import Data.List import Data.Maybe import System.IO readInts = fmap read . words <$> getLine :: IO [Int] main = do t <- readLn :: IO Int hSetBuffering stdout NoBuffering sequence_ $ solveAct <$> [1..t] showTable x = intercalate "\n" $ intercalate " " . fmap show <$> x solveAct i = do [j, n] <- readInts putStrLn $ "Case #" ++ show i ++ ":" putStrLn $ showTable (take n $ solve (j-1)) digits n = [[x ^ y | y <- [1..n-1]] | x <- [2..10]] primes = 2 : [x | x <- [3,5..], all (\y -> x `rem` y /= 0) $ takeWhile (<= intSqrt x) primes] intSqrt = floor . sqrt . fromIntegral getNDivisor n = listToMaybe [x | x <- takeWhile (<= intSqrt n) primes, n `rem` x == 0] casesOfMat = subsequences . transpose . digits casesOfJam n = fmap ([1 + x^n | x <- [2..10]]:) $ casesOfMat n eachBaseReps n = fmap sum . transpose <$> casesOfJam n solve :: Int -> [[Int]] solve n = do decimals <- eachBaseReps n let divs = getNDivisor <$> decimals guard $ all isJust divs return $ last decimals : catMaybes divs
You are seeing the results in real time. It's just that the computation of all isJust . map getNDivisor takes a long time for the third element of eachBaseReps 14.
Error in recursive function / trying to find all subdirectories of a given directory
I'm trying to write a function that returns all subdirectories of a given directory (recursive). What I have so far is: import System.Directory import Control.Monad import Data.List getSubDirs :: FilePath -> IO [FilePath] getSubDirs dir = getDirectoryContents dir >>= filterM (\x -> return $ x /= "." && x /= "..") >>= mapM (makeAbsolute . (\x -> dir ++ "/" ++ x)) >>= filterM doesDirectoryExist >>= return . reverse getDirTree :: [FilePath] -> IO [FilePath] getDirTree [] = return [] getDirTree l#(x:xs) = do a <- getSubDirs x >>= getDirTree b <- getDirTree xs return (nub $ l ++ a ++ b) Which seems to work. But there is something wrong with the recursion - I would like to get rid of the nub in getDirTree.
This looks wrong: getDirTree l#(x:xs) = do -- ... b <- getDirTree xs return (nub $ l ++ a ++ b) The last line adds l which is x:xs with b, which will contain the l argument in the getDirTree xs call, so b will contain xs. Hence xs is included twice (at every recursive step!). Try return ( x : a ++ b ) instead.
This seems to work: getDirTree' :: FilePath -> IO [FilePath] getDirTree' path = do subs <- getSubDirs path as <- mapM getDirTree' subs return $ subs ++ concat as
How to set getLine to only receive strings that can be converted to numbers?
main = do putStrLn "Hello,Name please?" first <- getLine second <- getLine third <- getLine if (second == "divide") then putStrLn (show (read first ::Double )/ (read third :: Double)) else putStrLn "Cannot do" So i want a number in first and third variables,and the second variable will be given the work divide and the if statement will begin and convert the String in first to a Double.But i think the issue is that the variable First is expecting a String like "one" that cannot be converted to a Double.How to fix this to allow getLine to only receive Strings that can be changed in numbers
Here's a quick idea that could help you: import Control.Applicative import Data.Char getNum :: (Num a, Read a) => IO (Maybe a) getNum = do (x, xs) <- break (not . isDigit ) <$> getLine case xs of [] -> return $ Just $ read x _ -> return Nothing main :: IO () main = do x <- getNum :: IO (Maybe Double) case x of Nothing -> do putStrLn "Not a number, try again" main Just x' -> putStrLn $ "Your number: " ++ show x' return () You cannot "make" getLine accept only numbers, you make a function that does. You can even modify this function to accept only the first set of numbers before a non-digit (right now it returns Nothing if any non-digit is in the string). Update Here's a program that asks for two numbers and an operation, doing some value checking: import Control.Applicative import Data.Char import Data.Maybe getNum :: (Num a, Read a) => IO (Maybe a) getNum = do (x, xs) <- break (not . isDigit ) <$> getLine case xs of [] -> return $ Just $ read x _ -> return Nothing main :: IO () main = do putStr "First: " x <- getNum :: IO (Maybe Double) putStr "Operation: " op <- getLine putStr "Second: " y <- getNum :: IO (Maybe Double) if isJust x && isJust y then do let x' = fromJust x y' = fromJust y putStr "Result: " case op of "divide" -> putStrLn $ show $ x' / y' "sum" -> putStrLn $ show $ x' + y' _ -> putStrLn "No operation" else putStrLn "Invalid numbers" return ()
How to print list of tuples like table in Haskell
i have a list of tuples like: [("3",69.46),("4",38.32),("5",111.67),("9",97.13)] and i want to print this list of tuple like : 3 69.46 4 38.32 5 111.67 9 97.13 What is the best way to implement this? (The length of list is dynamic) Thanks
One way would be like this: printList xs = mapM_ (\(a,b) -> putStr a >> putStr (" " ++ show b) >> putStrLn "") xs Or in a more readable way: printList xs = mapM_ (\(a,b) -> do putStr a putStr (" " ++ show b) putStrLn "") xs Or as #icktoofay points out you can use a single putStrLn: printList xs = mapM_ (\(a,b) -> putStrLn $ a ++ " " ++ show b) xs In ghci: λ> printList [("3",69.46),("4",38.32),("5",111.67),("9",97.13)] 3 69.46 4 38.32 5 111.67 9 97.13
Print List of Lists without brackets
I am trying to print Pascals triangle up to some arbitrary row, after some thought I came up with this solution: next xs = zipWith (+) ([0] ++ xs) (xs ++ [0]) pascal n = take n (iterate next [1]) main = do n <- readLn :: IO Int mapM_ putStrLn $ map show $ pascal n Which works quite well, except for the printing. When I apply pascal 4 I get: [1] [1,1] [1,2,1] [1,3,3,1] When what I really want is this: 1 1 1 1 2 1 1 3 3 1 Is there any way I can do this?
Define your own pretty-printing function: import Data.List (intercalate) show' :: Show a => [a] -> String show' = intercalate " " . map show
You could unwords / unlines: import Data.List ... putStr $ unlines $ map (unwords . map show) $ pascal n