module Data.Array.Accelerate.NumberTheory where
import qualified Data.List.HT as ListHT
import Data.Maybe.HT (toMaybe, )
import Data.Bits ((.&.), (.|.), shiftR, )
import Data.List (unfoldr, )
fermatFactors :: Integer -> [(Integer,Integer)]
fermatFactors n =
let root = floor $ sqrt (fromInteger n :: Double)
in map (\(a,b) -> (ba,b+a)) $
mergeAndFilter
(zip (scanl (+) n [1,3..]) [0 .. div (n1) 2])
(zip (scanl (+) (root*root) $ iterate (2+) (2*root+1)) [root..])
mergeAndFilter :: (Ord a) => [(a,b)] -> [(a,c)] -> [(b,c)]
mergeAndFilter ((a0,b):a0s) ((a1,c):a1s) =
case compare a0 a1 of
LT -> mergeAndFilter a0s ((a1,c):a1s)
GT -> mergeAndFilter ((a0,b):a0s) a1s
EQ -> (b,c) : mergeAndFilter a0s a1s
mergeAndFilter _ _ = []
multiplicativeGenerator :: Integer -> Integer
multiplicativeGenerator p =
head $ primitiveRootsOfUnity p (p1)
primitiveRootsOfUnity :: Integer -> Integer -> [Integer]
primitiveRootsOfUnity modu order =
let greatDivisors = map (div order) $ uniquePrimeFactors order
in filter
(\n ->
let pow y = modularPower modu y n
in coprime n modu
&&
pow order == 1
&&
all (\y -> pow y /= 1) greatDivisors) $
[1 .. modu1]
coprime :: Integer -> Integer -> Bool
coprime x y = gcd x y == 1
modularPower :: Integer -> Integer -> Integer -> Integer
modularPower modu =
let go 0 _ = 1
go expo n =
case divMod expo 2 of
(expo2, r) ->
let n2 = mod (n*n) modu
in if r==0
then go expo2 n2
else mod (go expo2 n2 * n) modu
in go
uniquePrimeFactors :: Integer -> [Integer]
uniquePrimeFactors n =
let oddFactors =
foldr
(\p go m ->
let (q,r) = divMod m p
in if r==0
then p : go (divideByMaximumPower p q)
else
if q >= p
then go m
else if m==1 then [] else m : [])
(error "uniquePrimeFactors: end of infinite list")
(iterate (2+) 3)
in case powerOfTwoFactors n of
(1,m) -> oddFactors m
(_,m) -> 2 : oddFactors m
divideByMaximumPower :: Integer -> Integer -> Integer
divideByMaximumPower b n =
last $
n : unfoldr (\m -> case divMod m b of (q,r) -> toMaybe (r==0) (q,q)) n
powerOfTwoFactors :: Integer -> (Integer, Integer)
powerOfTwoFactors n =
let powerOfTwo = n .&. (n)
in (powerOfTwo, div n powerOfTwo)
ceilingPowerOfTwo :: Integer -> Integer
ceilingPowerOfTwo 0 = 1
ceilingPowerOfTwo n =
(1+) $ fst $ head $
dropWhile (uncurry (/=)) $
ListHT.mapAdjacent (,) $
scanl (\m d -> shiftR m d .|. m) (n1) $
iterate (2*) 1
ceiling5Smooth :: Integer -> Integer
ceiling5Smooth n =
minimum $ map (minimum . ceilingSmooths 2 5 n) $
ceilingSmooths 2 3 n $ ceilingPowerOfTwo n
ceilingSmooths :: Integer -> Integer -> Integer -> Integer -> [Integer]
ceilingSmooths a b n =
let divMany k =
case divMod k a of
(q,r) -> if r==0 && q>=n then divMany q else k
go m = m : if mod m a == 0 then go $ divMany $ m*b else []
in go