module Data.Array.Accelerate.Fourier.Real (
toSpectrum,
fromSpectrum,
twoToSpectrum,
twoToSpectrum2d,
untangleSpectra,
untangleSpectra2d,
untangleCoefficient,
twoFromSpectrum,
twoFromSpectrum2d,
entangleSpectra,
entangleSpectra2d,
entangleCoefficient,
) where
import qualified Data.Array.Accelerate.Fourier.Sign as Sign
import qualified Data.Array.Accelerate.Fourier.Private as Fourier
import qualified Data.Array.Accelerate.Cyclic as Cyclic
import qualified Data.Array.Accelerate.Utility.Sliced as Sliced
import qualified Data.Array.Accelerate.Utility.Lift.Exp as Exp
import Data.Array.Accelerate.Utility.Lift.Exp (expr)
import Data.Array.Accelerate.LinearAlgebra (zipExtrudedVectorWith, )
import qualified Data.Array.Accelerate.Data.Complex as Complex
import Data.Array.Accelerate.Data.Complex (Complex((:+)), )
import qualified Data.Array.Accelerate as A
import Data.Array.Accelerate
(Acc, Array, Exp, Slice, Shape, (:.)((:.)), (!), (?), )
toSpectrum ::
(Shape sh, Slice sh, A.RealFloat a, A.FromIntegral Int a) =>
Fourier.Transform (sh:.Int) (Complex a) ->
Acc (Array (sh:.Int) a) -> Acc (Array (sh:.Int) (Complex a))
toSpectrum subTrans arr =
let n2 = div (Sliced.length arr) 2
x = subTrans $ complexDeinterleave arr
xp = A.map (/2) $ A.zipWith (+) x (Cyclic.reverse x)
xm = A.map (/2) $ A.zipWith () x (Cyclic.reverse x)
twiddles =
A.map (imagUnit*) $
Fourier.twiddleFactors2 Sign.forwardExp n2
evens =
A.zipWith
(\xpk xmk -> A.lift $ Complex.real xpk :+ Complex.imag xmk) xp xm
odds =
zipExtrudedVectorWith (*) twiddles $
A.zipWith
(\xpk xmk -> A.lift $ Complex.real xmk :+ Complex.imag xpk) xp xm
in A.zipWith () evens odds
A.++
A.zipWith (+) evens odds
complexDeinterleave ::
(Shape sh, Slice sh, A.RealFloat a) =>
Acc (Array (sh:.Int) a) -> Acc (Array (sh:.Int) (Complex a))
complexDeinterleave arr =
let (sh:.len) = Exp.unlift (expr:.expr) $ A.shape arr
in A.generate
(A.lift $ sh :. div len 2)
(Exp.modify (expr:.expr) $
\(ix:.j) ->
arr ! A.lift (ix:.2*j)
:+
arr ! A.lift (ix:.2*j+1))
fromSpectrum ::
(Shape sh, Slice sh, A.RealFloat a, A.FromIntegral Int a) =>
Fourier.Transform (sh:.Int) (Complex a) ->
Acc (Array (sh:.Int) (Complex a)) -> Acc (Array (sh:.Int) a)
fromSpectrum subTrans spec =
let n2 = div (Sliced.length spec) 2
twiddles =
A.map (imagUnit*) $
Fourier.twiddleFactors2 Sign.inverseExp n2
part0 = Sliced.take n2 spec
part1 = Sliced.drop n2 spec
fe = A.zipWith (+) part0 part1
fo =
zipExtrudedVectorWith (*) twiddles $
A.zipWith () part0 part1
in complexInterleave $ subTrans $ A.zipWith (+) fe fo
complexInterleave ::
(Shape sh, Slice sh, A.RealFloat a) =>
Acc (Array (sh:.Int) (Complex a)) -> Acc (Array (sh:.Int) a)
complexInterleave arr =
let (sh:.len) = Exp.unlift (expr:.expr) $ A.shape arr
in A.generate
(A.lift $ sh :. 2*len)
(Exp.modify (expr:.expr) $
\(ix:.j) ->
let k = div j 2
r = mod j 2
x = arr ! A.lift (ix:.k)
in r A.== 0 ? (Complex.real x, Complex.imag x))
twoToSpectrum ::
(Shape sh, Slice sh, A.RealFloat a) =>
Fourier.Transform (sh:.Int) (Complex a) ->
Acc (Array (sh:.Int) (a,a)) ->
Acc (Array (sh:.Int) (Complex a, Complex a))
twoToSpectrum subTrans =
untangleSpectra . subTrans .
A.map (Exp.modify (expr,expr) $ uncurry (:+))
twoToSpectrum2d ::
(Shape sh, Slice sh, A.RealFloat a) =>
Fourier.Transform (sh:.Int:.Int) (Complex a) ->
Acc (Array (sh:.Int:.Int) (a,a)) ->
Acc (Array (sh:.Int:.Int) (Complex a, Complex a))
twoToSpectrum2d subTrans =
untangleSpectra2d . subTrans .
A.map (Exp.modify (expr,expr) $ uncurry (:+))
untangleSpectra ::
(Shape sh, Slice sh, A.RealFloat a) =>
Acc (Array (sh:.Int) (Complex a)) ->
Acc (Array (sh:.Int) (Complex a, Complex a))
untangleSpectra spec =
A.zipWith untangleCoefficient spec (Cyclic.reverse spec)
untangleSpectra2d ::
(Shape sh, Slice sh, A.RealFloat a) =>
Acc (Array (sh:.Int:.Int) (Complex a)) ->
Acc (Array (sh:.Int:.Int) (Complex a, Complex a))
untangleSpectra2d spec =
A.zipWith untangleCoefficient spec (Cyclic.reverse2d spec)
untangleCoefficient ::
(A.RealFloat a) =>
Exp (Complex a) -> Exp (Complex a) -> Exp (Complex a, Complex a)
untangleCoefficient a b =
let bc = Complex.conjugate b
in A.lift ((a + bc) / 2, (a bc) * (imagUnit / 2))
twoFromSpectrum ::
(Shape sh, Slice sh, A.RealFloat a) =>
Fourier.Transform (sh:.Int) (Complex a) ->
Acc (Array (sh:.Int) (Complex a, Complex a)) ->
Acc (Array (sh:.Int) (a,a))
twoFromSpectrum subTrans =
A.map (Exp.modify (expr:+expr) $ \(x:+y) -> (x,y)) .
subTrans . entangleSpectra
twoFromSpectrum2d ::
(Shape sh, Slice sh, A.RealFloat a) =>
Fourier.Transform (sh:.Int:.Int) (Complex a) ->
Acc (Array (sh:.Int:.Int) (Complex a, Complex a)) ->
Acc (Array (sh:.Int:.Int) (a,a))
twoFromSpectrum2d subTrans =
A.map (Exp.modify (expr:+expr) $ \(x:+y) -> (x,y)) .
subTrans . entangleSpectra2d
entangleSpectra ::
(Shape sh, Slice sh, A.RealFloat a) =>
Acc (Array (sh:.Int) (Complex a, Complex a)) ->
Acc (Array (sh:.Int) (Complex a))
entangleSpectra = entangleSpectraGen
entangleSpectra2d ::
(Shape sh, Slice sh, A.RealFloat a) =>
Acc (Array (sh:.Int:.Int) (Complex a, Complex a)) ->
Acc (Array (sh:.Int:.Int) (Complex a))
entangleSpectra2d = entangleSpectraGen
entangleSpectraGen ::
(Shape sh, Slice sh, A.RealFloat a) =>
Acc (Array sh (Complex a, Complex a)) ->
Acc (Array sh (Complex a))
entangleSpectraGen = A.map (A.fst . A.uncurry entangleCoefficient)
entangleCoefficient ::
(A.RealFloat a) =>
Exp (Complex a) -> Exp (Complex a) -> Exp (Complex a, Complex a)
entangleCoefficient c d =
let di = d * imagUnit
in A.lift (c + di, Complex.conjugate (c di))
imagUnit :: (A.Num a) => Exp (Complex a)
imagUnit = A.lift $ zero :+ one
zero, one :: (A.Num a) => Exp a
zero = 0
one = 1