-- Good chunksize was obtained from experimentation
lenstraECMParallel :: Integer -> Integer -> Maybe Integer
lenstraECMParallel number bound
    | number `mod` 2 == 0 = Just 2
    | number `mod` 3 == 0 = Just 3
    | number `mod` 5 == 0 = Just 5
    | otherwise           =
        let primes      = eratosthenesSieve bound
            primePowers = map (findHighestPower bound) primes
            upperBound  = (number - 1)
            curves      = filter (isElliptic number) $ map (\x -> MEC x 1) [1..upperBound]
        in lenstraECMLoop number primePowers curves
    where lenstraECMLoop _ _ [] = Nothing
          lenstraECMLoop number primePowers ecs
              = if isNothing result then recurse else result
              where result    = lenstraECMTryChunk number primePowers points ecChunk
                    recurse   = lenstraECMLoop number primePowers ecRest
                    ecChunk   = take chunkSize ecs
                    ecRest    = drop chunkSize ecs
                    points    = take chunkSize $ repeat (Point 0 1)
                    chunkSize = if number < 100 then fromIntegral number else 100
          lenstraECMTryChunk _ [] _ _ = Nothing
          lenstraECMTryChunk number (p:ps) accumPoints ecChunk
              = either recurse Just result
              where recurse points = lenstraECMTryChunk number ps points ecChunk
                    result         = repeatedParallelCubic ecChunk accumPoints p number
lenstraECMParallel :: Integer -> Integer -> Maybe Integer
lenstraECMParallel number bound
    | number `mod` 2 == 0 = Just 2
    | number `mod` 3 == 0 = Just 3
    | number `mod` 5 == 0 = Just 5
    | otherwise           =
        let primes      = eratosthenesSieve bound
            primePowers = map (findHighestPower bound) primes
            upperBound  = (number - 1)
            curves      = filter (isElliptic number) $ map (\x -> MEC x 1) [1..upperBound]
        in lenstraECMLoop number primePowers curves
    where lenstraECMLoop _ _ [] = Nothing
          lenstraECMLoop number primePowers ecs
              = if isNothing result then recurse else result
              where result    = lenstraECMTryChunk number primePowers points ecChunk
                    recurse   = lenstraECMLoop number primePowers ecRest
                    ecChunk   = take chunkSize ecs
                    ecRest    = drop chunkSize ecs
                    points    = take chunkSize $ repeat (Point 0 1)
                    chunkSize = if number < 100 then fromIntegral number else 100
          lenstraECMTryChunk _ [] _ _ = Nothing
          lenstraECMTryChunk number (p:ps) accumPoints ecChunk
              = either recurse Just result
              where recurse points = lenstraECMTryChunk number ps points ecChunk
                    result         = repeatedParallelCubic ecChunk accumPoints p number
lenstraECMParallel number bound
    | number `mod` 2 == 0 = Just 2
    | number `mod` 3 == 0 = Just 3
    | number `mod` 5 == 0 = Just 5
    | otherwise           =
        let primes      = eratosthenesSieve bound
            primePowers = map (findHighestPower bound) primes
            upperBound  = (number - 1)
            curves      = filter (isElliptic number) $ map (\x -> MEC x 1) [1..upperBound]
        in lenstraECMLoop number primePowers curves
    where lenstraECMLoop _ _ [] = Nothing
          lenstraECMLoop number primePowers ecs
              = if isNothing result then recurse else result
              where result    = lenstraECMTryChunk number primePowers points ecChunk
                    recurse   = lenstraECMLoop number primePowers ecRest
                    ecChunk   = take chunkSize ecs
                    ecRest    = drop chunkSize ecs
                    points    = take chunkSize $ repeat (Point 0 1)
                    chunkSize = if number < 100 then fromIntegral number else 100
          lenstraECMTryChunk _ [] _ _ = Nothing
          lenstraECMTryChunk number (p:ps) accumPoints ecChunk
              = either recurse Just result
              where recurse points = lenstraECMTryChunk number ps points ecChunk
                    result         = repeatedParallelCubic ecChunk accumPoints p number