/* Test real_fft routines */

closeto(e,tol):=block([numer:true,abse],abse:abs(e),if(abse<=tol) then true else abse);
closeto(e,tol):=block([numer:true,abse],abse:abs(e),if(abse<=tol) then true else abse);

(compare_real_fft(tol, x) :=
  block([rft: real_fft(x),
         ft: fft(x),
         maperror: false,
         maxdiff],
    maxdiff: lreduce('max, abs(rft - ft)),
    closeto(maxdiff, tol)),
 0);
0;

(compare_inverse_real_fft(tol, x) :=
  block([rft: inverse_real_fft(real_fft(x)),
         maxdiff],
    maxdiff: lreduce('max, abs(x - rft)),
    closeto(maxdiff, tol)),
 0);
0;


/* verify that real_fft does not modify its argument */

(foo0 : [1, 2, 4, 8], 0);
0;

(kill (foo), foo : foo0, real_fft (foo), foo);
''foo0;

(foo : make_array (any, 4), fillarray (foo, foo0), real_fft (foo), listarray (foo));
''foo0;

(kill (foo), array (foo, 3), fillarray (foo, foo0), real_fft (foo), listarray (foo));
''foo0;

/* Verify basic computation */

real_fft([]);
[];

real_fft([123]);
[123.0];

real_fft([1,2]);
[1.5, -0.5];

errcatch(real_fft([1,2,3]));
[];

compare_real_fft(0, makelist(k, k, 1, 4));
true;

compare_real_fft(1.2413e-16, makelist(k, k, 1, 16));
true;

compare_real_fft(9.8712e-14, makelist(k, k, 1, 1024));
true;

compare_real_fft(3.8703e-13, makelist(k, k, 1, 4096));
true;

inverse_real_fft([]);
[];

inverse_real_fft([123]);
[123.0];

inverse_real_fft([1.5 ,-0.5]);
[1.0, 2.0];

compare_inverse_real_fft(0, makelist(k, k, 1, 4));
true;

compare_inverse_real_fft(1.7764e-15, makelist(k, k, 1, 16));
true;

compare_inverse_real_fft(3.9791e-13, makelist(k, k, 1, 1024));
true;

compare_inverse_real_fft(2.2738e-12, makelist(k, k, 1, 4096));
true;

/* verify that bf_real_fft does not modify its argument */

(foo0 : [1, 2, 4, 8], 0);
0;

(kill (foo), foo : foo0, bf_real_fft (foo), foo);
''foo0;

(foo : make_array (any, 4), fillarray (foo, foo0), bf_real_fft (foo), listarray (foo));
''foo0;

(kill (foo), array (foo, 3), fillarray (foo, foo0), bf_real_fft (foo), listarray (foo));
''foo0;

/* Verify basic computation */

bf_real_fft([]);
[];

bf_real_fft([123]);
[123b0];

bf_real_fft([1,2]);
[1.5b0, -0.5b0];

errcatch(bf_real_fft([1,2,3]));
[];

(compare_bf_real_fft(tol, x) :=
  block([rft: bf_real_fft(x),
         ft: bf_fft(x),
         maperror: false,
         maxdiff],
    maxdiff: lreduce('max, abs(rft - ft)),
    closeto(maxdiff, tol)),
 0);
0;

(compare_bf_inverse_real_fft(tol, x) :=
  block([rft: bf_inverse_real_fft(bf_real_fft(x)),
         maxdiff],
    maxdiff: lreduce('max, abs(x - rft)),
    closeto(maxdiff, tol)),
 0);
0;

compare_bf_real_fft(0, makelist(k, k, 1, 4));
true;

compare_bf_real_fft(2.7756b-17, makelist(k, k, 1, 16));
true;

compare_bf_real_fft(5.7034b-15, makelist(k, k, 1, 1024));
true;

compare_bf_real_fft(2.4145b-14, makelist(k, k, 1, 4096));
true;

bf_inverse_real_fft([]);
[];

bf_inverse_real_fft([1.5 ,-0.5]);
[1b0, 2b0];

compare_bf_inverse_real_fft(0, makelist(k, k, 1, 4));
true;

compare_bf_inverse_real_fft(3.3088b-24, makelist(k, k, 1, 16));
true;

compare_bf_inverse_real_fft(8.4704b-22, makelist(k, k, 1, 1024));
true;

compare_bf_inverse_real_fft(5.0822b-21, makelist(k, k, 1, 4096));
true;

(errcatch(real_fft([1,2,3])), error);
["real_fft: size of input must be a power of 2, not ~M",3];

(errcatch(inverse_real_fft([1,2,3,4])), error);
["inverse_real_fft: input length must be one more than a power of two, not ~M",4];

(errcatch(bf_real_fft([1,2,3])), error);
["bf_fft: size of input must be a power of 2, not ~M",3];

(errcatch(bf_inverse_real_fft([1,2,3,4])), error);
["bf_inverse_real_fft: input length must be one more than a power of two, not ~M",4];


