import Control.Parallel
import Data.Time.Clock

fibSer :: Int -> Integer
fibSer 0 = 0
fibSer 1 = 1
fibSer n = fibSer (n-1) + fibSer (n-2)

fibPar :: Int -> Int -> Integer
fibPar _ 0 = 0
fibPar _ 1 = 1
fibPar c n 
  | n<c     = fibSer (n-1) + fibSer (n-2)
  | n>=c    = (term1 `par` term2) `pseq` (term1 + term2)
    where
      term1 = fibPar c (n-1)
      term2 = fibPar c (n-2)

-- time fibPar for with the given cutoff
timeCutoff :: Int -> Int -> IO NominalDiffTime
timeCutoff n c = do
  st <- getCurrentTime
  let r = fibPar c n
  en <- st `pseq` r `pseq` getCurrentTime
  return $ diffUTCTime en st

-- time all cutoffs
timeAll :: Int -> IO [Float]
timeAll n = do
  times <- sequence $ map (timeCutoff n) [0..n+1]
  return $ map (fromRational.toRational) times

-- time fibSer for comparison
timeSer :: Int -> IO Float
timeSer n = do
  st <- getCurrentTime
  let r = fibSer n
  en <- st `pseq` r `pseq` getCurrentTime
  return $ fromRational.toRational $ diffUTCTime en st

n :: Int
n = 47

main :: IO ()
main = do
  ser <- timeSer n
  putStrLn $ "ser_time_warmup = " ++ (show ser)
  ser <- timeSer n
  putStrLn $ "ser_time1 = " ++ (show ser)
  secs <- timeAll n
  putStrLn $ "par_times1 = np.array(" ++ (show secs) ++ ")"
