1111
1212{-# LANGUAGE GADTs #-}
1313{-# LANGUAGE TemplateHaskell #-}
14+ {-# LANGUAGE TypeSynonymInstances #-}
1415
1516module Main where
1617
@@ -20,35 +21,48 @@ import Control.Applicative
2021import Control.Arrow
2122import Control.Monad (forM_ , unless )
2223import Data.Complex
23- import Data.Foldable (sum )
24+ import Data.Foldable (Foldable , sum , foldl' )
2425import Data.Newtypes.PrettyDouble
2526import System.Exit (exitFailure )
26- import TypeUnary.Nat (IsNat , natToZ , Nat (.. ), nat , N2 , N3 , N4 , N5 ) -- , N6)
27+ import TypeUnary.Nat (IsNat , Nat (.. ), nat , N2 , N3 , N4 , N5 ) -- , N6)
2728
2829-- import Test.QuickCheck (choose, vectorOf, elements, collect)
2930import Test.QuickCheck (choose , vectorOf )
3031import Test.QuickCheck.Arbitrary
3132import Test.QuickCheck.All (quickCheckAll )
3233
33- import Circat.Scan (scanlTEx )
34+ import Circat.Scan (lproducts , LScan )
3435import qualified Circat.Pair as P
3536import qualified Circat.RTree as RT
3637import Circat.RTree (bottomSplit )
3738
3839type RTree = RT. Tree
3940
40- -- Phasor, as a function of tree depth.
41- phasor :: (IsNat n , RealFloat a , Enum a ) => Nat n -> RTree n (Complex a )
42- phasor n = scanlTEx (*) 1 (pure phaseDelta)
43- where phaseDelta = cis ((- pi ) / 2 ** natToZ n)
44-
45- -- Radix-2, DIT FFT
46- fft_r2_dit :: (IsNat n , RealFloat a , Enum a ) => RTree n (Complex a ) -> RTree n (Complex a )
47- fft_r2_dit = fft_r2_dit' nat
48-
49- fft_r2_dit' :: (RealFloat a , Enum a ) => Nat n -> RTree n (Complex a ) -> RTree n (Complex a )
50- fft_r2_dit' Zero = id
51- fft_r2_dit' (Succ n) = RT. toB . P. inP (uncurry (+) &&& uncurry (-) ) . P. secondP (liftA2 (*) (phasor n)) . fmap (fft_r2_dit' n) . bottomSplit
41+ -- FFT, as a class
42+ -- The LScan constraint comes from the use of 'lproducts', in 'phasor'.
43+ class (LScan f ) => FFT f where
44+ fft :: (RealFloat a ) => f (Complex a ) -> f (Complex a )
45+
46+ instance IsNat n => FFT (RTree n ) where
47+ fft = fft' nat
48+ where fft' :: (RealFloat a ) => Nat n -> RTree n (Complex a ) -> RTree n (Complex a )
49+ fft' Zero = id
50+ fft' (Succ n) = inDIT $ fftP . P. secondP addPhase . fmap (fft' n)
51+ where inDIT g = RT. toB . g . bottomSplit
52+ fftP = P. inP (uncurry (+) &&& uncurry (-) )
53+ addPhase = liftA2 (*) id phasor
54+
55+ -- Phasor, as a general function on LScans.
56+ -- Gives the "length" (i.e. - number of elements in) of a Foldable.
57+ -- (Soon, to be provided by the Foldable class, as "length".)
58+ flen :: (Foldable f ) => f a -> Int
59+ flen = foldl' (flip ((+) . const 1 )) 0
60+
61+ -- Given a Foldable Applicative LScan, construct its matching phasor.
62+ phasor :: (Applicative f , Foldable f , LScan f , RealFloat b ) => f a -> f (Complex b )
63+ phasor f = fst $ lproducts (pure phaseDelta)
64+ where phaseDelta = cis ((- pi ) / (fromIntegral n))
65+ n = flen f
5266
5367-- Test config.
5468realData :: [[PrettyDouble ]]
@@ -112,19 +126,19 @@ instance Arbitrary FFTTestVal where
112126 return $ FFTTestVal zs
113127
114128prop_fft_test_N2 :: FFTTestVal -> Bool
115- prop_fft_test_N2 testVal = fft_r2_dit (myTree2 zs) == (RT. fromList $ dft zs)
129+ prop_fft_test_N2 testVal = fft (myTree2 zs) == (RT. fromList $ dft zs)
116130 where zs = take 4 $ getVal testVal
117131
118132prop_fft_test_N3 :: FFTTestVal -> Bool
119- prop_fft_test_N3 testVal = fft_r2_dit (myTree3 zs) == (RT. fromList $ dft zs)
133+ prop_fft_test_N3 testVal = fft (myTree3 zs) == (RT. fromList $ dft zs)
120134 where zs = take 8 $ getVal testVal
121135
122136prop_fft_test_N4 :: FFTTestVal -> Bool
123- prop_fft_test_N4 testVal = fft_r2_dit (myTree4 zs) == (RT. fromList $ dft zs)
137+ prop_fft_test_N4 testVal = fft (myTree4 zs) == (RT. fromList $ dft zs)
124138 where zs = take 16 $ getVal testVal
125139
126140prop_fft_test_N5 :: FFTTestVal -> Bool
127- prop_fft_test_N5 testVal = fft_r2_dit (myTree5 zs) == (RT. fromList $ dft zs)
141+ prop_fft_test_N5 testVal = fft (myTree5 zs) == (RT. fromList $ dft zs)
128142 where zs = take 32 $ getVal testVal
129143
130144-- Test definitions & choice
@@ -136,7 +150,7 @@ basicTest = do
136150 putStr " Expected output: "
137151 print $ dft x
138152 putStr " Actual output: "
139- print $ fft_r2_dit $ myTree2 x
153+ print $ fft $ myTree2 x
140154 )
141155
142156-- This weirdness is required, as of GHC 7.8.
0 commit comments