synthesizer-core-0.9: test/Test/Sound/Synthesizer/Generic/FourierInteger.hs
{-# LANGUAGE NoImplicitPrelude #-}
module Test.Sound.Synthesizer.Generic.FourierInteger (tests) where
import qualified Synthesizer.Generic.Fourier as Fourier
import qualified Synthesizer.Generic.Cyclic as Cyclic
import qualified Synthesizer.Generic.Filter.NonRecursive as FiltNRG
import qualified Synthesizer.Generic.Signal as SigG
import qualified Synthesizer.Generic.Cut as CutG
import qualified Synthesizer.State.Signal as SigS
import qualified Synthesizer.Plain.Signal as Sig
import Test.QuickCheck (Testable, Arbitrary, arbitrary, Property, property)
import qualified Synthesizer.Basic.NumberTheory as NT
import qualified Number.ResidueClass.Check as RC
import Number.ResidueClass.Check ((/:), )
import qualified Algebra.ToInteger as ToInteger
import qualified Algebra.IntegralDomain as Integral
import qualified Algebra.Ring as Ring
import Control.Monad (liftM2, )
import NumericPrelude.Numeric
import NumericPrelude.Base
import Prelude ()
newtype Modulus a = Modulus a
deriving (Show)
instance Ring.C a => Arbitrary (Modulus a) where
arbitrary = fmap (Modulus . (2+) . fromInteger) arbitrary
data ModularSignal =
ModularSignal (Modulus Integer) (Sig.T (RC.T Integer))
deriving (Show)
instance Arbitrary ModularSignal where
arbitrary =
fmap (uncurry ModularSignal . signal) arbitrary
data ModularSignal2 =
ModularSignal2
(Modulus Integer) (Sig.T (RC.T Integer)) (Sig.T (RC.T Integer))
deriving (Show)
instance Arbitrary ModularSignal2 where
arbitrary =
liftM2
(\x y ->
let len = min (CutG.length x) (CutG.length y)
m = NT.fastFourierRing len
in ModularSignal2
(Modulus m)
(fmap (/: m) $ CutG.take len x)
(fmap (/: m) $ CutG.take len y))
arbitrary
arbitrary
scalarProduct ::
Modulus Integer ->
Sig.T (RC.T Integer) -> Sig.T (RC.T Integer) ->
RC.T Integer
scalarProduct (Modulus m) xs ys =
SigS.foldL (+) (RC.zero m) $
SigS.zipWith (*)
(SigG.toState xs)
(SigG.toState ys)
signal ::
Sig.T Integer -> (Modulus Integer, Sig.T (RC.T Integer))
signal xs =
let m = NT.fastFourierRing $ length xs
in (Modulus m, fmap (/: m) xs)
modular ::
(Integral.C a, ToInteger.C b) =>
Modulus a -> b -> RC.T a
modular (Modulus m) =
RC.fromRepresentative m . fromIntegral
simple ::
(Testable t) =>
(Sig.T Integer -> t) -> Property
simple = property
tests :: [(String, Property)]
tests =
("fourier inverse",
property $ \(ModularSignal m x) ->
(Fourier.transformBackward $ Fourier.transformForward x)
==
FiltNRG.amplify (modular m $ length x) x) :
("double fourier = reverse",
property $ \(ModularSignal m x) ->
(Cyclic.reverse $
Fourier.transformForward $
Fourier.transformForward x)
==
FiltNRG.amplify (modular m $ length x) x) :
("fourier of reverse",
property $ \(ModularSignal _m x) ->
Cyclic.reverse (Fourier.transformForward x) ==
Fourier.transformForward (Cyclic.reverse x)) :
("homogenity",
property $ \(ModularSignal m x) y ->
(FiltNRG.amplify (modular m (y::Integer)) $
Fourier.transformForward x)
==
(Fourier.transformForward $
FiltNRG.amplify (modular m y) x)) :
("additivity",
property $ \(ModularSignal2 _m x y) ->
SigG.mix (Fourier.transformForward x) (Fourier.transformForward y)
==
Fourier.transformForward (SigG.mix x y)) :
{-
("isometry",
simple $ \xs x0 ->
let (m,x) = signal (SigG.cons x0 xs)
in (AnaG.volumeVectorEuclideanSqr $ Fourier.transformForward x)
==
(modular m (SigG.length x) *
AnaG.volumeVectorEuclideanSqr x)) :
-}
("unitarity",
property $ \(ModularSignal2 m x y) ->
{-
since there is no equivalent of a complex conjugate
we have to take the scalar product with the backwards transform.
-}
scalarProduct m
(Fourier.transformForward x) (Fourier.transformBackward y)
==
modular m (length x) * scalarProduct m x y) :
("convolution",
property $ \(ModularSignal2 _m x y) ->
SigG.zipWith (*)
(Fourier.transformForward x)
(Fourier.transformForward y)
==
Fourier.transformForward (Cyclic.convolve x y)) :
("convolution cyclic",
property $ \(ModularSignal2 _m x y) ->
Fourier.convolveCyclic x y
==
Cyclic.convolve x y) :
("convolution long",
simple $ \x0 y0 ->
let m = Modulus $ NT.fastFourierRing $
2 * (NT.ceilingPowerOfTwo $ length x0)
x = fmap (modular m) x0
y = fmap (modular m) y0
in fmap (modular m) (FiltNRG.karatsubaFinite (*) x0 y0)
==
Fourier.convolveWithWindow (Fourier.window x) y) :
("convolution long modular",
simple $ \x0 y0 ->
let m = Modulus $ NT.fastFourierRing $
2 * (NT.ceilingPowerOfTwo $ length x0)
x = fmap (modular m) x0
y = fmap (modular m) (y0 :: Sig.T Integer)
in FiltNRG.karatsubaFinite (*) x y
==
Fourier.convolveWithWindow (Fourier.window x) y) :
[]