Repository URL to install this package:
Version:
3.0.0 ▾
|
(*************************************************************************
Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
>>> SOURCE LICENSE >>>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (www.fsf.org); either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
A copy of the GNU General Public License is available at
http://www.fsf.org/licensing/licenses
>>> END OF LICENSE >>>
*************************************************************************)
unit u_ftbase;
interface
uses Math, Sysutils, u_ap;
type
FTPlan = record
Plan : TInteger1DArray;
Precomputed : TReal1DArray;
TmpBuf : TReal1DArray;
StackBuf : TReal1DArray;
end;
procedure FTBaseGenerateComplexFFTPlan(N : Integer; var Plan : FTPlan);
procedure FTBaseGenerateRealFFTPlan(N : Integer; var Plan : FTPlan);
procedure FTBaseGenerateRealFHTPlan(N : Integer; var Plan : FTPlan);
procedure FTBaseExecutePlan(var A : TReal1DArray;
AOffset : Integer;
N : Integer;
var Plan : FTPlan);
procedure FTBaseExecutePlanRec(var A : TReal1DArray;
AOffset : Integer;
var Plan : FTPlan;
EntryOffset : Integer;
StackPtr : Integer);
procedure FTBaseFactorize(N : Integer;
TaskType : Integer;
var N1 : Integer;
var N2 : Integer);
function FTBaseIsSmooth(N : Integer):Boolean;
function FTBaseFindSmooth(N : Integer):Integer;
function FTBaseFindSmoothEven(N : Integer):Integer;
function FTBaseGetFLOPEstimate(N : Integer):Double;
implementation
const
FTBasePlanEntrySize = 8;
FTBaseCFFTTask = 0;
FTBaseRFHTTask = 1;
FTBaseRFFTTask = 2;
FFTCooleyTukeyPlan = 0;
FFTBluesteinPlan = 1;
FFTCodeletPlan = 2;
FHTCooleyTukeyPlan = 3;
FHTCodeletPlan = 4;
FFTRealCooleyTukeyPlan = 5;
FFTEmptyPlan = 6;
FHTN2Plan = 999;
FTBaseUpdateTw = 4;
FTBaseCodeletMax = 5;
FTBaseCodeletRecommended = 5;
FTBaseInefficiencyFactor = Double(1.3);
FTBaseMaxSmoothFactor = 5;
procedure FTBaseGeneratePlanRec(N : Integer;
TaskType : Integer;
var Plan : FTPlan;
var PlanSize : Integer;
var PrecomputedSize : Integer;
var PlanArraySize : Integer;
var TmpMemSize : Integer;
var StackMemSize : Integer;
StackPtr : Integer);forward;
procedure FTBasePrecomputePlanRec(var Plan : FTPlan;
EntryOffset : Integer;
StackPtr : Integer);forward;
procedure FFTTwCalc(var A : TReal1DArray;
AOffset : Integer;
N1 : Integer;
N2 : Integer);forward;
procedure InternalComplexLinTranspose(var A : TReal1DArray;
M : Integer;
N : Integer;
AStart : Integer;
var Buf : TReal1DArray);forward;
procedure InternalRealLinTranspose(var A : TReal1DArray;
M : Integer;
N : Integer;
AStart : Integer;
var Buf : TReal1DArray);forward;
procedure FFTICLTRec(var A : TReal1DArray;
AStart : Integer;
AStride : Integer;
var B : TReal1DArray;
BStart : Integer;
BStride : Integer;
M : Integer;
N : Integer);forward;
procedure FFTIRLTRec(var A : TReal1DArray;
AStart : Integer;
AStride : Integer;
var B : TReal1DArray;
BStart : Integer;
BStride : Integer;
M : Integer;
N : Integer);forward;
procedure FTBaseFindSmoothRec(N : Integer;
Seed : Integer;
LeastFactor : Integer;
var Best : Integer);forward;
procedure FFTArrayResize(var A : TInteger1DArray;
var ASize : Integer;
NewASize : Integer);forward;
procedure RefFHT(var A : TReal1DArray; N : Integer; Offs : Integer);forward;
(*************************************************************************
This subroutine generates FFT plan - a decomposition of a N-length FFT to
the more simpler operations. Plan consists of the root entry and the child
entries.
Subroutine parameters:
N task size
Output parameters:
Plan plan
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FTBaseGenerateComplexFFTPlan(N : Integer; var Plan : FTPlan);
var
PlanArraySize : Integer;
PlanSize : Integer;
PrecomputedSize : Integer;
TmpMemSize : Integer;
StackMemSize : Integer;
StackPtr : Integer;
begin
PlanArraySize := 1;
PlanSize := 0;
PrecomputedSize := 0;
StackMemSize := 0;
StackPtr := 0;
TmpMemSize := 2*N;
SetLength(Plan.Plan, PlanArraySize);
FTBaseGeneratePlanRec(N, FTBaseCFFTTask, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
Assert(StackPtr=0, 'Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!');
SetLength(Plan.StackBuf, Max(StackMemSize, 1));
SetLength(Plan.TmpBuf, Max(TmpMemSize, 1));
SetLength(Plan.Precomputed, Max(PrecomputedSize, 1));
StackPtr := 0;
FTBasePrecomputePlanRec(Plan, 0, StackPtr);
Assert(StackPtr=0, 'Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!');
end;
(*************************************************************************
Generates real FFT plan
*************************************************************************)
procedure FTBaseGenerateRealFFTPlan(N : Integer; var Plan : FTPlan);
var
PlanArraySize : Integer;
PlanSize : Integer;
PrecomputedSize : Integer;
TmpMemSize : Integer;
StackMemSize : Integer;
StackPtr : Integer;
begin
PlanArraySize := 1;
PlanSize := 0;
PrecomputedSize := 0;
StackMemSize := 0;
StackPtr := 0;
TmpMemSize := 2*N;
SetLength(Plan.Plan, PlanArraySize);
FTBaseGeneratePlanRec(N, FTBaseRFFTTask, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
Assert(StackPtr=0, 'Internal error in FTBaseGenerateRealFFTPlan: stack ptr!');
SetLength(Plan.StackBuf, Max(StackMemSize, 1));
SetLength(Plan.TmpBuf, Max(TmpMemSize, 1));
SetLength(Plan.Precomputed, Max(PrecomputedSize, 1));
StackPtr := 0;
FTBasePrecomputePlanRec(Plan, 0, StackPtr);
Assert(StackPtr=0, 'Internal error in FTBaseGenerateRealFFTPlan: stack ptr!');
end;
(*************************************************************************
Generates real FHT plan
*************************************************************************)
procedure FTBaseGenerateRealFHTPlan(N : Integer; var Plan : FTPlan);
var
PlanArraySize : Integer;
PlanSize : Integer;
PrecomputedSize : Integer;
TmpMemSize : Integer;
StackMemSize : Integer;
StackPtr : Integer;
begin
PlanArraySize := 1;
PlanSize := 0;
PrecomputedSize := 0;
StackMemSize := 0;
StackPtr := 0;
TmpMemSize := N;
SetLength(Plan.Plan, PlanArraySize);
FTBaseGeneratePlanRec(N, FTBaseRFHTTask, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
Assert(StackPtr=0, 'Internal error in FTBaseGenerateRealFHTPlan: stack ptr!');
SetLength(Plan.StackBuf, Max(StackMemSize, 1));
SetLength(Plan.TmpBuf, Max(TmpMemSize, 1));
SetLength(Plan.Precomputed, Max(PrecomputedSize, 1));
StackPtr := 0;
FTBasePrecomputePlanRec(Plan, 0, StackPtr);
Assert(StackPtr=0, 'Internal error in FTBaseGenerateRealFHTPlan: stack ptr!');
end;
(*************************************************************************
This subroutine executes FFT/FHT plan.
If Plan is a:
* complex FFT plan - sizeof(A)=2*N,
A contains interleaved real/imaginary values
* real FFT plan - sizeof(A)=2*N,
A contains real values interleaved with zeros
* real FHT plan - sizeof(A)=2*N,
A contains real values interleaved with zeros
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FTBaseExecutePlan(var A : TReal1DArray;
AOffset : Integer;
N : Integer;
var Plan : FTPlan);
var
StackPtr : Integer;
begin
StackPtr := 0;
FTBaseExecutePlanRec(A, AOffset, Plan, 0, StackPtr);
end;
(*************************************************************************
Recurrent subroutine for the FTBaseExecutePlan
Parameters:
A FFT'ed array
AOffset offset of the FFT'ed part (distance is measured in doubles)
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FTBaseExecutePlanRec(var A : TReal1DArray;
AOffset : Integer;
var Plan : FTPlan;
EntryOffset : Integer;
StackPtr : Integer);
var
I : Integer;
J : Integer;
K : Integer;
Idx : Integer;
N1 : Integer;
N2 : Integer;
N : Integer;
M : Integer;
Offs : Integer;
Offs1 : Integer;
Offs2 : Integer;
OffsA : Integer;
OffsB : Integer;
OffsP : Integer;
HK : Double;
HNK : Double;
X : Double;
Y : Double;
BX : Double;
BY : Double;
V : Double;
EmptyArray : TReal1DArray;
A0X : Double;
A0Y : Double;
A1X : Double;
A1Y : Double;
A2X : Double;
A2Y : Double;
A3X : Double;
A3Y : Double;
A4X : Double;
A4Y : Double;
V0 : Double;
V1 : Double;
V2 : Double;
V3 : Double;
T1X : Double;
T1Y : Double;
T2X : Double;
T2Y : Double;
T3X : Double;
T3Y : Double;
T4X : Double;
T4Y : Double;
T5X : Double;
T5Y : Double;
M1X : Double;
M1Y : Double;
M2X : Double;
M2Y : Double;
M3X : Double;
M3Y : Double;
M4X : Double;
M4Y : Double;
M5X : Double;
M5Y : Double;
S1X : Double;
S1Y : Double;
S2X : Double;
S2Y : Double;
S3X : Double;
S3Y : Double;
S4X : Double;
S4Y : Double;
S5X : Double;
S5Y : Double;
C1 : Double;
C2 : Double;
C3 : Double;
C4 : Double;
C5 : Double;
Tmp : TReal1DArray;
begin
if Plan.Plan[EntryOffset+3]=FFTEmptyPlan then
begin
Exit;
end;
if Plan.Plan[EntryOffset+3]=FFTCooleyTukeyPlan then
begin
//
// Cooley-Tukey plan
// * transposition
// * row-wise FFT
// * twiddle factors:
// - TwBase is a basis twiddle factor for I=1, J=1
// - TwRow is a twiddle factor for a second element in a row (J=1)
// - Tw is a twiddle factor for a current element
// * transposition again
// * row-wise FFT again
//
N1 := Plan.Plan[EntryOffset+1];
N2 := Plan.Plan[EntryOffset+2];
InternalComplexLinTranspose(A, N1, N2, AOffset, Plan.TmpBuf);
I:=0;
while I<=N2-1 do
begin
FTBaseExecutePlanRec(A, AOffset+I*N1*2, Plan, Plan.Plan[EntryOffset+5], StackPtr);
Inc(I);
end;
FFTTwCalc(A, AOffset, N1, N2);
InternalComplexLinTranspose(A, N2, N1, AOffset, Plan.TmpBuf);
I:=0;
while I<=N1-1 do
begin
FTBaseExecutePlanRec(A, AOffset+I*N2*2, Plan, Plan.Plan[EntryOffset+6], StackPtr);
Inc(I);
end;
InternalComplexLinTranspose(A, N1, N2, AOffset, Plan.TmpBuf);
Exit;
end;
if Plan.Plan[EntryOffset+3]=FFTRealCooleyTukeyPlan then
begin
//
// Cooley-Tukey plan
// * transposition
// * row-wise FFT
// * twiddle factors:
// - TwBase is a basis twiddle factor for I=1, J=1
// - TwRow is a twiddle factor for a second element in a row (J=1)
// - Tw is a twiddle factor for a current element
// * transposition again
// * row-wise FFT again
//
N1 := Plan.Plan[EntryOffset+1];
N2 := Plan.Plan[EntryOffset+2];
InternalComplexLinTranspose(A, N2, N1, AOffset, Plan.TmpBuf);
I:=0;
while I<=N1 div 2-1 do
begin
//
// pack two adjacent smaller real FFT's together,
// make one complex FFT,
// unpack result
//
Offs := AOffset+2*I*N2*2;
K:=0;
while K<=N2-1 do
begin
A[Offs+2*K+1] := A[Offs+2*N2+2*K+0];
Inc(K);
end;
FTBaseExecutePlanRec(A, Offs, Plan, Plan.Plan[EntryOffset+6], StackPtr);
Plan.TmpBuf[0] := A[Offs+0];
Plan.TmpBuf[1] := 0;
Plan.TmpBuf[2*N2+0] := A[Offs+1];
Plan.TmpBuf[2*N2+1] := 0;
K:=1;
while K<=N2-1 do
begin
Offs1 := 2*K;
Offs2 := 2*N2+2*K;
HK := A[Offs+2*K+0];
HNK := A[Offs+2*(N2-K)+0];
Plan.TmpBuf[Offs1+0] := +Double(0.5)*(HK+HNK);
Plan.TmpBuf[Offs2+1] := -Double(0.5)*(HK-HNK);
HK := A[Offs+2*K+1];
HNK := A[Offs+2*(N2-K)+1];
Plan.TmpBuf[Offs2+0] := +Double(0.5)*(HK+HNK);
Plan.TmpBuf[Offs1+1] := +Double(0.5)*(HK-HNK);
Inc(K);
end;
APVMove(@A[0], Offs, Offs+2*N2*2-1, @Plan.TmpBuf[0], 0, 2*N2*2-1);
Inc(I);
end;
if N1 mod 2<>0 then
begin
FTBaseExecutePlanRec(A, AOffset+(N1-1)*N2*2, Plan, Plan.Plan[EntryOffset+6], StackPtr);
end;
FFTTwCalc(A, AOffset, N2, N1);
InternalComplexLinTranspose(A, N1, N2, AOffset, Plan.TmpBuf);
I:=0;
while I<=N2-1 do
begin
FTBaseExecutePlanRec(A, AOffset+I*N1*2, Plan, Plan.Plan[EntryOffset+5], StackPtr);
Inc(I);
end;
InternalComplexLinTranspose(A, N2, N1, AOffset, Plan.TmpBuf);
Exit;
end;
if Plan.Plan[EntryOffset+3]=FHTCooleyTukeyPlan then
begin
//
// Cooley-Tukey FHT plan:
// * transpose \
// * smaller FHT's |
// * pre-process |
// * multiply by twiddle factors | corresponds to multiplication by H1
// * post-process |
// * transpose again /
// * multiply by H2 (smaller FHT's)
// * final transposition
//
// For more details see Vitezslav Vesely, "Fast algorithms
// of Fourier and Hartley transform and their implementation in MATLAB",
// page 31.
//
N1 := Plan.Plan[EntryOffset+1];
N2 := Plan.Plan[EntryOffset+2];
N := N1*N2;
InternalRealLinTranspose(A, N1, N2, AOffset, Plan.TmpBuf);
I:=0;
while I<=N2-1 do
begin
FTBaseExecutePlanRec(A, AOffset+I*N1, Plan, Plan.Plan[EntryOffset+5], StackPtr);
Inc(I);
end;
I:=0;
while I<=N2-1 do
begin
J:=0;
while J<=N1-1 do
begin
OffsA := AOffset+I*N1;
HK := A[OffsA+J];
HNK := A[OffsA+(N1-J) mod N1];
Offs := 2*(I*N1+J);
Plan.TmpBuf[Offs+0] := -Double(0.5)*(HNK-HK);
Plan.TmpBuf[Offs+1] := +Double(0.5)*(HK+HNK);
Inc(J);
end;
Inc(I);
end;
FFTTwCalc(Plan.TmpBuf, 0, N1, N2);
J:=0;
while J<=N1-1 do
begin
A[AOffset+J] := Plan.TmpBuf[2*J+0]+Plan.TmpBuf[2*J+1];
Inc(J);
end;
if N2 mod 2=0 then
begin
Offs := 2*(N2 div 2)*N1;
OffsA := AOffset+N2 div 2*N1;
J:=0;
while J<=N1-1 do
begin
A[OffsA+J] := Plan.TmpBuf[Offs+2*J+0]+Plan.TmpBuf[Offs+2*J+1];
Inc(J);
end;
end;
I:=1;
while I<=(N2+1) div 2-1 do
begin
Offs := 2*I*N1;
Offs2 := 2*(N2-I)*N1;
OffsA := AOffset+I*N1;
J:=0;
while J<=N1-1 do
begin
A[OffsA+J] := Plan.TmpBuf[Offs+2*J+1]+Plan.TmpBuf[Offs2+2*J+0];
Inc(J);
end;
OffsA := AOffset+(N2-I)*N1;
J:=0;
while J<=N1-1 do
begin
A[OffsA+J] := Plan.TmpBuf[Offs+2*J+0]+Plan.TmpBuf[Offs2+2*J+1];
Inc(J);
end;
Inc(I);
end;
InternalRealLinTranspose(A, N2, N1, AOffset, Plan.TmpBuf);
I:=0;
while I<=N1-1 do
begin
FTBaseExecutePlanRec(A, AOffset+I*N2, Plan, Plan.Plan[EntryOffset+6], StackPtr);
Inc(I);
end;
InternalRealLinTranspose(A, N1, N2, AOffset, Plan.TmpBuf);
Exit;
end;
if Plan.Plan[EntryOffset+3]=FHTN2Plan then
begin
//
// Cooley-Tukey FHT plan
//
N1 := Plan.Plan[EntryOffset+1];
N2 := Plan.Plan[EntryOffset+2];
N := N1*N2;
RefFHT(A, N, AOffset);
Exit;
end;
if Plan.Plan[EntryOffset+3]=FFTCodeletPlan then
begin
N1 := Plan.Plan[EntryOffset+1];
N2 := Plan.Plan[EntryOffset+2];
N := N1*N2;
if N=2 then
begin
A0X := A[AOffset+0];
A0Y := A[AOffset+1];
A1X := A[AOffset+2];
A1Y := A[AOffset+3];
V0 := A0X+A1X;
V1 := A0Y+A1Y;
V2 := A0X-A1X;
V3 := A0Y-A1Y;
A[AOffset+0] := V0;
A[AOffset+1] := V1;
A[AOffset+2] := V2;
A[AOffset+3] := V3;
Exit;
end;
if N=3 then
begin
Offs := Plan.Plan[EntryOffset+7];
C1 := Plan.Precomputed[Offs+0];
C2 := Plan.Precomputed[Offs+1];
A0X := A[AOffset+0];
A0Y := A[AOffset+1];
A1X := A[AOffset+2];
A1Y := A[AOffset+3];
A2X := A[AOffset+4];
A2Y := A[AOffset+5];
T1X := A1X+A2X;
T1Y := A1Y+A2Y;
A0X := A0X+T1X;
A0Y := A0Y+T1Y;
M1X := C1*T1X;
M1Y := C1*T1Y;
M2X := C2*(A1Y-A2Y);
M2Y := C2*(A2X-A1X);
S1X := A0X+M1X;
S1Y := A0Y+M1Y;
A1X := S1X+M2X;
A1Y := S1Y+M2Y;
A2X := S1X-M2X;
A2Y := S1Y-M2Y;
A[AOffset+0] := A0X;
A[AOffset+1] := A0Y;
A[AOffset+2] := A1X;
A[AOffset+3] := A1Y;
A[AOffset+4] := A2X;
A[AOffset+5] := A2Y;
Exit;
end;
if N=4 then
begin
A0X := A[AOffset+0];
A0Y := A[AOffset+1];
A1X := A[AOffset+2];
A1Y := A[AOffset+3];
A2X := A[AOffset+4];
A2Y := A[AOffset+5];
A3X := A[AOffset+6];
A3Y := A[AOffset+7];
T1X := A0X+A2X;
T1Y := A0Y+A2Y;
T2X := A1X+A3X;
T2Y := A1Y+A3Y;
M2X := A0X-A2X;
M2Y := A0Y-A2Y;
M3X := A1Y-A3Y;
M3Y := A3X-A1X;
A[AOffset+0] := T1X+T2X;
A[AOffset+1] := T1Y+T2Y;
A[AOffset+4] := T1X-T2X;
A[AOffset+5] := T1Y-T2Y;
A[AOffset+2] := M2X+M3X;
A[AOffset+3] := M2Y+M3Y;
A[AOffset+6] := M2X-M3X;
A[AOffset+7] := M2Y-M3Y;
Exit;
end;
if N=5 then
begin
Offs := Plan.Plan[EntryOffset+7];
C1 := Plan.Precomputed[Offs+0];
C2 := Plan.Precomputed[Offs+1];
C3 := Plan.Precomputed[Offs+2];
C4 := Plan.Precomputed[Offs+3];
C5 := Plan.Precomputed[Offs+4];
T1X := A[AOffset+2]+A[AOffset+8];
T1Y := A[AOffset+3]+A[AOffset+9];
T2X := A[AOffset+4]+A[AOffset+6];
T2Y := A[AOffset+5]+A[AOffset+7];
T3X := A[AOffset+2]-A[AOffset+8];
T3Y := A[AOffset+3]-A[AOffset+9];
T4X := A[AOffset+6]-A[AOffset+4];
T4Y := A[AOffset+7]-A[AOffset+5];
T5X := T1X+T2X;
T5Y := T1Y+T2Y;
A[AOffset+0] := A[AOffset+0]+T5X;
A[AOffset+1] := A[AOffset+1]+T5Y;
M1X := C1*T5X;
M1Y := C1*T5Y;
M2X := C2*(T1X-T2X);
M2Y := C2*(T1Y-T2Y);
M3X := -C3*(T3Y+T4Y);
M3Y := C3*(T3X+T4X);
M4X := -C4*T4Y;
M4Y := C4*T4X;
M5X := -C5*T3Y;
M5Y := C5*T3X;
S3X := M3X-M4X;
S3Y := M3Y-M4Y;
S5X := M3X+M5X;
S5Y := M3Y+M5Y;
S1X := A[AOffset+0]+M1X;
S1Y := A[AOffset+1]+M1Y;
S2X := S1X+M2X;
S2Y := S1Y+M2Y;
S4X := S1X-M2X;
S4Y := S1Y-M2Y;
A[AOffset+2] := S2X+S3X;
A[AOffset+3] := S2Y+S3Y;
A[AOffset+4] := S4X+S5X;
A[AOffset+5] := S4Y+S5Y;
A[AOffset+6] := S4X-S5X;
A[AOffset+7] := S4Y-S5Y;
A[AOffset+8] := S2X-S3X;
A[AOffset+9] := S2Y-S3Y;
Exit;
end;
end;
if Plan.Plan[EntryOffset+3]=FHTCodeletPlan then
begin
N1 := Plan.Plan[EntryOffset+1];
N2 := Plan.Plan[EntryOffset+2];
N := N1*N2;
if N=2 then
begin
A0X := A[AOffset+0];
A1X := A[AOffset+1];
A[AOffset+0] := A0X+A1X;
A[AOffset+1] := A0X-A1X;
Exit;
end;
if N=3 then
begin
Offs := Plan.Plan[EntryOffset+7];
C1 := Plan.Precomputed[Offs+0];
C2 := Plan.Precomputed[Offs+1];
A0X := A[AOffset+0];
A1X := A[AOffset+1];
A2X := A[AOffset+2];
T1X := A1X+A2X;
A0X := A0X+T1X;
M1X := C1*T1X;
M2Y := C2*(A2X-A1X);
S1X := A0X+M1X;
A[AOffset+0] := A0X;
A[AOffset+1] := S1X-M2Y;
A[AOffset+2] := S1X+M2Y;
Exit;
end;
if N=4 then
begin
A0X := A[AOffset+0];
A1X := A[AOffset+1];
A2X := A[AOffset+2];
A3X := A[AOffset+3];
T1X := A0X+A2X;
T2X := A1X+A3X;
M2X := A0X-A2X;
M3Y := A3X-A1X;
A[AOffset+0] := T1X+T2X;
A[AOffset+1] := M2X-M3Y;
A[AOffset+2] := T1X-T2X;
A[AOffset+3] := M2X+M3Y;
Exit;
end;
if N=5 then
begin
Offs := Plan.Plan[EntryOffset+7];
C1 := Plan.Precomputed[Offs+0];
C2 := Plan.Precomputed[Offs+1];
C3 := Plan.Precomputed[Offs+2];
C4 := Plan.Precomputed[Offs+3];
C5 := Plan.Precomputed[Offs+4];
T1X := A[AOffset+1]+A[AOffset+4];
T2X := A[AOffset+2]+A[AOffset+3];
T3X := A[AOffset+1]-A[AOffset+4];
T4X := A[AOffset+3]-A[AOffset+2];
T5X := T1X+T2X;
V0 := A[AOffset+0]+T5X;
A[AOffset+0] := V0;
M2X := C2*(T1X-T2X);
M3Y := C3*(T3X+T4X);
S3Y := M3Y-C4*T4X;
S5Y := M3Y+C5*T3X;
S1X := V0+C1*T5X;
S2X := S1X+M2X;
S4X := S1X-M2X;
A[AOffset+1] := S2X-S3Y;
A[AOffset+2] := S4X-S5Y;
A[AOffset+3] := S4X+S5Y;
A[AOffset+4] := S2X+S3Y;
Exit;
end;
end;
if Plan.Plan[EntryOffset+3]=FFTBluesteinPlan then
begin
//
// Bluestein plan:
// 1. multiply by precomputed coefficients
// 2. make convolution: forward FFT, multiplication by precomputed FFT
// and backward FFT. backward FFT is represented as
//
// invfft(x) = fft(x')'/M
//
// for performance reasons reduction of inverse FFT to
// forward FFT is merged with multiplication of FFT components
// and last stage of Bluestein's transformation.
// 3. post-multiplication by Bluestein factors
//
N := Plan.Plan[EntryOffset+1];
M := Plan.Plan[EntryOffset+4];
Offs := Plan.Plan[EntryOffset+7];
I:=StackPtr+2*N;
while I<=StackPtr+2*M-1 do
begin
Plan.StackBuf[I] := 0;
Inc(I);
end;
OffsP := Offs+2*M;
OffsA := AOffset;
OffsB := StackPtr;
I:=0;
while I<=N-1 do
begin
BX := Plan.Precomputed[OffsP+0];
BY := Plan.Precomputed[OffsP+1];
X := A[OffsA+0];
Y := A[OffsA+1];
Plan.StackBuf[OffsB+0] := X*BX-Y*-BY;
Plan.StackBuf[OffsB+1] := X*-BY+Y*BX;
OffsP := OffsP+2;
OffsA := OffsA+2;
OffsB := OffsB+2;
Inc(I);
end;
FTBaseExecutePlanRec(Plan.StackBuf, StackPtr, Plan, Plan.Plan[EntryOffset+5], StackPtr+2*2*M);
OffsB := StackPtr;
OffsP := Offs;
I:=0;
while I<=M-1 do
begin
X := Plan.StackBuf[OffsB+0];
Y := Plan.StackBuf[OffsB+1];
BX := Plan.Precomputed[OffsP+0];
BY := Plan.Precomputed[OffsP+1];
Plan.StackBuf[OffsB+0] := X*BX-Y*BY;
Plan.StackBuf[OffsB+1] := -(X*BY+Y*BX);
OffsB := OffsB+2;
OffsP := OffsP+2;
Inc(I);
end;
FTBaseExecutePlanRec(Plan.StackBuf, StackPtr, Plan, Plan.Plan[EntryOffset+5], StackPtr+2*2*M);
OffsB := StackPtr;
OffsP := Offs+2*M;
OffsA := AOffset;
I:=0;
while I<=N-1 do
begin
X := +Plan.StackBuf[OffsB+0]/M;
Y := -Plan.StackBuf[OffsB+1]/M;
BX := Plan.Precomputed[OffsP+0];
BY := Plan.Precomputed[OffsP+1];
A[OffsA+0] := X*BX-Y*-BY;
A[OffsA+1] := X*-BY+Y*BX;
OffsP := OffsP+2;
OffsA := OffsA+2;
OffsB := OffsB+2;
Inc(I);
end;
Exit;
end;
end;
(*************************************************************************
Returns good factorization N=N1*N2.
Usually N1<=N2 (but not always - small N's may be exception).
if N1<>1 then N2<>1.
Factorization is chosen depending on task type and codelets we have.
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FTBaseFactorize(N : Integer;
TaskType : Integer;
var N1 : Integer;
var N2 : Integer);
var
J : Integer;
begin
N1 := 0;
N2 := 0;
//
// try to find good codelet
//
if N1*N2<>N then
begin
J:=FTBaseCodeletRecommended;
while J>=2 do
begin
if N mod J=0 then
begin
N1 := J;
N2 := N div J;
Break;
end;
Dec(J);
end;
end;
//
// try to factorize N
//
if N1*N2<>N then
begin
J:=FTBaseCodeletRecommended+1;
while J<=N-1 do
begin
if N mod J=0 then
begin
N1 := J;
N2 := N div J;
Break;
end;
Inc(J);
end;
end;
//
// looks like N is prime :(
//
if N1*N2<>N then
begin
N1 := 1;
N2 := N;
end;
//
// normalize
//
if (N2=1) and (N1<>1) then
begin
N2 := N1;
N1 := 1;
end;
end;
(*************************************************************************
Is number smooth?
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
function FTBaseIsSmooth(N : Integer):Boolean;
var
I : Integer;
begin
I:=2;
while I<=FTBaseMaxSmoothFactor do
begin
while N mod I=0 do
begin
N := N div I;
end;
Inc(I);
end;
Result := N=1;
end;
(*************************************************************************
Returns smallest smooth (divisible only by 2, 3, 5) number that is greater
than or equal to max(N,2)
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
function FTBaseFindSmooth(N : Integer):Integer;
var
Best : Integer;
begin
Best := 2;
while Best<N do
begin
Best := 2*Best;
end;
FTBaseFindSmoothRec(N, 1, 2, Best);
Result := Best;
end;
(*************************************************************************
Returns smallest smooth (divisible only by 2, 3, 5) even number that is
greater than or equal to max(N,2)
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
function FTBaseFindSmoothEven(N : Integer):Integer;
var
Best : Integer;
begin
Best := 2;
while Best<N do
begin
Best := 2*Best;
end;
FTBaseFindSmoothRec(N, 2, 2, Best);
Result := Best;
end;
(*************************************************************************
Returns estimate of FLOP count for the FFT.
It is only an estimate based on operations count for the PERFECT FFT
and relative inefficiency of the algorithm actually used.
N should be power of 2, estimates are badly wrong for non-power-of-2 N's.
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
function FTBaseGetFLOPEstimate(N : Integer):Double;
begin
Result := FTBaseInefficiencyFactor*(4*N*Ln(N)/Ln(2)-6*N+8);
end;
(*************************************************************************
Recurrent subroutine for the FFTGeneratePlan:
PARAMETERS:
N plan size
IsReal whether input is real or not.
subroutine MUST NOT ignore this flag because real
inputs comes with non-initialized imaginary parts,
so ignoring this flag will result in corrupted output
HalfOut whether full output or only half of it from 0 to
floor(N/2) is needed. This flag may be ignored if
doing so will simplify calculations
Plan plan array
PlanSize size of used part (in integers)
PrecomputedSize size of precomputed array allocated yet
PlanArraySize plan array size (actual)
TmpMemSize temporary memory required size
BluesteinMemSize temporary memory required size
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FTBaseGeneratePlanRec(N : Integer;
TaskType : Integer;
var Plan : FTPlan;
var PlanSize : Integer;
var PrecomputedSize : Integer;
var PlanArraySize : Integer;
var TmpMemSize : Integer;
var StackMemSize : Integer;
StackPtr : Integer);
var
J : Integer;
K : Integer;
M : Integer;
N1 : Integer;
N2 : Integer;
ESize : Integer;
EntryOffset : Integer;
begin
//
// prepare
//
if PlanSize+FTBasePlanEntrySize>PlanArraySize then
begin
FFTArrayResize(Plan.Plan, PlanArraySize, 8*PlanArraySize);
end;
EntryOffset := PlanSize;
ESize := FTBasePlanEntrySize;
PlanSize := PlanSize+ESize;
//
// if N=1, generate empty plan and exit
//
if N=1 then
begin
Plan.Plan[EntryOffset+0] := ESize;
Plan.Plan[EntryOffset+1] := -1;
Plan.Plan[EntryOffset+2] := -1;
Plan.Plan[EntryOffset+3] := FFTEmptyPlan;
Plan.Plan[EntryOffset+4] := -1;
Plan.Plan[EntryOffset+5] := -1;
Plan.Plan[EntryOffset+6] := -1;
Plan.Plan[EntryOffset+7] := -1;
Exit;
end;
//
// generate plans
//
FTBaseFactorize(N, TaskType, N1, N2);
if (TaskType=FTBaseCFFTTask) or (TaskType=FTBaseRFFTTask) then
begin
//
// complex FFT plans
//
if N1<>1 then
begin
//
// Cooley-Tukey plan (real or complex)
//
// Note that child plans are COMPLEX
// (whether plan itself is complex or not).
//
TmpMemSize := Max(TmpMemSize, 2*N1*N2);
Plan.Plan[EntryOffset+0] := ESize;
Plan.Plan[EntryOffset+1] := N1;
Plan.Plan[EntryOffset+2] := N2;
if TaskType=FTBaseCFFTTask then
begin
Plan.Plan[EntryOffset+3] := FFTCooleyTukeyPlan;
end
else
begin
Plan.Plan[EntryOffset+3] := FFTRealCooleyTukeyPlan;
end;
Plan.Plan[EntryOffset+4] := 0;
Plan.Plan[EntryOffset+5] := PlanSize;
FTBaseGeneratePlanRec(N1, FTBaseCFFTTask, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
Plan.Plan[EntryOffset+6] := PlanSize;
FTBaseGeneratePlanRec(N2, FTBaseCFFTTask, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
Plan.Plan[EntryOffset+7] := -1;
Exit;
end
else
begin
if (N=2) or (N=3) or (N=4) or (N=5) then
begin
//
// hard-coded plan
//
Plan.Plan[EntryOffset+0] := ESize;
Plan.Plan[EntryOffset+1] := N1;
Plan.Plan[EntryOffset+2] := N2;
Plan.Plan[EntryOffset+3] := FFTCodeletPlan;
Plan.Plan[EntryOffset+4] := 0;
Plan.Plan[EntryOffset+5] := -1;
Plan.Plan[EntryOffset+6] := -1;
Plan.Plan[EntryOffset+7] := PrecomputedSize;
if N=3 then
begin
PrecomputedSize := PrecomputedSize+2;
end;
if N=5 then
begin
PrecomputedSize := PrecomputedSize+5;
end;
Exit;
end
else
begin
//
// Bluestein's plan
//
// Select such M that M>=2*N-1, M is composite, and M's
// factors are 2, 3, 5
//
K := 2*N2-1;
M := FTBaseFindSmooth(K);
TmpMemSize := Max(TmpMemSize, 2*M);
Plan.Plan[EntryOffset+0] := ESize;
Plan.Plan[EntryOffset+1] := N2;
Plan.Plan[EntryOffset+2] := -1;
Plan.Plan[EntryOffset+3] := FFTBluesteinPlan;
Plan.Plan[EntryOffset+4] := M;
Plan.Plan[EntryOffset+5] := PlanSize;
StackPtr := StackPtr+2*2*M;
StackMemSize := Max(StackMemSize, StackPtr);
FTBaseGeneratePlanRec(M, FTBaseCFFTTask, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
StackPtr := StackPtr-2*2*M;
Plan.Plan[EntryOffset+6] := -1;
Plan.Plan[EntryOffset+7] := PrecomputedSize;
PrecomputedSize := PrecomputedSize+2*M+2*N;
Exit;
end;
end;
end;
if TaskType=FTBaseRFHTTask then
begin
//
// real FHT plans
//
if N1<>1 then
begin
//
// Cooley-Tukey plan
//
//
TmpMemSize := Max(TmpMemSize, 2*N1*N2);
Plan.Plan[EntryOffset+0] := ESize;
Plan.Plan[EntryOffset+1] := N1;
Plan.Plan[EntryOffset+2] := N2;
Plan.Plan[EntryOffset+3] := FHTCooleyTukeyPlan;
Plan.Plan[EntryOffset+4] := 0;
Plan.Plan[EntryOffset+5] := PlanSize;
FTBaseGeneratePlanRec(N1, TaskType, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
Plan.Plan[EntryOffset+6] := PlanSize;
FTBaseGeneratePlanRec(N2, TaskType, Plan, PlanSize, PrecomputedSize, PlanArraySize, TmpMemSize, StackMemSize, StackPtr);
Plan.Plan[EntryOffset+7] := -1;
Exit;
end
else
begin
//
// N2 plan
//
Plan.Plan[EntryOffset+0] := ESize;
Plan.Plan[EntryOffset+1] := N1;
Plan.Plan[EntryOffset+2] := N2;
Plan.Plan[EntryOffset+3] := FHTN2Plan;
Plan.Plan[EntryOffset+4] := 0;
Plan.Plan[EntryOffset+5] := -1;
Plan.Plan[EntryOffset+6] := -1;
Plan.Plan[EntryOffset+7] := -1;
if (N=2) or (N=3) or (N=4) or (N=5) then
begin
//
// hard-coded plan
//
Plan.Plan[EntryOffset+0] := ESize;
Plan.Plan[EntryOffset+1] := N1;
Plan.Plan[EntryOffset+2] := N2;
Plan.Plan[EntryOffset+3] := FHTCodeletPlan;
Plan.Plan[EntryOffset+4] := 0;
Plan.Plan[EntryOffset+5] := -1;
Plan.Plan[EntryOffset+6] := -1;
Plan.Plan[EntryOffset+7] := PrecomputedSize;
if N=3 then
begin
PrecomputedSize := PrecomputedSize+2;
end;
if N=5 then
begin
PrecomputedSize := PrecomputedSize+5;
end;
Exit;
end;
Exit;
end;
end;
end;
(*************************************************************************
Recurrent subroutine for precomputing FFT plans
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FTBasePrecomputePlanRec(var Plan : FTPlan;
EntryOffset : Integer;
StackPtr : Integer);
var
I : Integer;
J : Integer;
Idx : Integer;
N1 : Integer;
N2 : Integer;
N : Integer;
M : Integer;
Offs : Integer;
V : Double;
EmptyArray : TReal1DArray;
BX : Double;
BY : Double;
begin
if (Plan.Plan[EntryOffset+3]=FFTCooleyTukeyPlan) or (Plan.Plan[EntryOffset+3]=FFTRealCooleyTukeyPlan) or (Plan.Plan[EntryOffset+3]=FHTCooleyTukeyPlan) then
begin
FTBasePrecomputePlanRec(Plan, Plan.Plan[EntryOffset+5], StackPtr);
FTBasePrecomputePlanRec(Plan, Plan.Plan[EntryOffset+6], StackPtr);
Exit;
end;
if (Plan.Plan[EntryOffset+3]=FFTCodeletPlan) or (Plan.Plan[EntryOffset+3]=FHTCodeletPlan) then
begin
N1 := Plan.Plan[EntryOffset+1];
N2 := Plan.Plan[EntryOffset+2];
N := N1*N2;
if N=3 then
begin
Offs := Plan.Plan[EntryOffset+7];
Plan.Precomputed[Offs+0] := Cos(2*Pi/3)-1;
Plan.Precomputed[Offs+1] := Sin(2*Pi/3);
Exit;
end;
if N=5 then
begin
Offs := Plan.Plan[EntryOffset+7];
V := 2*Pi/5;
Plan.Precomputed[Offs+0] := (cos(V)+cos(2*V))/2-1;
Plan.Precomputed[Offs+1] := (cos(V)-cos(2*V))/2;
Plan.Precomputed[Offs+2] := -sin(V);
Plan.Precomputed[Offs+3] := -(sin(V)+sin(2*V));
Plan.Precomputed[Offs+4] := sin(V)-sin(2*V);
Exit;
end;
end;
if Plan.Plan[EntryOffset+3]=FFTBluesteinPlan then
begin
FTBasePrecomputePlanRec(Plan, Plan.Plan[EntryOffset+5], StackPtr);
N := Plan.Plan[EntryOffset+1];
M := Plan.Plan[EntryOffset+4];
Offs := Plan.Plan[EntryOffset+7];
I:=0;
while I<=2*M-1 do
begin
Plan.Precomputed[Offs+I] := 0;
Inc(I);
end;
I:=0;
while I<=N-1 do
begin
BX := Cos(Pi*AP_Sqr(I)/N);
BY := Sin(Pi*AP_Sqr(I)/N);
Plan.Precomputed[Offs+2*I+0] := BX;
Plan.Precomputed[Offs+2*I+1] := BY;
Plan.Precomputed[Offs+2*M+2*I+0] := BX;
Plan.Precomputed[Offs+2*M+2*I+1] := BY;
if I>0 then
begin
Plan.Precomputed[Offs+2*(M-I)+0] := BX;
Plan.Precomputed[Offs+2*(M-I)+1] := BY;
end;
Inc(I);
end;
FTBaseExecutePlanRec(Plan.Precomputed, Offs, Plan, Plan.Plan[EntryOffset+5], StackPtr);
Exit;
end;
end;
(*************************************************************************
Twiddle factors calculation
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FFTTwCalc(var A : TReal1DArray;
AOffset : Integer;
N1 : Integer;
N2 : Integer);
var
I : Integer;
J : Integer;
N : Integer;
Idx : Integer;
Offs : Integer;
X : Double;
Y : Double;
TwXM1 : Double;
TwY : Double;
TwBaseXM1 : Double;
TwBaseY : Double;
TwRowXM1 : Double;
TwRowY : Double;
TmpX : Double;
TmpY : Double;
V : Double;
begin
N := N1*N2;
V := -2*Pi/N;
TwBaseXM1 := -2*AP_Sqr(Sin(Double(0.5)*V));
TwBaseY := Sin(V);
TwRowXM1 := 0;
TwRowY := 0;
I:=0;
while I<=N2-1 do
begin
TwXM1 := 0;
TwY := 0;
J:=0;
while J<=N1-1 do
begin
Idx := I*N1+J;
Offs := AOffset+2*Idx;
X := A[Offs+0];
Y := A[Offs+1];
TmpX := X*TwXM1-Y*TwY;
TmpY := X*TwY+Y*TwXM1;
A[Offs+0] := X+TmpX;
A[Offs+1] := Y+TmpY;
//
// update Tw: Tw(new) = Tw(old)*TwRow
//
if J<N1-1 then
begin
if J mod FTBaseUpdateTw=0 then
begin
V := -2*Pi*I*(J+1)/N;
TwXM1 := -2*AP_Sqr(Sin(Double(0.5)*V));
TwY := Sin(V);
end
else
begin
TmpX := TwRowXM1+TwXM1*TwRowXM1-TwY*TwRowY;
TmpY := TwRowY+TwXM1*TwRowY+TwY*TwRowXM1;
TwXM1 := TwXM1+TmpX;
TwY := TwY+TmpY;
end;
end;
Inc(J);
end;
//
// update TwRow: TwRow(new) = TwRow(old)*TwBase
//
if I<N2-1 then
begin
if J mod FTBaseUpdateTw=0 then
begin
V := -2*Pi*(I+1)/N;
TwRowXM1 := -2*AP_Sqr(Sin(Double(0.5)*V));
TwRowY := Sin(V);
end
else
begin
TmpX := TwBaseXM1+TwRowXM1*TwBaseXM1-TwRowY*TwBaseY;
TmpY := TwBaseY+TwRowXM1*TwBaseY+TwRowY*TwBaseXM1;
TwRowXM1 := TwRowXM1+TmpX;
TwRowY := TwRowY+TmpY;
end;
end;
Inc(I);
end;
end;
(*************************************************************************
Linear transpose: transpose complex matrix stored in 1-dimensional array
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure InternalComplexLinTranspose(var A : TReal1DArray;
M : Integer;
N : Integer;
AStart : Integer;
var Buf : TReal1DArray);
begin
FFTICLTRec(A, AStart, N, Buf, 0, M, M, N);
APVMove(@A[0], AStart, AStart+2*M*N-1, @Buf[0], 0, 2*M*N-1);
end;
(*************************************************************************
Linear transpose: transpose real matrix stored in 1-dimensional array
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure InternalRealLinTranspose(var A : TReal1DArray;
M : Integer;
N : Integer;
AStart : Integer;
var Buf : TReal1DArray);
begin
FFTIRLTRec(A, AStart, N, Buf, 0, M, M, N);
APVMove(@A[0], AStart, AStart+M*N-1, @Buf[0], 0, M*N-1);
end;
(*************************************************************************
Recurrent subroutine for a InternalComplexLinTranspose
Write A^T to B, where:
* A is m*n complex matrix stored in array A as pairs of real/image values,
beginning from AStart position, with AStride stride
* B is n*m complex matrix stored in array B as pairs of real/image values,
beginning from BStart position, with BStride stride
stride is measured in complex numbers, i.e. in real/image pairs.
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FFTICLTRec(var A : TReal1DArray;
AStart : Integer;
AStride : Integer;
var B : TReal1DArray;
BStart : Integer;
BStride : Integer;
M : Integer;
N : Integer);
var
I : Integer;
J : Integer;
Idx1 : Integer;
Idx2 : Integer;
M2 : Integer;
M1 : Integer;
N1 : Integer;
begin
if (M=0) or (N=0) then
begin
Exit;
end;
if Max(M, N)<=8 then
begin
M2 := 2*BStride;
I:=0;
while I<=M-1 do
begin
Idx1 := BStart+2*I;
Idx2 := AStart+2*I*AStride;
J:=0;
while J<=N-1 do
begin
B[Idx1+0] := A[Idx2+0];
B[Idx1+1] := A[Idx2+1];
Idx1 := Idx1+M2;
Idx2 := Idx2+2;
Inc(J);
end;
Inc(I);
end;
Exit;
end;
if N>M then
begin
//
// New partition:
//
// "A^T -> B" becomes "(A1 A2)^T -> ( B1 )
// ( B2 )
//
N1 := N div 2;
if (N-N1>=8) and (N1 mod 8<>0) then
begin
N1 := N1+(8-N1 mod 8);
end;
Assert(N-N1>0);
FFTICLTRec(A, AStart, AStride, B, BStart, BStride, M, N1);
FFTICLTRec(A, AStart+2*N1, AStride, B, BStart+2*N1*BStride, BStride, M, N-N1);
end
else
begin
//
// New partition:
//
// "A^T -> B" becomes "( A1 )^T -> ( B1 B2 )
// ( A2 )
//
M1 := M div 2;
if (M-M1>=8) and (M1 mod 8<>0) then
begin
M1 := M1+(8-M1 mod 8);
end;
Assert(M-M1>0);
FFTICLTRec(A, AStart, AStride, B, BStart, BStride, M1, N);
FFTICLTRec(A, AStart+2*M1*AStride, AStride, B, BStart+2*M1, BStride, M-M1, N);
end;
end;
(*************************************************************************
Recurrent subroutine for a InternalRealLinTranspose
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FFTIRLTRec(var A : TReal1DArray;
AStart : Integer;
AStride : Integer;
var B : TReal1DArray;
BStart : Integer;
BStride : Integer;
M : Integer;
N : Integer);
var
I : Integer;
J : Integer;
Idx1 : Integer;
Idx2 : Integer;
M1 : Integer;
N1 : Integer;
begin
if (M=0) or (N=0) then
begin
Exit;
end;
if Max(M, N)<=8 then
begin
I:=0;
while I<=M-1 do
begin
Idx1 := BStart+I;
Idx2 := AStart+I*AStride;
J:=0;
while J<=N-1 do
begin
B[Idx1] := A[Idx2];
Idx1 := Idx1+BStride;
Idx2 := Idx2+1;
Inc(J);
end;
Inc(I);
end;
Exit;
end;
if N>M then
begin
//
// New partition:
//
// "A^T -> B" becomes "(A1 A2)^T -> ( B1 )
// ( B2 )
//
N1 := N div 2;
if (N-N1>=8) and (N1 mod 8<>0) then
begin
N1 := N1+(8-N1 mod 8);
end;
Assert(N-N1>0);
FFTIRLTRec(A, AStart, AStride, B, BStart, BStride, M, N1);
FFTIRLTRec(A, AStart+N1, AStride, B, BStart+N1*BStride, BStride, M, N-N1);
end
else
begin
//
// New partition:
//
// "A^T -> B" becomes "( A1 )^T -> ( B1 B2 )
// ( A2 )
//
M1 := M div 2;
if (M-M1>=8) and (M1 mod 8<>0) then
begin
M1 := M1+(8-M1 mod 8);
end;
Assert(M-M1>0);
FFTIRLTRec(A, AStart, AStride, B, BStart, BStride, M1, N);
FFTIRLTRec(A, AStart+M1*AStride, AStride, B, BStart+M1, BStride, M-M1, N);
end;
end;
(*************************************************************************
recurrent subroutine for FFTFindSmoothRec
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FTBaseFindSmoothRec(N : Integer;
Seed : Integer;
LeastFactor : Integer;
var Best : Integer);
begin
Assert(FTBaseMaxSmoothFactor<=5, 'FTBaseFindSmoothRec: internal error!');
if Seed>=N then
begin
Best := Min(Best, Seed);
Exit;
end;
if LeastFactor<=2 then
begin
FTBaseFindSmoothRec(N, Seed*2, 2, Best);
end;
if LeastFactor<=3 then
begin
FTBaseFindSmoothRec(N, Seed*3, 3, Best);
end;
if LeastFactor<=5 then
begin
FTBaseFindSmoothRec(N, Seed*5, 5, Best);
end;
end;
(*************************************************************************
Internal subroutine: array resize
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************)
procedure FFTArrayResize(var A : TInteger1DArray;
var ASize : Integer;
NewASize : Integer);
var
Tmp : TInteger1DArray;
I : Integer;
begin
SetLength(Tmp, ASize);
I:=0;
while I<=ASize-1 do
begin
Tmp[I] := A[I];
Inc(I);
end;
SetLength(A, NewASize);
I:=0;
while I<=ASize-1 do
begin
A[I] := Tmp[I];
Inc(I);
end;
ASize := NewASize;
end;
(*************************************************************************
Reference FHT stub
*************************************************************************)
procedure RefFHT(var A : TReal1DArray; N : Integer; Offs : Integer);
var
Buf : TReal1DArray;
I : Integer;
J : Integer;
V : Double;
begin
Assert(N>0, 'RefFHTR1D: incorrect N!');
SetLength(Buf, N);
I:=0;
while I<=N-1 do
begin
V := 0;
J:=0;
while J<=N-1 do
begin
V := V+A[Offs+J]*(Cos(2*Pi*I*J/N)+Sin(2*Pi*I*J/N));
Inc(J);
end;
Buf[I] := V;
Inc(I);
end;
I:=0;
while I<=N-1 do
begin
A[Offs+I] := Buf[I];
Inc(I);
end;
end;
end.