18.03.2013 - Bug fixes, add in/out speed diagnostic to PIProtocol, fixed PIConsole tab switch segfault, PIObject EVENT / EVENT_HANDLER mechanism update - new EVENT macros that use EVENT_HANDLER with raiseEvent implementation.

This allow compile check event for CONNECT and use EVENT as CONNECT target, also raise event now is simple execute EVENT function.
This commit is contained in:
peri4
2013-03-18 12:07:44 +04:00
parent cfc5eed75e
commit 66c53a27fc
72 changed files with 4407 additions and 960 deletions

1134
pimath.cpp Executable file → Normal file
View File

@@ -1,7 +1,7 @@
/*
PIP - Platform Independent Primitives
Math
Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com
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
@@ -19,160 +19,6 @@
#include "pimath.h"
/*
* Fast Fourier Transformation
* ====================================================
* Coded by Miroslav Voinarovsky, 2002
* This source is freeware.
*/
// This array contains values from 0 to 255 with reverse bit order
static uchar reverse256[]= {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
};
//This is array exp(-2*pi*j/2^n) for n= 1,...,32
//exp(-2*pi*j/2^n) = complexd( cos(2*pi/2^n), -sin(2*pi/2^n) )
static complexd W2n[32] = {
complexd(-1.00000000000000000000000000000000, 0.00000000000000000000000000000000), // W2 calculator (copy/paste) : po, ps
complexd( 0.00000000000000000000000000000000, -1.00000000000000000000000000000000), // W4: p/2=o, p/2=s
complexd( 0.70710678118654752440084436210485, -0.70710678118654752440084436210485), // W8: p/4=o, p/4=s
complexd( 0.92387953251128675612818318939679, -0.38268343236508977172845998403040), // p/8=o, p/8=s
complexd( 0.98078528040323044912618223613424, -0.19509032201612826784828486847702), // p/16=
complexd( 0.99518472667219688624483695310948, -9.80171403295606019941955638886e-2), // p/32=
complexd( 0.99879545620517239271477160475910, -4.90676743274180142549549769426e-2), // p/64=
complexd( 0.99969881869620422011576564966617, -2.45412285229122880317345294592e-2), // p/128=
complexd( 0.99992470183914454092164649119638, -1.22715382857199260794082619510e-2), // p/256=
complexd( 0.99998117528260114265699043772857, -6.13588464915447535964023459037e-3), // p/(2y9)=
complexd( 0.99999529380957617151158012570012, -3.06795676296597627014536549091e-3), // p/(2y10)=
complexd( 0.99999882345170190992902571017153, -1.53398018628476561230369715026e-3), // p/(2y11)=
complexd( 0.99999970586288221916022821773877, -7.66990318742704526938568357948e-4), // p/(2y12)=
complexd( 0.99999992646571785114473148070739, -3.83495187571395589072461681181e-4), // p/(2y13)=
complexd( 0.99999998161642929380834691540291, -1.91747597310703307439909561989e-4), // p/(2y14)=
complexd( 0.99999999540410731289097193313961, -9.58737990959773458705172109764e-5), // p/(2y15)=
complexd( 0.99999999885102682756267330779455, -4.79368996030668845490039904946e-5), // p/(2y16)=
complexd( 0.99999999971275670684941397221864, -2.39684498084182187291865771650e-5), // p/(2y17)=
complexd( 0.99999999992818917670977509588385, -1.19842249050697064215215615969e-5), // p/(2y18)=
complexd( 0.99999999998204729417728262414778, -5.99211245264242784287971180889e-6), // p/(2y19)=
complexd( 0.99999999999551182354431058417300, -2.99605622633466075045481280835e-6), // p/(2y20)=
complexd( 0.99999999999887795588607701655175, -1.49802811316901122885427884615e-6), // p/(2y21)=
complexd( 0.99999999999971948897151921479472, -7.49014056584715721130498566730e-7), // p/(2y22)=
complexd( 0.99999999999992987224287980123973, -3.74507028292384123903169179084e-7), // p/(2y23)=
complexd( 0.99999999999998246806071995015625, -1.87253514146195344868824576593e-7), // p/(2y24)=
complexd( 0.99999999999999561701517998752946, -9.36267570730980827990672866808e-8), // p/(2y25)=
complexd( 0.99999999999999890425379499688176, -4.68133785365490926951155181385e-8), // p/(2y26)=
complexd( 0.99999999999999972606344874922040, -2.34066892682745527595054934190e-8), // p/(2y27)=
complexd( 0.99999999999999993151586218730510, -1.17033446341372771812462135032e-8), // p/(2y28)=
complexd( 0.99999999999999998287896554682627, -5.85167231706863869080979010083e-9), // p/(2y29)=
complexd( 0.99999999999999999571974138670657, -2.92583615853431935792823046906e-9), // p/(2y30)=
complexd( 0.99999999999999999892993534667664, -1.46291807926715968052953216186e-9), // p/(2y31)=
};
/*
* x: x - array of items
* T: 1 << T = 2 power T - number of items in array
* complement: false - normal (direct) transformation, true - reverse transformation
*/
void fft(complexd * x, int T, bool complement)
{
uint I, J, Nmax, N, Nd2, k, m, mpNd2, Skew;
uchar *Ic = (uchar*) &I;
uchar *Jc = (uchar*) &J;
complexd S;
complexd * Wstore, * Warray;
complexd WN, W, Temp, *pWN;
Nmax = 1 << T;
//first interchanging
for(I = 1; I < Nmax - 1; I++)
{
Jc[0] = reverse256[Ic[3]];
Jc[1] = reverse256[Ic[2]];
Jc[2] = reverse256[Ic[1]];
Jc[3] = reverse256[Ic[0]];
J >>= (32 - T);
if (I < J)
{
S = x[I];
x[I] = x[J];
x[J] = S;
}
}
//rotation multiplier array allocation
Wstore = new complexd[Nmax / 2];
Wstore[0] = complexd(1., 0.);
//main loop
for(N = 2, Nd2 = 1, pWN = W2n, Skew = Nmax >> 1; N <= Nmax; Nd2 = N, N += N, pWN++, Skew >>= 1)
{
//WN = W(1, N) = exp(-2*pi*j/N)
WN= *pWN;
if (complement)
WN = complexd(WN.real(), -WN.imag());
for(Warray = Wstore, k = 0; k < Nd2; k++, Warray += Skew)
{
if (k & 1)
{
W *= WN;
*Warray = W;
}
else
W = *Warray;
for(m = k; m < Nmax; m += N)
{
mpNd2 = m + Nd2;
Temp = W;
Temp *= x[mpNd2];
x[mpNd2] = x[m];
x[mpNd2] -= Temp;
x[m] += Temp;
}
}
}
delete[] Wstore;
if (complement)
{
for( I = 0; I < Nmax; I++ )
x[I] /= Nmax;
}
}
const char Solver::methods_desc[] = "b{Methods:}\
\n -1 - Global settings\
@@ -401,3 +247,981 @@ void Solver::solvePA(double u, double h, uint deg) {
}
moveF();
}
PIFFT::PIFFT() {
prepared = false;
}
PIVector<complexd> * PIFFT::calcFFT(const PIVector<complexd> & val) {
// for (uint i=0; i<result.size(); i+=2)
// {
// result[i] = val.at(indexes[i]) + val.at(indexes[i+1]);
// result[i+1] = val.at(indexes[i]) - val.at(indexes[i+1]);
// }
// return &result;
result.clear();
if (val.size_s() < 4) return &result;
fftc1d(val, val.size());
return &result;
}
PIVector<complexd> *PIFFT::calcFFTinverse(const PIVector<complexd> &val)
{
result.clear();
if (val.size_s() < 4) return &result;
fftc1dinv(val, val.size());
return &result;
}
PIVector<complexd> *PIFFT::calcHilbert(const PIVector<double> &val)
{
result.clear();
if (val.size_s() < 4) return &result;
fftc1r(val, val.size());
for (uint i=0; i<result.size()/2; i++) result[i] = result[i]*2.;
for (uint i=result.size()/2; i<result.size(); i++) result[i] = 0;
fftc1dinv(result, result.size());
return &result;
}
PIVector< complexd >* PIFFT::calcFFT(const PIVector<double> & val) {
result.clear();
if (val.size_s() < 4) return &result;
fftc1r(val, val.size());
return &result;
}
PIVector<double> PIFFT::getAmplitude() {
PIVector<double> a;
double tmp;
for (uint i=0; i<result.size(); i++) {
tmp = sqrt(result.at(i).real()*result.at(i).real()+result.at(i).imag()*result.at(i).imag());
a.push_back(tmp);
}
return a;
}
void PIFFT::fftc1d(const PIVector<complexd> &a, uint n) {
createPlan(n);
uint i;
PIVector<double> buf;
buf.resize(2*n);
for(i=0; i<n; i++) {
buf[2*i+0] = a.at(i).real();// a->ptr.p_complex[i].x;
buf[2*i+1] = a.at(i).imag();//a->ptr.p_complex[i].y;
}
ftbaseexecuteplan(&buf, 0, n, &curplan);
result.resize(n);
for(i=0; i<n; i++)
result[i]=complexd(buf[2*i+0],buf[2*i+1]);
}
void PIFFT::fftc1r(const PIVector<double> & a, uint n) {
uint i;
if( n%2==0 ) {
PIVector<double> buf;
uint n2 = n/2;
//buf.resize(n);
buf = a;
createPlan(n2);
//cout << "fftr " << n2 << endl;
ftbaseexecuteplan(&buf, 0, n2, &curplan);
result.resize(n);
uint idx;
complexd hn, hmnc, v;
for(i=0; i<=n2; i++) {
idx = 2*(i%n2);
hn = complexd(buf[idx+0], buf[idx+1]);
idx = 2*((n2-i)%n2);
hmnc = complexd(buf[idx+0], -buf[idx+1]);
v = complexd(sin(M_PI*i/n2), cos(M_PI*i/n2));
result[i] = ((hn + hmnc) - (v * (hn - hmnc)));
result[i] *= 0.5;
}
for(i=n2+1; i<n; i++)
result[i] = conj(result[n-i]);
} else {
PIVector<complexd> cbuf;
cbuf.resize(n);
for(i=0; i<n; i++)
cbuf[i] = complexd(a[i], 0.);
fftc1d(cbuf, n);
}
}
void PIFFT::fftc1dinv(const PIVector<complexd> &a, uint n)
{
PIVector<complexd> cbuf;
cbuf.resize(n);
uint i;
for(i=0; i<n; i++)
{
cbuf[i] = conj(a[i]);
}
fftc1d(cbuf, n);
// result.resize(n);
for(i=0; i<n; i++)
{
result[i] = conj(result[i] / (double)n);
}
}
void PIFFT::createPlan(uint n) {
curplan.plan.clear();
curplan.precomputed.clear();
curplan.stackbuf.clear();
curplan.tmpbuf.clear();
if (n<2) return;
ftbasegeneratecomplexfftplan(n, &curplan);
prepared = true;
}
void PIFFT::ftbasegeneratecomplexfftplan(uint n, ftplan* plan) {
int planarraysize;
int plansize;
int precomputedsize;
int tmpmemsize;
int stackmemsize;
ae_int_t stackptr;
planarraysize = 1;
plansize = 0;
precomputedsize = 0;
stackmemsize = 0;
stackptr = 0;
tmpmemsize = 2*n;
curplan.plan.resize(planarraysize);
int ftbase_ftbasecffttask = 0;
ftbase_ftbasegenerateplanrec(n, ftbase_ftbasecffttask, plan, &plansize, &precomputedsize, &planarraysize, &tmpmemsize, &stackmemsize, stackptr);
if (stackptr!=0) { return;}//ae_assert(stackptr==0, "Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!");
curplan.stackbuf.resize(piMax(stackmemsize,1));//ae_vector_set_length(&curplan.stackbuf, ae_maxint(stackmemsize, 1));
curplan.tmpbuf.resize(piMax(tmpmemsize,1));//ae_vector_set_length(&(curplan.tmpbuf), ae_maxint(tmpmemsize, 1));
curplan.precomputed.resize(piMax(precomputedsize,1));//ae_vector_set_length(&curplan.precomputed, ae_maxint(precomputedsize, 1));
stackptr = 0;
ftbase_ftbaseprecomputeplanrec(plan, 0, stackptr);
if (stackptr!=0) { return;}//ae_assert(stackptr==0, "Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!");
}
/*************************************************************************
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
*************************************************************************/
void PIFFT::ftbase_ftbasegenerateplanrec(
int n,
int tasktype,
ftplan* plan,
int* plansize,
int* precomputedsize,
int* planarraysize,
int* tmpmemsize,
int* stackmemsize,
ae_int_t stackptr, int debugi)
{
int k, m, n1, n2, esize, entryoffset;
int ftbase_ftbaseplanentrysize = 8;
int ftbase_ftbasecffttask = 0;
int ftbase_fftcooleytukeyplan = 0;
int ftbase_fftbluesteinplan = 1;
int ftbase_fftcodeletplan = 2;
int ftbase_fftrealcooleytukeyplan = 5;
int ftbase_fftemptyplan = 6;
if( *plansize+ftbase_ftbaseplanentrysize>(*planarraysize) ) {
curplan.plan.resize(8*(*planarraysize));
*planarraysize = 8*(*planarraysize);
}
entryoffset = *plansize;
esize = ftbase_ftbaseplanentrysize;
*plansize = *plansize+esize;
if( n==1 ) {
curplan.plan[entryoffset+0] = esize;
curplan.plan[entryoffset+1] = -1;
curplan.plan[entryoffset+2] = -1;
curplan.plan[entryoffset+3] = ftbase_fftemptyplan;
curplan.plan[entryoffset+4] = -1;
curplan.plan[entryoffset+5] = -1;
curplan.plan[entryoffset+6] = -1;
curplan.plan[entryoffset+7] = -1;
return;
}
ftbasefactorize(n, &n1, &n2);
if( n1!=1 ) {
*tmpmemsize = piMax(*tmpmemsize, 2*n1*n2);
curplan.plan[entryoffset+0] = esize;
curplan.plan[entryoffset+1] = n1;
curplan.plan[entryoffset+2] = n2;
if( tasktype==ftbase_ftbasecffttask )
curplan.plan[entryoffset+3] = ftbase_fftcooleytukeyplan;
else
curplan.plan[entryoffset+3] = ftbase_fftrealcooleytukeyplan;
curplan.plan[entryoffset+4] = 0;
curplan.plan[entryoffset+5] = *plansize;
debugi++;
ftbase_ftbasegenerateplanrec(n1, ftbase_ftbasecffttask, plan, plansize, precomputedsize, planarraysize, tmpmemsize, stackmemsize, stackptr,debugi);
curplan.plan[entryoffset+6] = *plansize;
ftbase_ftbasegenerateplanrec(n2, ftbase_ftbasecffttask, plan, plansize, precomputedsize, planarraysize, tmpmemsize, stackmemsize, stackptr,debugi);
curplan.plan[entryoffset+7] = -1;
return;
} else {
if (n>=2 && n<=5) {
curplan.plan[entryoffset+0] = esize;
curplan.plan[entryoffset+1] = n1;
curplan.plan[entryoffset+2] = n2;
curplan.plan[entryoffset+3] = ftbase_fftcodeletplan;
curplan.plan[entryoffset+4] = 0;
curplan.plan[entryoffset+5] = -1;
curplan.plan[entryoffset+6] = -1;
curplan.plan[entryoffset+7] = *precomputedsize;
if( n==3 )
*precomputedsize = *precomputedsize+2;
if( n==5 )
*precomputedsize = *precomputedsize+5;
return;
} else {
k = 2*n2-1;
m = ftbasefindsmooth(k);
*tmpmemsize = piMax(*tmpmemsize, 2*m);
curplan.plan[entryoffset+0] = esize;
curplan.plan[entryoffset+1] = n2;
curplan.plan[entryoffset+2] = -1;
curplan.plan[entryoffset+3] = ftbase_fftbluesteinplan;
curplan.plan[entryoffset+4] = m;
curplan.plan[entryoffset+5] = *plansize;
stackptr = stackptr+2*2*m;
*stackmemsize = piMax(*stackmemsize, stackptr);
ftbase_ftbasegenerateplanrec(m, ftbase_ftbasecffttask, plan, plansize, precomputedsize, planarraysize, tmpmemsize, stackmemsize, stackptr);
stackptr = stackptr-2*2*m;
curplan.plan[entryoffset+6] = -1;
curplan.plan[entryoffset+7] = *precomputedsize;
*precomputedsize = *precomputedsize+2*m+2*n;
return;
}
}
}
/*************************************************************************
Recurrent subroutine for precomputing FFT plans
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************/
void PIFFT::ftbase_ftbaseprecomputeplanrec(ftplan* plan,
int entryoffset,
ae_int_t stackptr)
{
int n1, n2, n, m, offs;
double v, bx, by;
int ftbase_fftcooleytukeyplan = 0;
int ftbase_fftbluesteinplan = 1;
int ftbase_fftcodeletplan = 2;
int ftbase_fhtcooleytukeyplan = 3;
int ftbase_fhtcodeletplan = 4;
int ftbase_fftrealcooleytukeyplan = 5;
if( (curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan||curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan)||curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan ) {
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+5], stackptr);
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+6], stackptr);
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan||curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan ) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
if( n==3 ) {
offs = curplan.plan[entryoffset+7];
curplan.precomputed[offs+0] = cos(2*M_PI/3)-1;
curplan.precomputed[offs+1] = sin(2*M_PI/3);
return;
}
if( n==5 ) {
offs = curplan.plan[entryoffset+7];
v = 2*M_PI/5;
curplan.precomputed[offs+0] = (cos(v)+cos(2*v))/2-1;
curplan.precomputed[offs+1] = (cos(v)-cos(2*v))/2;
curplan.precomputed[offs+2] = -sin(v);
curplan.precomputed[offs+3] = -(sin(v)+sin(2*v));
curplan.precomputed[offs+4] = sin(v)-sin(2*v);
return;
}
}
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan ) {
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+5], stackptr);
n = curplan.plan[entryoffset+1];
m = curplan.plan[entryoffset+4];
offs = curplan.plan[entryoffset+7];
for(int i=0; i<=2*m-1; i++)
curplan.precomputed[offs+i] = 0;
for(int i=0; i<n; i++) {
bx = cos(M_PI*sqr(i)/n);
by = sin(M_PI*sqr(i)/n);
curplan.precomputed[offs+2*i+0] = bx;
curplan.precomputed[offs+2*i+1] = by;
curplan.precomputed[offs+2*m+2*i+0] = bx;
curplan.precomputed[offs+2*m+2*i+1] = by;
if( i>0 ) {
curplan.precomputed[offs+2*(m-i)+0] = bx;
curplan.precomputed[offs+2*(m-i)+1] = by;
}
}
ftbaseexecuteplanrec(&curplan.precomputed, offs, plan, curplan.plan[entryoffset+5], stackptr);
return;
}
}
void PIFFT::ftbasefactorize(int n, int* n1, int* n2) {
*n1 = *n2 = 0;
int ftbase_ftbasecodeletrecommended = 5;
if( (*n1)*(*n2)!=n ) {
for(int j=ftbase_ftbasecodeletrecommended; j>=2; j--) {
if( n%j==0 ) {
*n1 = j;
*n2 = n/j;
break;
}
}
}
if( (*n1)*(*n2)!=n ) {
for(int j=ftbase_ftbasecodeletrecommended+1; j<=n-1; j++) {
if( n%j==0 ) {
*n1 = j;
*n2 = n/j;
break;
}
}
}
if( (*n1)*(*n2)!=n ) {
*n1 = 1;
*n2 = n;
}
if( (*n2)==1 && (*n1)!=1 ) {
*n2 = *n1;
*n1 = 1;
}
}
/*************************************************************************
Is number smooth?
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************/
void PIFFT::ftbase_ftbasefindsmoothrec(int n, int seed, int leastfactor, int* best) {
if( seed>=n ) {
*best = piMin(*best, seed);
return;
}
if( leastfactor<=2 )
ftbase_ftbasefindsmoothrec(n, seed*2, 2, best);
if( leastfactor<=3 )
ftbase_ftbasefindsmoothrec(n, seed*3, 3, best);
if( leastfactor<=5 )
ftbase_ftbasefindsmoothrec(n, seed*5, 5, best);
}
int PIFFT::ftbasefindsmooth(int n) {
int best, result;
best = 2;
while(best<n)
best = 2*best;
ftbase_ftbasefindsmoothrec(n, 1, 2, &best);
result = best;
return result;
}
void PIFFT::ftbase_internalreallintranspose(PIVector<double>* a, int m, int n, int astart, PIVector<double>* buf) {
ftbase_fftirltrec(a, astart, n, buf, 0, m, m, n);
for (int i=0; i<2*m*n; i++) (*a)[astart+i] = (*buf)[i];
}
void PIFFT::ftbase_fftirltrec(PIVector<double>* a, int astart, int astride, PIVector<double>* b, int bstart, int bstride, int m, int n) {
int idx1, idx2;
int m1, n1;
if( m==0||n==0 )
return;
if( piMax(m, n)<=8 ) {
for(int i=0; i<=m-1; i++) {
idx1 = bstart+i;
idx2 = astart+i*astride;
for(int j=0; j<=n-1; j++) {
(*b)[idx1] = a->at(idx2);
idx1 = idx1+bstride;
idx2 = idx2+1;
}
}
return;
}
if( n>m ) {
n1 = n/2;
if( n-n1>=8&&n1%8!=0 )
n1 = n1+(8-n1%8);
ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m, n1);
ftbase_fftirltrec(a, astart+n1, astride, b, bstart+n1*bstride, bstride, m, n-n1);
} else {
m1 = m/2;
if( m-m1>=8&&m1%8!=0 )
m1 = m1+(8-m1%8);
ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m1, n);
ftbase_fftirltrec(a, astart+m1*astride, astride, b, bstart+m1, bstride, m-m1, n);
}
}
void PIFFT::ftbase_internalcomplexlintranspose(PIVector<double>* a, int m, int n, int astart, PIVector<double>* buf) {
ftbase_ffticltrec(a, astart, n, buf, 0, m, m, n);
for (int i=0; i<2*m*n; i++)
(*a)[astart+i] = (*buf)[i];
}
void PIFFT::ftbase_ffticltrec(PIVector<double>* a, int astart, int astride, PIVector<double>* b, int bstart, int bstride, int m, int n) {
int idx1, idx2, m2, m1, n1;
if( m==0||n==0 )
return;
if( piMax(m, n)<=8 ) {
m2 = 2*bstride;
for(int i=0; i<=m-1; i++) {
idx1 = bstart+2*i;
idx2 = astart+2*i*astride;
for(int j=0; j<=n-1; j++) {
(*b)[idx1+0] = a->at(idx2+0);
(*b)[idx1+1] = a->at(idx2+1);
idx1 = idx1+m2;
idx2 = idx2+2;
}
}
return;
}
if( n>m ) {
n1 = n/2;
if( n-n1>=8&&n1%8!=0 )
n1 = n1+(8-n1%8);
ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m, n1);
ftbase_ffticltrec(a, astart+2*n1, astride, b, bstart+2*n1*bstride, bstride, m, n-n1);
} else {
m1 = m/2;
if( m-m1>=8&&m1%8!=0 )
m1 = m1+(8-m1%8);
ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m1, n);
ftbase_ffticltrec(a, astart+2*m1*astride, astride, b, bstart+2*m1, bstride, m-m1, n);
}
}
void PIFFT::ftbaseexecuteplan(PIVector<double>* a, int aoffset, int n, ftplan* plan) {
ae_int_t stackptr;
stackptr = 0;
ftbaseexecuteplanrec(a, aoffset, plan, 0, stackptr);
}
/*************************************************************************
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
*************************************************************************/
void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan, int entryoffset, ae_int_t stackptr) {
int n1, n2, n, m, offs, offs1, offs2, offsa, offsb, offsp;
double hk, hnk, x, y, bx, by, v0, v1, v2, v3;
double a0x, a0y, a1x, a1y, a2x, a2y, a3x, a3y;
double t1x, t1y, t2x, t2y, t3x, t3y, t4x, t4y, t5x, t5y;
double m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y, m5x, m5y;
double s1x, s1y, s2x, s2y, s3x, s3y, s4x, s4y, s5x, s5y;
double c1, c2, c3, c4, c5;
int ftbase_fftcooleytukeyplan = 0;
int ftbase_fftbluesteinplan = 1;
int ftbase_fftcodeletplan = 2;
int ftbase_fhtcooleytukeyplan = 3;
int ftbase_fhtcodeletplan = 4;
int ftbase_fftrealcooleytukeyplan = 5;
int ftbase_fftemptyplan = 6;
PIVector<double> & tmpb(curplan.tmpbuf);
if( curplan.plan[entryoffset+3]==ftbase_fftemptyplan )
return;
if( curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan ) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
for(int i=0; i<=n2-1; i++)
ftbaseexecuteplanrec(a, aoffset+i*n1*2, plan, curplan.plan[entryoffset+5], stackptr);
ftbase_ffttwcalc(a, aoffset, n1, n2);
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
for(int i=0; i<=n1-1; i++)
ftbaseexecuteplanrec(a, aoffset+i*n2*2, plan, curplan.plan[entryoffset+6], stackptr);
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan ) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
for(int i=0; i<=n1/2-1; i++) {
offs = aoffset+2*i*n2*2;
for(int k=0; k<=n2-1; k++)
(*a)[offs+2*k+1] = (*a)[offs+2*n2+2*k+0];
ftbaseexecuteplanrec(a, offs, plan, curplan.plan[entryoffset+6], stackptr);
tmpb[0] = (*a)[offs+0];
tmpb[1] = 0;
tmpb[2*n2+0] = (*a)[offs+1];
tmpb[2*n2+1] = 0;
for(int k=1; k<=n2-1; k++) {
offs1 = 2*k;
offs2 = 2*n2+2*k;
hk = (*a)[offs+2*k+0];
hnk = (*a)[offs+2*(n2-k)+0];
tmpb[offs1+0] = 0.5*(hk+hnk);
tmpb[offs2+1] = -0.5*(hk-hnk);
hk = (*a)[offs+2*k+1];
hnk = (*a)[offs+2*(n2-k)+1];
tmpb[offs2+0] = 0.5*(hk+hnk);
tmpb[offs1+1] = 0.5*(hk-hnk);
}
for (int i=0; i<2*n2*2; i++) (*a)[offs+i] = tmpb[i];
}
if( n1%2!=0 )
ftbaseexecuteplanrec(a, aoffset+(n1-1)*n2*2, plan, curplan.plan[entryoffset+6], stackptr);
ftbase_ffttwcalc(a, aoffset, n2, n1);
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
for(int i=0; i<=n2-1; i++)
ftbaseexecuteplanrec(a, aoffset+i*n1*2, plan, curplan.plan[entryoffset+5], stackptr);
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan ) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
ftbase_internalreallintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
for(int i=0; i<=n2-1; i++)
ftbaseexecuteplanrec(a, aoffset+i*n1, plan, curplan.plan[entryoffset+5], stackptr);
for(int i=0; i<=n2-1; i++) {
for(int j=0; j<=n1-1; j++) {
offsa = aoffset+i*n1;
hk = (*a)[offsa+j];
hnk = (*a)[offsa+(n1-j)%n1];
offs = 2*(i*n1+j);
tmpb[offs+0] = -0.5*(hnk-hk);
tmpb[offs+1] = 0.5*(hk+hnk);
}
}
ftbase_ffttwcalc(&(curplan.tmpbuf), 0, n1, n2);
for(int j=0; j<=n1-1; j++)
(*a)[aoffset+j] = tmpb[2*j+0]+tmpb[2*j+1];
if( n2%2==0 ) {
offs = 2*(n2/2)*n1;
offsa = aoffset+n2/2*n1;
for(int j=0; j<=n1-1; j++)
(*a)[offsa+j] = tmpb[offs+2*j+0]+tmpb[offs+2*j+1];
}
for(int i=1; i<=(n2+1)/2-1; i++) {
offs = 2*i*n1;
offs2 = 2*(n2-i)*n1;
offsa = aoffset+i*n1;
for(int j=0; j<=n1-1; j++)
(*a)[offsa+j] = tmpb[offs+2*j+1]+tmpb[offs2+2*j+0];
offsa = aoffset+(n2-i)*n1;
for(int j=0; j<=n1-1; j++)
(*a)[offsa+j] = tmpb[offs+2*j+0]+tmpb[offs2+2*j+1];
}
ftbase_internalreallintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
for(int i=0; i<=n1-1; i++)
ftbaseexecuteplanrec(a, aoffset+i*n2, plan, curplan.plan[entryoffset+6], stackptr);
ftbase_internalreallintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan ) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
if( n==2 ) {
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;
return;
}
if( n==3 ) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.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;
return;
}
if( n==4 ) {
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;
return;
}
if( n==5 ) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.precomputed[offs+1];
c3 = curplan.precomputed[offs+2];
c4 = curplan.precomputed[offs+3];
c5 = curplan.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;
return;
}
}
if( curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan ) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
if( n==2 ) {
a0x = (*a)[aoffset+0];
a1x = (*a)[aoffset+1];
(*a)[aoffset+0] = a0x+a1x;
(*a)[aoffset+1] = a0x-a1x;
return;
}
if( n==3 ) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.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;
return;
}
if( n==4 ) {
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;
return;
}
if( n==5 ) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.precomputed[offs+1];
c3 = curplan.precomputed[offs+2];
c4 = curplan.precomputed[offs+3];
c5 = curplan.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;
return;
}
}
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan ) {
n = curplan.plan[entryoffset+1];
m = curplan.plan[entryoffset+4];
offs = curplan.plan[entryoffset+7];
for(int i=stackptr+2*n; i<=stackptr+2*m-1; i++)
curplan.stackbuf[i] = 0;
offsp = offs+2*m;
offsa = aoffset;
offsb = stackptr;
for(int i=0; i<n; i++) {
bx = curplan.precomputed[offsp+0];
by = curplan.precomputed[offsp+1];
x = (*a)[offsa+0];
y = (*a)[offsa+1];
curplan.stackbuf[offsb+0] = x*bx-y*(-by);
curplan.stackbuf[offsb+1] = x*(-by)+y*bx;
offsp = offsp+2;
offsa = offsa+2;
offsb = offsb+2;
}
ftbaseexecuteplanrec(&curplan.stackbuf, stackptr, plan, curplan.plan[entryoffset+5], stackptr+2*2*m);
offsb = stackptr;
offsp = offs;
for(int i=0; i<=m-1; i++) {
x = curplan.stackbuf[offsb+0];
y = curplan.stackbuf[offsb+1];
bx = curplan.precomputed[offsp+0];
by = curplan.precomputed[offsp+1];
curplan.stackbuf[offsb+0] = x*bx-y*by;
curplan.stackbuf[offsb+1] = -(x*by+y*bx);
offsb = offsb+2;
offsp = offsp+2;
}
ftbaseexecuteplanrec(&curplan.stackbuf, stackptr, plan, curplan.plan[entryoffset+5], stackptr+2*2*m);
offsb = stackptr;
offsp = offs+2*m;
offsa = aoffset;
for(int i=0; i<n; i++) {
x = curplan.stackbuf[offsb+0]/m;
y = -curplan.stackbuf[offsb+1]/m;
bx = curplan.precomputed[offsp+0];
by = curplan.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;
}
return;
}
}
/*************************************************************************
Twiddle factors calculation
-- ALGLIB --
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************/
void PIFFT::ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2) {
int n, idx, offs;
double x, y, twxm1, twy, twbasexm1, twbasey, twrowxm1, twrowy, tmpx, tmpy, v;
int ftbase_ftbaseupdatetw = 4;
n = n1*n2;
v = -2*M_PI/n;
twbasexm1 = -2*sqr(sin(0.5*v));
twbasey = sin(v);
twrowxm1 = 0;
twrowy = 0;
for(int i=0, j = 0; i<=n2-1; i++) {
twxm1 = 0;
twy = 0;
for(j=0; j<=n1-1; j++) {
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;
if( j<n1-1 ) {
if( j%ftbase_ftbaseupdatetw==0 ) {
v = -2*M_PI*i*(j+1)/n;
twxm1 = -2*sqr(sin(0.5*v));
twy = sin(v);
} else {
tmpx = twrowxm1+twxm1*twrowxm1-twy*twrowy;
tmpy = twrowy+twxm1*twrowy+twy*twrowxm1;
twxm1 = twxm1+tmpx;
twy = twy+tmpy;
}
}
}
if( i<n2-1 ) {
if( j%ftbase_ftbaseupdatetw==0 ) {
v = -2*M_PI*(i+1)/n;
twrowxm1 = -2*sqr(sin(0.5*v));
twrowy = sin(v);
} else {
tmpx = twbasexm1+twrowxm1*twbasexm1-twrowy*twbasey;
tmpy = twbasey+twrowxm1*twbasey+twrowy*twbasexm1;
twrowxm1 = twrowxm1+tmpx;
twrowy = twrowy+tmpy;
}
}
}
}
PIStatistic::PIStatistic() {
mean = 0.;
variance = 0.;
skewness = 0.;
kurtosis = 0.;
}
bool PIStatistic::calculate(const PIVector<double> & val) {
double v = 0., v1 = 0., v2 = 0., stddev = 0.;
int i, n = val.size();
if (n < 2)
return false;
/*
* Mean
*/
for (i = 0; i < n; i++)
mean += val[i];
mean /= n;
/*
* Variance (using corrected two-pass algorithm)
*/
for (i = 0; i < n; i++)
v1 += sqr(val[i] - mean);
for (i = 0; i < n; i++)
v2 += val[i] - mean;
v2 = sqr(v2) / n;
variance = (v1 - v2) / (n - 1);
if(variance < 0)
variance = 0.;
stddev = sqrt(variance);
/*
* Skewness and kurtosis
*/
if (stddev != 0) {
for (i = 0; i < n; i++) {
v = (val[i] - mean) / stddev;
v2 = sqr(v);
skewness = skewness + v2 * v;
kurtosis = kurtosis + sqr(v2);
}
skewness /= n;
kurtosis = kurtosis / n - 3.;
}
return true;
}