module Maths where
import Data.Ratio
import Text.Printf
import Control.Monad
import qualified Data.List as List
import qualified Data.Char as Char
import qualified Data.Array as Array
import Numeric
import Data.Array.IO
import Data.Array.Base
import Data.Bits
powerset :: [a] -> [[a]]
powerset [] = [[]]
powerset (x:xs) = (powerset xs) ++ (map (x:) (powerset xs))
powersetVoodoo = filterM (const [True, False])
everywhere :: a -> [a] -> [[a]]
everywhere x [] = [[x]]
everywhere x (y:ys) = (x:y:ys) : [ y:zs | zs <- everywhere x ys ]
permutations :: [a] -> [[a]]
permutations [] = [[]]
permutations (x:xs) = [ zs | ys <- permutations xs , zs <- everywhere x ys ]
permutations_count :: Integral a => a -> a -> a
permutations_count n k = factorial n `div` factorial (nk)
combinations :: [a] -> [[a]]
combinations [] = [[]]
combinations (x:xs)
= combinations xs ++ [ x:xs' | xs' <- combinations xs ]
combinations_count :: Integral a => a -> a -> a
combinations_count n k
= if k == 0 || k == n
then 1
else factorial n `div` (factorial k * factorial (n k))
binomial :: (Integral a) => a -> a -> Ratio a -> Ratio a
binomial n r p = (num_combs * (p^r) * (((1%1)p) ^ (n r)))
where num_combs = (combinations_count n r) % 1
printBinomial :: Integral a => a -> a -> Ratio a -> IO ()
printBinomial n r p = printf "%0.2f\n" (ratioToFloating (binomial n r p) :: Double)
binomialSimple :: Integral a => a -> a -> Ratio a
binomialSimple n r = binomial n r (1%n)
printBinomialSimple :: Integral a => a -> a -> IO ()
printBinomialSimple n r = printBinomial n r (1%n)
ratioToFloating :: (Integral a, Floating b) => Ratio a -> b
ratioToFloating x = (fromIntegral $ numerator x) / (fromIntegral $ denominator x)
fareylen :: Integral a => a -> a
fareylen n = 1 + f 1 0
where f x acc | x == n = term x acc
| otherwise = f (x+1) (term x acc)
term x acc = acc + totient x
fareylenf :: Integral a => a -> a
fareylenf n = 1 + (fromIntegral $ f 1 0)
where f x acc | x == n = term (fromIntegral x) acc
| otherwise = f ((fromIntegral x)+1) (term (fromIntegral x) acc)
term :: Int -> Integer -> Integer
term x acc = acc + fromIntegral (totient x)
totient :: Integral a => a -> a
totient 1 = 1
totient n | n > 1 = round $ foldr (*) (fromIntegral n) (t [head p | p <- primefactors])
where primefactors = List.group $ factors n
t [] = []
t (x:xs) = 1 (1/(fromIntegral x)) : t xs
polyx :: Integral a => a -> [a]
polyx n = polyx' 0 1 diff
where diff = n2
polyx' curr incr diff = next : polyx' next (incr + diff) diff
where next = curr + incr
integralToBinary :: Integral a => a -> String
integralToBinary n | n < 0 = error "Arg must be non-negative, not " ++ show n
| otherwise = (showIntAtBase 2 (Char.intToDigit) n) ""
factorial :: Integral a => a -> a
factorial n | n < 0 = error "Integer must be non-negative."
| n == 0 = 1
| otherwise = product [1..n]
factorials :: Array.Array Int Int
factorials = Array.listArray (0,9) (1:1:[product [2..n] | n<- [2..9]])
tri :: Integral a => a -> a
tri n = round (fromIntegral (n * (n+1)) / 2)
tris :: Integral a => [a]
tris = polyx 3
pents :: Integral a => [a]
pents = polyx 5
fibs :: Integral a => [a]
fibs = 1 : 1 : [ a + b | (a, b) <- zip fibs (tail fibs)]
primes :: Integral a => [a]
primes = 2 : sieve [3, 5..]
where sieve (p:rest) = p : sieve [n | n <- rest, mod n p /= 0]
primesn :: Integral a => a -> [a]
primesn n = 2 : sieve [3,5..n]
where sieve [] = []
sieve (p:ps) = p : sieve [x | x <- ps, mod x p /= 0]
divides :: Integral a => a -> a -> Bool
divides d n = rem n d == 0
ld :: Integral a => a -> a
ld n = ldf 2 n
ldf :: Integral a => a -> a -> a
ldf k n | rem n k == 0 = k
| k*k > n = n
| otherwise = ldf (k+1) n
isprime :: Integral a => a -> Bool
isprime n = n > 1 && (n == 2 || n == 3 || ((modn6 == 1 || modn6 == 5) && n == ldf' 3 n))
where modn6 = mod n 6
ldf' k n | divides k n = k
| k*k > n = n
| otherwise = ldf' (k+2) n
factors :: Integral a => a -> [a]
factors 1 = []
factors n = p : factors (div n p) where p = ld n
ufactors :: Integral a => a -> [a]
ufactors = List.nub . factors
divisors :: Integral a => a -> [a]
divisors n = [x | x <- [1..n1], mod n x == 0]
numdivisors :: Integral a => a -> Int
numdivisors n = let ps = List.group $ factors n
in product [1 + length p | p <- ps]
sumdivisors :: Integral a => a -> a
sumdivisors n = let primefactors = List.group $ factors n
in product [pnumdivisors (head p) (fromIntegral $ length p) | p <- primefactors]
pnumdivisors :: Integral a => a -> a -> a
pnumdivisors p x = let numer = fromIntegral (p^(x+1) 1)
denom = fromIntegral p1
in round $ numer / denom
coprime :: Integral a => a -> a -> Bool
coprime a b = 1 == gcd a b
mean :: Fractional a => [a] -> a
mean [] = 0
mean xs = (sum xs) / (fromIntegral $ length xs)
sum_of_n_primes_app :: Integral a => a -> Float
sum_of_n_primes_app n = (1/2) * fromIntegral (n*n) * log (fromIntegral n)
sum_of_n_primes :: Integral a => a -> Float
sum_of_n_primes n = fromIntegral $ sum $ take (fromIntegral n) primes
primesf m = do ps <- newArray (2,m) True >>= \a -> loop a m (2::Int)
return ps
where
loop arr m n | arr `seq` m `seq` n `seq` False = undefined
loop arr m n = if n == m then return [] else do
el <- unsafeRead arr n
if el then let loop' j | j > m = do a <- loop arr m (n+1); return (n : a)
| otherwise = unsafeWrite arr j False >> loop' (j+n)
in loop' (n+n)
else loop (arr :: IOUArray Int Bool) m (n+1)
modexp :: Integer -> Integer -> Integer -> Integer
modexp x y n =
if y == 0
then 1
else
let z = modexp x (y `div` 2) n
in case even y of
True -> (z*z) `mod` n
_ -> (x * z * z) `mod` n
e_calc :: Int -> Double
e_calc n = sum $ take n $ map (1/) $ scanl (*) 1 [1..]
e_calc' :: Int -> Double
e_calc' n = (1 + 1/n') ** n'
where n' = fromIntegral n