user
The discrete Fourier transform is a linear, invertible transformation which transforms an arbitrary sequence of complex numbers to another sequence of complex numbers of the same length. The Fast Fourier transform (FFT) is an efficient implementation of this mechanism, but one which only works for sequences which have a length which is a power of 2.

The discrete Fourier transform is a useful testing mechanism to verify the correctness of code bases which use or implement the FFT.

For this task:

1. Implement the discrete fourier transform
2. Implement the inverse fourier transform
3. (optional) implement a cleaning mechanism to remove small errors introduced by floating point representation.
4. Verify the correctness of your implementation using a small sequence of integers, such as 2 3 5 7 11

The fourier transform of a sequence 

x

n
{\displaystyle {\displaystyle x\_{n}}}
 of length 

N
{\displaystyle {\displaystyle N}}
 is given by:

X

n
=

∑

k
=
0

N
−
1

x

k
⋅

e

−
i

2
π
N
k
n
{\displaystyle {\displaystyle X\_{n}=\sum \_{k=0}^{N-1}x\_{k}\cdot e^{-i{\frac {2\pi }{N}}kn}}}

The inverse transform is given by:

x

n
=


1
N

∑

k
=
0

N
−
1

X

k
⋅

e

i

2
π
N
k
n
{\displaystyle {\displaystyle x\_{n}={\frac {1}{N}}\sum \_{k=0}^{N-1}X\_{k}\cdot e^{i{\frac {2\pi }{N}}kn}}}
assistant
* This task could be done with a loop of maps like  
  @X[k] = sum @x.kv.map: -> \n, \v { v \* exp( -i \* tau / N \* k \* n ) }  
  , but it is a better fit for Raku's concurrent Hyper-operators.
* In the DFT formula, *N* becomes *+@x*, the element count. We would usually omit the plus sign and get the same result from numeric context, but that gets confusing to read when mixed with hyper-ops like »\*« .
* The exponents of DFT and IDFT only differ from each other in the sign of *i*, and the calculation of any given elements only differ by the *k* index of the element being output, so the inner loop is cleanly shareable between DFT and IDFT.
* Euler's constant, imaginary unit, pi, and 2pi are built-in, with ASCII and Unicode spellings: e 𝑒 i pi π tau τ .
* $one\_thing «op« @many\_things vectorizes the *op* operation: 5 «+« (1,2,3) is (6,7,8) .
* @many\_things »op« @many\_more\_things distributes the *op* operation pairwise: (5,6,7) »+« (1,2,3) is (6,8,10) .
* (list)».method applies the method to each element of the list.
* @array.keys, when @array has e.g. 4 elements, is 0,1,2,3 .
* $n.round($r) returns *$n* rounded to the nearest *$r*. (13/16).round(1/4) is 3/4 .
* .narrow changes a Numeric's type to a "narrower" type, when no precision would be lost.  
  8/2 is 4, but is type Rat (rational). (8/2).narrow is also 4, but type Int.

```
sub ft_inner ( @x, $k, $pos_neg_i where * == i|-i ) {
    my @exp := ( $pos_neg_i * tau / +@x * $k ) «*« @x.keys;
    return sum @x »*« 𝑒 «**« @exp;
}
sub dft   ( @x ) { return @x.keys.map: { ft_inner( @x, $_, -i )       } }
sub idft  ( @x ) { return @x.keys.map: { ft_inner( @x, $_,  i ) / +@x } }
sub clean ( @x ) { @x».round(1e-12)».narrow }

my @tests = ( 1, 2-i, -i, -1+2i     ),
            ( 2,   3,  5,     7, 11 ),
;
for @tests -> @x {
    my @x_dft  =  dft(@x);
    my @x_idft = idft(@x_dft);

    say .key.fmt('%6s:'), .value.&clean.fmt('%5s', ', ') for :@x, :@x_dft, :@x_idft;
    say '';
    warn "Round-trip failed" unless ( clean(@x) Z== clean(@x_idft) ).all;
}

```

Output:

```
     x:    1,  2-1i,  0-1i, -1+2i
 x_dft:    2, -2-2i,  0-2i,  4+4i
x_idft:    1,  2-1i,  0-1i, -1+2i

     x:    2,     3,     5,     7,    11
 x_dft:   28, -3.38196601125+8.784022634946i, -5.61803398875+2.800168985749i, -5.61803398875-2.800168985749i, -3.38196601125-8.784022634946i
x_idft:    2,     3,     5,     7,    11
```