> module Fourier

>  (fft, fftinv,  dft, dftinv,  sft, sct)

> where

> import Complex--1.3
> import List(transpose)--1.3
> import Complex_Vectors
                
> fft:: [ComplexF] -> [ComplexF] -- Warning: works only for n=2^km
>                                -- time=O(n log(n)) algorithm
> fft xs = map((1/(fromInt n))*) (ffth xs us)   where
>   us = map conjugate (rootsOfUnity n)
>   n = length xs
>   fromInt = fromInteger . toInteger -- partain addition

> fftinv:: [ComplexF] -> [ComplexF] -- Warning: works only for n=2^km
>                                   -- time=O(n log(n)) algorithm
> fftinv xs = ffth xs us   where
>   us = rootsOfUnity n
>   n = length xs

> ffth:: [ComplexF] -> [ComplexF] -> [ComplexF]
> ffth xs us
>  | n>1    =             (replikate fftEvn) `plus` 
>             (us `times` (replikate fftOdd))
>  | n==1   = xs
>  where
>    fftEvn = ffth (evns xs) uEvns
>    fftOdd = ffth (odds xs) uEvns
>    uEvns = evns us
>    evns = everyNth 2
>    odds = everyNth 2 . tail
>    n = length xs


  Discrete Fourier Transform (fft generalized to non-binary orders)

> dft:: [ComplexF] -> [ComplexF] 
>      -- time=O(n*sum(map (^2) (factors n))) algorithm
>      --     =O(n*log(n)) when n is a product of small primes
> dft xs
>  = map((1/(fromInt n))*) (dfth fs xs us)
>  where
>    us = replikate(map conjugate (rootsOfUnity n))
>    fs = factors n
>    n = length xs
>    fromInt = fromInteger . toInteger -- partain addition

> dftinv:: [ComplexF] -> [ComplexF]
>      -- time=O(n*sum(map (^2) (factors n))) algorithm
>      --     =O(n*log(n)) when n is a product of small primes
> dftinv xs
>  = dfth fs xs us
>  where
>    us = replikate(rootsOfUnity n)
>    fs = factors n
>    n = length xs

> dfth:: [Int] -> [ComplexF] -> [ComplexF] -> [ComplexF]
> dfth (f:fs) xs us
>  | fs==[]      = sfth f xs us
>  | otherwise   = map sum (transpose pfts)
>  where
>    pfts = [(dftOfSection k) `times` (us `toThe` k)| k<-[0..f-1]]
>    dftOfSection k = repl f
>                          (dfth fs (fsectionOfxs k) (us `toThe` f))
>    fsectionOfxs k = everyNth f (drop k xs)


  Slow Fourier Transform

> sft:: [ComplexF] -> [ComplexF]     -- time=O(n^2) algorithm
> sft xs
>  = map((1/(fromInt n))*) (sfth n xs us)
>  where
>    us = replikate(map conjugate (rootsOfUnity n))
>    n = length xs
>    fromInt = fromInteger . toInteger -- partain addition

> sftinv:: [ComplexF] -> [ComplexF]  -- time=O(n^2) algorithm
> sftinv xs
>  = sfth n xs us
>  where
>    us = replikate(rootsOfUnity n)
>    n = length xs

> sfth:: Int -> [ComplexF] -> [ComplexF] -> [ComplexF]
> sfth n xs us
>  = [sum(xs `times` upowers)| upowers<-[us `toThe` k| k<-[0..n-1]]]


  Slow Cosine Transform

> sct:: [Double] -> [Double]  -- time=O(n^2) algorithm
> sct xs                    -- computes n^2 cosines
>  = [xs_dot (map (cos.((fromInt k)*)) (thetas n))| k<-[0 .. n-1]]
>  where
>    n = length xs
>    xs_dot = sum.(zipWith (*) xs)
>    fromInt = fromInteger . toInteger -- partain addition


   Utilities

> plus  = zipWith (+)
> times = zipWith (*)
> replikate = cycle
> repl n = concat . take n . repeat
> everyNth n = (map head).(takeWhile (/=[])).(iterate (drop n))

> toThe:: [ComplexF] -> Int -> [ComplexF]
> rootsOfUnity `toThe` k = everyNth k rootsOfUnity

> factors:: Int -> [Int]
> factors n = factorsh n primes

> factorsh:: Int -> [Int] -> [Int]
> factorsh n (p:ps)
>  | n==1             = []
>  | n `mod` p == 0   = p: factorsh (n `div` p) (p:ps)
>  | otherwise        = factorsh n ps

> primes:: [Int]
> primes = map head (iterate sieve [2..])
> sieve(p:xs) = [x| x<-xs, x `mod` p /= 0]


