module Math.NumberTheory.Prime (primes, isTrialDivisionPrime, isMillerRabinPrime,
isPrime, notPrime, prevPrime, nextPrime) where
import System.Random
import System.IO.Unsafe
isTrialDivisionPrime n
| n > 1 = isNotDivisibleBy primes
| otherwise = False
where isNotDivisibleBy (d:ds) | d*d > n = True
| n `rem` d == 0 = False
| otherwise = isNotDivisibleBy ds
primes :: [Integer]
primes = 2 : 3 : filter isTrialDivisionPrime (concat [ [m61,m6+1] | m6 <- [6,12..] ])
pfactors1 n | n > 0 = pfactors' n primes
| n < 0 = 1 : pfactors' (n) primes
where pfactors' n (d:ds) | n == 1 = []
| n < d*d = [n]
| r == 0 = d : pfactors' q (d:ds)
| otherwise = pfactors' n ds
where (q,r) = quotRem n d
isStrongPseudoPrime n b =
let (s,q) = split2s 0 (n1)
in isStrongPseudoPrime' n (s,q) b
isStrongPseudoPrime' n (s,q) b
| b' == 1 = True
| otherwise = n1 `elem` squarings
where b' = power_mod b q n
squarings = take s $ iterate (\x -> x*x `mod` n) b'
split2s s t = let (q,r) = t `quotRem` 2
in if r == 0 then split2s (s+1) q else (s,t)
power_mod b t n = powerMod' b 1 t
where powerMod' x y 0 = y
powerMod' x y t = powerMod' (x*x `rem` n) (if even t then y else x*y `rem` n) (t `div` 2)
isMillerRabinPrime' n
| n >= 4 =
let (s,q) = split2s 0 (n1)
in do g <- getStdGen
let rs = randomRs (2,n1) g
return $ all (isStrongPseudoPrime' n (s,q)) (take 25 rs)
| n >= 2 = return True
| otherwise = return False
isMillerRabinPrime n = unsafePerformIO (isMillerRabinPrime' n)
isPrime :: Integer -> Bool
isPrime n | n > 1 = isPrime' $ takeWhile (< 100) primes
| otherwise = False
where isPrime' (d:ds) | n < d*d = True
| otherwise = let (q,r) = quotRem n d
in if r == 0 then False else isPrime' ds
isPrime' [] = isMillerRabinPrime n
notPrime :: Integer -> Bool
notPrime = not . isPrime
prevPrime :: Integer -> Integer
prevPrime n | n > 5 = head $ filter isPrime $ candidates
| n < 3 = error "prevPrime: no previous primes"
| n == 3 = 2
| otherwise = 3
where n6 = (n `div` 6) * 6
candidates = dropWhile (>= n) $ concat [ [m6+5,m6+1] | m6 <- [n6, n66..] ]
nextPrime :: Integer -> Integer
nextPrime n | n < 2 = 2
| n < 3 = 3
| otherwise = head $ filter isPrime $ candidates
where n6 = (n `div` 6) * 6
candidates = dropWhile (<= n) $ concat [ [m6+1,m6+5] | m6 <- [n6, n6+6..] ]
pfactors2 n | n > 0 = pfactors' n $ takeWhile (< 10000) primes
| n < 0 = 1 : pfactors' (n) (takeWhile (< 10000) primes)
where pfactors' n (d:ds) | n == 1 = []
| n < d*d = [n]
| r == 0 = d : pfactors' q (d:ds)
| otherwise = pfactors' n ds
where (q,r) = quotRem n d
pfactors' n [] = if isMillerRabinPrime n then [n] else error ("pfactors2: can't factor " ++ show n)