Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/3.9.0/ALGLIB-3.9.0/fasttransforms.cs @ 12790

Last change on this file since 12790 was 12790, checked in by gkronber, 9 years ago

#2435: updated alglib to version 3.9.0

File size: 113.2 KB
Line 
1/*************************************************************************
2ALGLIB 3.9.0 (source code generated 2014-12-11)
3Copyright (c) Sergey Bochkanov (ALGLIB project).
4
5>>> SOURCE LICENSE >>>
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation (www.fsf.org); either version 2 of the
9License, or (at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16A copy of the GNU General Public License is available at
17http://www.fsf.org/licensing/licenses
18>>> END OF LICENSE >>>
19*************************************************************************/
20#pragma warning disable 162
21#pragma warning disable 219
22using System;
23
24public partial class alglib
25{
26
27
28    /*************************************************************************
29    1-dimensional complex FFT.
30
31    Array size N may be arbitrary number (composite or prime).  Composite  N's
32    are handled with cache-oblivious variation of  a  Cooley-Tukey  algorithm.
33    Small prime-factors are transformed using hard coded  codelets (similar to
34    FFTW codelets, but without low-level  optimization),  large  prime-factors
35    are handled with Bluestein's algorithm.
36
37    Fastests transforms are for smooth N's (prime factors are 2, 3,  5  only),
38    most fast for powers of 2. When N have prime factors  larger  than  these,
39    but orders of magnitude smaller than N, computations will be about 4 times
40    slower than for nearby highly composite N's. When N itself is prime, speed
41    will be 6 times lower.
42
43    Algorithm has O(N*logN) complexity for any N (composite or prime).
44
45    INPUT PARAMETERS
46        A   -   array[0..N-1] - complex function to be transformed
47        N   -   problem size
48
49    OUTPUT PARAMETERS
50        A   -   DFT of a input array, array[0..N-1]
51                A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
52
53
54      -- ALGLIB --
55         Copyright 29.05.2009 by Bochkanov Sergey
56    *************************************************************************/
57    public static void fftc1d(ref complex[] a, int n)
58    {
59
60        fft.fftc1d(ref a, n);
61        return;
62    }
63    public static void fftc1d(ref complex[] a)
64    {
65        int n;
66
67
68        n = ap.len(a);
69        fft.fftc1d(ref a, n);
70
71        return;
72    }
73
74    /*************************************************************************
75    1-dimensional complex inverse FFT.
76
77    Array size N may be arbitrary number (composite or prime).  Algorithm  has
78    O(N*logN) complexity for any N (composite or prime).
79
80    See FFTC1D() description for more information about algorithm performance.
81
82    INPUT PARAMETERS
83        A   -   array[0..N-1] - complex array to be transformed
84        N   -   problem size
85
86    OUTPUT PARAMETERS
87        A   -   inverse DFT of a input array, array[0..N-1]
88                A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
89
90
91      -- ALGLIB --
92         Copyright 29.05.2009 by Bochkanov Sergey
93    *************************************************************************/
94    public static void fftc1dinv(ref complex[] a, int n)
95    {
96
97        fft.fftc1dinv(ref a, n);
98        return;
99    }
100    public static void fftc1dinv(ref complex[] a)
101    {
102        int n;
103
104
105        n = ap.len(a);
106        fft.fftc1dinv(ref a, n);
107
108        return;
109    }
110
111    /*************************************************************************
112    1-dimensional real FFT.
113
114    Algorithm has O(N*logN) complexity for any N (composite or prime).
115
116    INPUT PARAMETERS
117        A   -   array[0..N-1] - real function to be transformed
118        N   -   problem size
119
120    OUTPUT PARAMETERS
121        F   -   DFT of a input array, array[0..N-1]
122                F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
123
124    NOTE:
125        F[] satisfies symmetry property F[k] = conj(F[N-k]),  so just one half
126    of  array  is  usually needed. But for convinience subroutine returns full
127    complex array (with frequencies above N/2), so its result may be  used  by
128    other FFT-related subroutines.
129
130
131      -- ALGLIB --
132         Copyright 01.06.2009 by Bochkanov Sergey
133    *************************************************************************/
134    public static void fftr1d(double[] a, int n, out complex[] f)
135    {
136        f = new complex[0];
137        fft.fftr1d(a, n, ref f);
138        return;
139    }
140    public static void fftr1d(double[] a, out complex[] f)
141    {
142        int n;
143
144        f = new complex[0];
145        n = ap.len(a);
146        fft.fftr1d(a, n, ref f);
147
148        return;
149    }
150
151    /*************************************************************************
152    1-dimensional real inverse FFT.
153
154    Algorithm has O(N*logN) complexity for any N (composite or prime).
155
156    INPUT PARAMETERS
157        F   -   array[0..floor(N/2)] - frequencies from forward real FFT
158        N   -   problem size
159
160    OUTPUT PARAMETERS
161        A   -   inverse DFT of a input array, array[0..N-1]
162
163    NOTE:
164        F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just  one
165    half of frequencies array is needed - elements from 0 to floor(N/2).  F[0]
166    is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd,  then
167    F[floor(N/2)] has no special properties.
168
169    Relying on properties noted above, FFTR1DInv subroutine uses only elements
170    from 0th to floor(N/2)-th. It ignores imaginary part of F[0],  and in case
171    N is even it ignores imaginary part of F[floor(N/2)] too.
172
173    When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
174    - you can pass either either frequencies array with N elements or  reduced
175    array with roughly N/2 elements - subroutine will  successfully  transform
176    both.
177
178    If you call this function using reduced arguments list -  "FFTR1DInv(F,A)"
179    - you must pass FULL array with N elements (although higher  N/2 are still
180    not used) because array size is used to automatically determine FFT length
181
182
183      -- ALGLIB --
184         Copyright 01.06.2009 by Bochkanov Sergey
185    *************************************************************************/
186    public static void fftr1dinv(complex[] f, int n, out double[] a)
187    {
188        a = new double[0];
189        fft.fftr1dinv(f, n, ref a);
190        return;
191    }
192    public static void fftr1dinv(complex[] f, out double[] a)
193    {
194        int n;
195
196        a = new double[0];
197        n = ap.len(f);
198        fft.fftr1dinv(f, n, ref a);
199
200        return;
201    }
202
203}
204public partial class alglib
205{
206
207
208    /*************************************************************************
209    1-dimensional complex convolution.
210
211    For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
212    choose between three implementations: straightforward O(M*N)  formula  for
213    very small N (or M), overlap-add algorithm for  cases  where  max(M,N)  is
214    significantly larger than min(M,N), but O(M*N) algorithm is too slow,  and
215    general FFT-based formula for cases where two previois algorithms are  too
216    slow.
217
218    Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.
219
220    INPUT PARAMETERS
221        A   -   array[0..M-1] - complex function to be transformed
222        M   -   problem size
223        B   -   array[0..N-1] - complex function to be transformed
224        N   -   problem size
225
226    OUTPUT PARAMETERS
227        R   -   convolution: A*B. array[0..N+M-2].
228
229    NOTE:
230        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
231    functions have non-zero values at negative T's, you  can  still  use  this
232    subroutine - just shift its result correspondingly.
233
234      -- ALGLIB --
235         Copyright 21.07.2009 by Bochkanov Sergey
236    *************************************************************************/
237    public static void convc1d(complex[] a, int m, complex[] b, int n, out complex[] r)
238    {
239        r = new complex[0];
240        conv.convc1d(a, m, b, n, ref r);
241        return;
242    }
243
244    /*************************************************************************
245    1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
246
247    Algorithm has M*log(M)) complexity for any M (composite or prime).
248
249    INPUT PARAMETERS
250        A   -   array[0..M-1] - convolved signal, A = conv(R, B)
251        M   -   convolved signal length
252        B   -   array[0..N-1] - response
253        N   -   response length, N<=M
254
255    OUTPUT PARAMETERS
256        R   -   deconvolved signal. array[0..M-N].
257
258    NOTE:
259        deconvolution is unstable process and may result in division  by  zero
260    (if your response function is degenerate, i.e. has zero Fourier coefficient).
261
262    NOTE:
263        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
264    functions have non-zero values at negative T's, you  can  still  use  this
265    subroutine - just shift its result correspondingly.
266
267      -- ALGLIB --
268         Copyright 21.07.2009 by Bochkanov Sergey
269    *************************************************************************/
270    public static void convc1dinv(complex[] a, int m, complex[] b, int n, out complex[] r)
271    {
272        r = new complex[0];
273        conv.convc1dinv(a, m, b, n, ref r);
274        return;
275    }
276
277    /*************************************************************************
278    1-dimensional circular complex convolution.
279
280    For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
281    complexity for any M/N.
282
283    IMPORTANT:  normal convolution is commutative,  i.e.   it  is symmetric  -
284    conv(A,B)=conv(B,A).  Cyclic convolution IS NOT.  One function - S - is  a
285    signal,  periodic function, and another - R - is a response,  non-periodic
286    function with limited length.
287
288    INPUT PARAMETERS
289        S   -   array[0..M-1] - complex periodic signal
290        M   -   problem size
291        B   -   array[0..N-1] - complex non-periodic response
292        N   -   problem size
293
294    OUTPUT PARAMETERS
295        R   -   convolution: A*B. array[0..M-1].
296
297    NOTE:
298        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
299    negative T's, you can still use this subroutine - just  shift  its  result
300    correspondingly.
301
302      -- ALGLIB --
303         Copyright 21.07.2009 by Bochkanov Sergey
304    *************************************************************************/
305    public static void convc1dcircular(complex[] s, int m, complex[] r, int n, out complex[] c)
306    {
307        c = new complex[0];
308        conv.convc1dcircular(s, m, r, n, ref c);
309        return;
310    }
311
312    /*************************************************************************
313    1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
314
315    Algorithm has M*log(M)) complexity for any M (composite or prime).
316
317    INPUT PARAMETERS
318        A   -   array[0..M-1] - convolved periodic signal, A = conv(R, B)
319        M   -   convolved signal length
320        B   -   array[0..N-1] - non-periodic response
321        N   -   response length
322
323    OUTPUT PARAMETERS
324        R   -   deconvolved signal. array[0..M-1].
325
326    NOTE:
327        deconvolution is unstable process and may result in division  by  zero
328    (if your response function is degenerate, i.e. has zero Fourier coefficient).
329
330    NOTE:
331        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
332    negative T's, you can still use this subroutine - just  shift  its  result
333    correspondingly.
334
335      -- ALGLIB --
336         Copyright 21.07.2009 by Bochkanov Sergey
337    *************************************************************************/
338    public static void convc1dcircularinv(complex[] a, int m, complex[] b, int n, out complex[] r)
339    {
340        r = new complex[0];
341        conv.convc1dcircularinv(a, m, b, n, ref r);
342        return;
343    }
344
345    /*************************************************************************
346    1-dimensional real convolution.
347
348    Analogous to ConvC1D(), see ConvC1D() comments for more details.
349
350    INPUT PARAMETERS
351        A   -   array[0..M-1] - real function to be transformed
352        M   -   problem size
353        B   -   array[0..N-1] - real function to be transformed
354        N   -   problem size
355
356    OUTPUT PARAMETERS
357        R   -   convolution: A*B. array[0..N+M-2].
358
359    NOTE:
360        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
361    functions have non-zero values at negative T's, you  can  still  use  this
362    subroutine - just shift its result correspondingly.
363
364      -- ALGLIB --
365         Copyright 21.07.2009 by Bochkanov Sergey
366    *************************************************************************/
367    public static void convr1d(double[] a, int m, double[] b, int n, out double[] r)
368    {
369        r = new double[0];
370        conv.convr1d(a, m, b, n, ref r);
371        return;
372    }
373
374    /*************************************************************************
375    1-dimensional real deconvolution (inverse of ConvC1D()).
376
377    Algorithm has M*log(M)) complexity for any M (composite or prime).
378
379    INPUT PARAMETERS
380        A   -   array[0..M-1] - convolved signal, A = conv(R, B)
381        M   -   convolved signal length
382        B   -   array[0..N-1] - response
383        N   -   response length, N<=M
384
385    OUTPUT PARAMETERS
386        R   -   deconvolved signal. array[0..M-N].
387
388    NOTE:
389        deconvolution is unstable process and may result in division  by  zero
390    (if your response function is degenerate, i.e. has zero Fourier coefficient).
391
392    NOTE:
393        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
394    functions have non-zero values at negative T's, you  can  still  use  this
395    subroutine - just shift its result correspondingly.
396
397      -- ALGLIB --
398         Copyright 21.07.2009 by Bochkanov Sergey
399    *************************************************************************/
400    public static void convr1dinv(double[] a, int m, double[] b, int n, out double[] r)
401    {
402        r = new double[0];
403        conv.convr1dinv(a, m, b, n, ref r);
404        return;
405    }
406
407    /*************************************************************************
408    1-dimensional circular real convolution.
409
410    Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.
411
412    INPUT PARAMETERS
413        S   -   array[0..M-1] - real signal
414        M   -   problem size
415        B   -   array[0..N-1] - real response
416        N   -   problem size
417
418    OUTPUT PARAMETERS
419        R   -   convolution: A*B. array[0..M-1].
420
421    NOTE:
422        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
423    negative T's, you can still use this subroutine - just  shift  its  result
424    correspondingly.
425
426      -- ALGLIB --
427         Copyright 21.07.2009 by Bochkanov Sergey
428    *************************************************************************/
429    public static void convr1dcircular(double[] s, int m, double[] r, int n, out double[] c)
430    {
431        c = new double[0];
432        conv.convr1dcircular(s, m, r, n, ref c);
433        return;
434    }
435
436    /*************************************************************************
437    1-dimensional complex deconvolution (inverse of ConvC1D()).
438
439    Algorithm has M*log(M)) complexity for any M (composite or prime).
440
441    INPUT PARAMETERS
442        A   -   array[0..M-1] - convolved signal, A = conv(R, B)
443        M   -   convolved signal length
444        B   -   array[0..N-1] - response
445        N   -   response length
446
447    OUTPUT PARAMETERS
448        R   -   deconvolved signal. array[0..M-N].
449
450    NOTE:
451        deconvolution is unstable process and may result in division  by  zero
452    (if your response function is degenerate, i.e. has zero Fourier coefficient).
453
454    NOTE:
455        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
456    negative T's, you can still use this subroutine - just  shift  its  result
457    correspondingly.
458
459      -- ALGLIB --
460         Copyright 21.07.2009 by Bochkanov Sergey
461    *************************************************************************/
462    public static void convr1dcircularinv(double[] a, int m, double[] b, int n, out double[] r)
463    {
464        r = new double[0];
465        conv.convr1dcircularinv(a, m, b, n, ref r);
466        return;
467    }
468
469}
470public partial class alglib
471{
472
473
474    /*************************************************************************
475    1-dimensional complex cross-correlation.
476
477    For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
478
479    Correlation is calculated using reduction to  convolution.  Algorithm with
480    max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
481    about performance).
482
483    IMPORTANT:
484        for  historical reasons subroutine accepts its parameters in  reversed
485        order: CorrC1D(Signal, Pattern) = Pattern x Signal (using  traditional
486        definition of cross-correlation, denoting cross-correlation as "x").
487
488    INPUT PARAMETERS
489        Signal  -   array[0..N-1] - complex function to be transformed,
490                    signal containing pattern
491        N       -   problem size
492        Pattern -   array[0..M-1] - complex function to be transformed,
493                    pattern to search withing signal
494        M       -   problem size
495
496    OUTPUT PARAMETERS
497        R       -   cross-correlation, array[0..N+M-2]:
498                    * positive lags are stored in R[0..N-1],
499                      R[i] = sum(conj(pattern[j])*signal[i+j]
500                    * negative lags are stored in R[N..N+M-2],
501                      R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]
502
503    NOTE:
504        It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
505    on [-K..M-1],  you can still use this subroutine, just shift result by K.
506
507      -- ALGLIB --
508         Copyright 21.07.2009 by Bochkanov Sergey
509    *************************************************************************/
510    public static void corrc1d(complex[] signal, int n, complex[] pattern, int m, out complex[] r)
511    {
512        r = new complex[0];
513        corr.corrc1d(signal, n, pattern, m, ref r);
514        return;
515    }
516
517    /*************************************************************************
518    1-dimensional circular complex cross-correlation.
519
520    For given Pattern/Signal returns corr(Pattern,Signal) (circular).
521    Algorithm has linearithmic complexity for any M/N.
522
523    IMPORTANT:
524        for  historical reasons subroutine accepts its parameters in  reversed
525        order:   CorrC1DCircular(Signal, Pattern) = Pattern x Signal    (using
526        traditional definition of cross-correlation, denoting cross-correlation
527        as "x").
528
529    INPUT PARAMETERS
530        Signal  -   array[0..N-1] - complex function to be transformed,
531                    periodic signal containing pattern
532        N       -   problem size
533        Pattern -   array[0..M-1] - complex function to be transformed,
534                    non-periodic pattern to search withing signal
535        M       -   problem size
536
537    OUTPUT PARAMETERS
538        R   -   convolution: A*B. array[0..M-1].
539
540
541      -- ALGLIB --
542         Copyright 21.07.2009 by Bochkanov Sergey
543    *************************************************************************/
544    public static void corrc1dcircular(complex[] signal, int m, complex[] pattern, int n, out complex[] c)
545    {
546        c = new complex[0];
547        corr.corrc1dcircular(signal, m, pattern, n, ref c);
548        return;
549    }
550
551    /*************************************************************************
552    1-dimensional real cross-correlation.
553
554    For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
555
556    Correlation is calculated using reduction to  convolution.  Algorithm with
557    max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
558    about performance).
559
560    IMPORTANT:
561        for  historical reasons subroutine accepts its parameters in  reversed
562        order: CorrR1D(Signal, Pattern) = Pattern x Signal (using  traditional
563        definition of cross-correlation, denoting cross-correlation as "x").
564
565    INPUT PARAMETERS
566        Signal  -   array[0..N-1] - real function to be transformed,
567                    signal containing pattern
568        N       -   problem size
569        Pattern -   array[0..M-1] - real function to be transformed,
570                    pattern to search withing signal
571        M       -   problem size
572
573    OUTPUT PARAMETERS
574        R       -   cross-correlation, array[0..N+M-2]:
575                    * positive lags are stored in R[0..N-1],
576                      R[i] = sum(pattern[j]*signal[i+j]
577                    * negative lags are stored in R[N..N+M-2],
578                      R[N+M-1-i] = sum(pattern[j]*signal[-i+j]
579
580    NOTE:
581        It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
582    on [-K..M-1],  you can still use this subroutine, just shift result by K.
583
584      -- ALGLIB --
585         Copyright 21.07.2009 by Bochkanov Sergey
586    *************************************************************************/
587    public static void corrr1d(double[] signal, int n, double[] pattern, int m, out double[] r)
588    {
589        r = new double[0];
590        corr.corrr1d(signal, n, pattern, m, ref r);
591        return;
592    }
593
594    /*************************************************************************
595    1-dimensional circular real cross-correlation.
596
597    For given Pattern/Signal returns corr(Pattern,Signal) (circular).
598    Algorithm has linearithmic complexity for any M/N.
599
600    IMPORTANT:
601        for  historical reasons subroutine accepts its parameters in  reversed
602        order:   CorrR1DCircular(Signal, Pattern) = Pattern x Signal    (using
603        traditional definition of cross-correlation, denoting cross-correlation
604        as "x").
605
606    INPUT PARAMETERS
607        Signal  -   array[0..N-1] - real function to be transformed,
608                    periodic signal containing pattern
609        N       -   problem size
610        Pattern -   array[0..M-1] - real function to be transformed,
611                    non-periodic pattern to search withing signal
612        M       -   problem size
613
614    OUTPUT PARAMETERS
615        R   -   convolution: A*B. array[0..M-1].
616
617
618      -- ALGLIB --
619         Copyright 21.07.2009 by Bochkanov Sergey
620    *************************************************************************/
621    public static void corrr1dcircular(double[] signal, int m, double[] pattern, int n, out double[] c)
622    {
623        c = new double[0];
624        corr.corrr1dcircular(signal, m, pattern, n, ref c);
625        return;
626    }
627
628}
629public partial class alglib
630{
631
632
633    /*************************************************************************
634    1-dimensional Fast Hartley Transform.
635
636    Algorithm has O(N*logN) complexity for any N (composite or prime).
637
638    INPUT PARAMETERS
639        A   -   array[0..N-1] - real function to be transformed
640        N   -   problem size
641
642    OUTPUT PARAMETERS
643        A   -   FHT of a input array, array[0..N-1],
644                A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)
645
646
647      -- ALGLIB --
648         Copyright 04.06.2009 by Bochkanov Sergey
649    *************************************************************************/
650    public static void fhtr1d(ref double[] a, int n)
651    {
652
653        fht.fhtr1d(ref a, n);
654        return;
655    }
656
657    /*************************************************************************
658    1-dimensional inverse FHT.
659
660    Algorithm has O(N*logN) complexity for any N (composite or prime).
661
662    INPUT PARAMETERS
663        A   -   array[0..N-1] - complex array to be transformed
664        N   -   problem size
665
666    OUTPUT PARAMETERS
667        A   -   inverse FHT of a input array, array[0..N-1]
668
669
670      -- ALGLIB --
671         Copyright 29.05.2009 by Bochkanov Sergey
672    *************************************************************************/
673    public static void fhtr1dinv(ref double[] a, int n)
674    {
675
676        fht.fhtr1dinv(ref a, n);
677        return;
678    }
679
680}
681public partial class alglib
682{
683    public class fft
684    {
685        /*************************************************************************
686        1-dimensional complex FFT.
687
688        Array size N may be arbitrary number (composite or prime).  Composite  N's
689        are handled with cache-oblivious variation of  a  Cooley-Tukey  algorithm.
690        Small prime-factors are transformed using hard coded  codelets (similar to
691        FFTW codelets, but without low-level  optimization),  large  prime-factors
692        are handled with Bluestein's algorithm.
693
694        Fastests transforms are for smooth N's (prime factors are 2, 3,  5  only),
695        most fast for powers of 2. When N have prime factors  larger  than  these,
696        but orders of magnitude smaller than N, computations will be about 4 times
697        slower than for nearby highly composite N's. When N itself is prime, speed
698        will be 6 times lower.
699
700        Algorithm has O(N*logN) complexity for any N (composite or prime).
701
702        INPUT PARAMETERS
703            A   -   array[0..N-1] - complex function to be transformed
704            N   -   problem size
705           
706        OUTPUT PARAMETERS
707            A   -   DFT of a input array, array[0..N-1]
708                    A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
709
710
711          -- ALGLIB --
712             Copyright 29.05.2009 by Bochkanov Sergey
713        *************************************************************************/
714        public static void fftc1d(ref complex[] a,
715            int n)
716        {
717            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
718            int i = 0;
719            double[] buf = new double[0];
720
721            alglib.ap.assert(n>0, "FFTC1D: incorrect N!");
722            alglib.ap.assert(alglib.ap.len(a)>=n, "FFTC1D: Length(A)<N!");
723            alglib.ap.assert(apserv.isfinitecvector(a, n), "FFTC1D: A contains infinite or NAN values!");
724           
725            //
726            // Special case: N=1, FFT is just identity transform.
727            // After this block we assume that N is strictly greater than 1.
728            //
729            if( n==1 )
730            {
731                return;
732            }
733           
734            //
735            // convert input array to the more convinient format
736            //
737            buf = new double[2*n];
738            for(i=0; i<=n-1; i++)
739            {
740                buf[2*i+0] = a[i].x;
741                buf[2*i+1] = a[i].y;
742            }
743           
744            //
745            // Generate plan and execute it.
746            //
747            // Plan is a combination of a successive factorizations of N and
748            // precomputed data. It is much like a FFTW plan, but is not stored
749            // between subroutine calls and is much simpler.
750            //
751            ftbase.ftcomplexfftplan(n, 1, plan);
752            ftbase.ftapplyplan(plan, buf, 0, 1);
753           
754            //
755            // result
756            //
757            for(i=0; i<=n-1; i++)
758            {
759                a[i].x = buf[2*i+0];
760                a[i].y = buf[2*i+1];
761            }
762        }
763
764
765        /*************************************************************************
766        1-dimensional complex inverse FFT.
767
768        Array size N may be arbitrary number (composite or prime).  Algorithm  has
769        O(N*logN) complexity for any N (composite or prime).
770
771        See FFTC1D() description for more information about algorithm performance.
772
773        INPUT PARAMETERS
774            A   -   array[0..N-1] - complex array to be transformed
775            N   -   problem size
776
777        OUTPUT PARAMETERS
778            A   -   inverse DFT of a input array, array[0..N-1]
779                    A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
780
781
782          -- ALGLIB --
783             Copyright 29.05.2009 by Bochkanov Sergey
784        *************************************************************************/
785        public static void fftc1dinv(ref complex[] a,
786            int n)
787        {
788            int i = 0;
789
790            alglib.ap.assert(n>0, "FFTC1DInv: incorrect N!");
791            alglib.ap.assert(alglib.ap.len(a)>=n, "FFTC1DInv: Length(A)<N!");
792            alglib.ap.assert(apserv.isfinitecvector(a, n), "FFTC1DInv: A contains infinite or NAN values!");
793           
794            //
795            // Inverse DFT can be expressed in terms of the DFT as
796            //
797            //     invfft(x) = fft(x')'/N
798            //
799            // here x' means conj(x).
800            //
801            for(i=0; i<=n-1; i++)
802            {
803                a[i].y = -a[i].y;
804            }
805            fftc1d(ref a, n);
806            for(i=0; i<=n-1; i++)
807            {
808                a[i].x = a[i].x/n;
809                a[i].y = -(a[i].y/n);
810            }
811        }
812
813
814        /*************************************************************************
815        1-dimensional real FFT.
816
817        Algorithm has O(N*logN) complexity for any N (composite or prime).
818
819        INPUT PARAMETERS
820            A   -   array[0..N-1] - real function to be transformed
821            N   -   problem size
822
823        OUTPUT PARAMETERS
824            F   -   DFT of a input array, array[0..N-1]
825                    F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
826
827        NOTE:
828            F[] satisfies symmetry property F[k] = conj(F[N-k]),  so just one half
829        of  array  is  usually needed. But for convinience subroutine returns full
830        complex array (with frequencies above N/2), so its result may be  used  by
831        other FFT-related subroutines.
832
833
834          -- ALGLIB --
835             Copyright 01.06.2009 by Bochkanov Sergey
836        *************************************************************************/
837        public static void fftr1d(double[] a,
838            int n,
839            ref complex[] f)
840        {
841            int i = 0;
842            int n2 = 0;
843            int idx = 0;
844            complex hn = 0;
845            complex hmnc = 0;
846            complex v = 0;
847            double[] buf = new double[0];
848            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
849            int i_ = 0;
850
851            f = new complex[0];
852
853            alglib.ap.assert(n>0, "FFTR1D: incorrect N!");
854            alglib.ap.assert(alglib.ap.len(a)>=n, "FFTR1D: Length(A)<N!");
855            alglib.ap.assert(apserv.isfinitevector(a, n), "FFTR1D: A contains infinite or NAN values!");
856           
857            //
858            // Special cases:
859            // * N=1, FFT is just identity transform.
860            // * N=2, FFT is simple too
861            //
862            // After this block we assume that N is strictly greater than 2
863            //
864            if( n==1 )
865            {
866                f = new complex[1];
867                f[0] = a[0];
868                return;
869            }
870            if( n==2 )
871            {
872                f = new complex[2];
873                f[0].x = a[0]+a[1];
874                f[0].y = 0;
875                f[1].x = a[0]-a[1];
876                f[1].y = 0;
877                return;
878            }
879           
880            //
881            // Choose between odd-size and even-size FFTs
882            //
883            if( n%2==0 )
884            {
885               
886                //
887                // even-size real FFT, use reduction to the complex task
888                //
889                n2 = n/2;
890                buf = new double[n];
891                for(i_=0; i_<=n-1;i_++)
892                {
893                    buf[i_] = a[i_];
894                }
895                ftbase.ftcomplexfftplan(n2, 1, plan);
896                ftbase.ftapplyplan(plan, buf, 0, 1);
897                f = new complex[n];
898                for(i=0; i<=n2; i++)
899                {
900                    idx = 2*(i%n2);
901                    hn.x = buf[idx+0];
902                    hn.y = buf[idx+1];
903                    idx = 2*((n2-i)%n2);
904                    hmnc.x = buf[idx+0];
905                    hmnc.y = -buf[idx+1];
906                    v.x = -Math.Sin(-(2*Math.PI*i/n));
907                    v.y = Math.Cos(-(2*Math.PI*i/n));
908                    f[i] = hn+hmnc-v*(hn-hmnc);
909                    f[i].x = 0.5*f[i].x;
910                    f[i].y = 0.5*f[i].y;
911                }
912                for(i=n2+1; i<=n-1; i++)
913                {
914                    f[i] = math.conj(f[n-i]);
915                }
916            }
917            else
918            {
919               
920                //
921                // use complex FFT
922                //
923                f = new complex[n];
924                for(i=0; i<=n-1; i++)
925                {
926                    f[i] = a[i];
927                }
928                fftc1d(ref f, n);
929            }
930        }
931
932
933        /*************************************************************************
934        1-dimensional real inverse FFT.
935
936        Algorithm has O(N*logN) complexity for any N (composite or prime).
937
938        INPUT PARAMETERS
939            F   -   array[0..floor(N/2)] - frequencies from forward real FFT
940            N   -   problem size
941
942        OUTPUT PARAMETERS
943            A   -   inverse DFT of a input array, array[0..N-1]
944
945        NOTE:
946            F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just  one
947        half of frequencies array is needed - elements from 0 to floor(N/2).  F[0]
948        is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd,  then
949        F[floor(N/2)] has no special properties.
950
951        Relying on properties noted above, FFTR1DInv subroutine uses only elements
952        from 0th to floor(N/2)-th. It ignores imaginary part of F[0],  and in case
953        N is even it ignores imaginary part of F[floor(N/2)] too.
954
955        When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
956        - you can pass either either frequencies array with N elements or  reduced
957        array with roughly N/2 elements - subroutine will  successfully  transform
958        both.
959
960        If you call this function using reduced arguments list -  "FFTR1DInv(F,A)"
961        - you must pass FULL array with N elements (although higher  N/2 are still
962        not used) because array size is used to automatically determine FFT length
963
964
965          -- ALGLIB --
966             Copyright 01.06.2009 by Bochkanov Sergey
967        *************************************************************************/
968        public static void fftr1dinv(complex[] f,
969            int n,
970            ref double[] a)
971        {
972            int i = 0;
973            double[] h = new double[0];
974            complex[] fh = new complex[0];
975
976            a = new double[0];
977
978            alglib.ap.assert(n>0, "FFTR1DInv: incorrect N!");
979            alglib.ap.assert(alglib.ap.len(f)>=(int)Math.Floor((double)n/(double)2)+1, "FFTR1DInv: Length(F)<Floor(N/2)+1!");
980            alglib.ap.assert(math.isfinite(f[0].x), "FFTR1DInv: F contains infinite or NAN values!");
981            for(i=1; i<=(int)Math.Floor((double)n/(double)2)-1; i++)
982            {
983                alglib.ap.assert(math.isfinite(f[i].x) && math.isfinite(f[i].y), "FFTR1DInv: F contains infinite or NAN values!");
984            }
985            alglib.ap.assert(math.isfinite(f[(int)Math.Floor((double)n/(double)2)].x), "FFTR1DInv: F contains infinite or NAN values!");
986            if( n%2!=0 )
987            {
988                alglib.ap.assert(math.isfinite(f[(int)Math.Floor((double)n/(double)2)].y), "FFTR1DInv: F contains infinite or NAN values!");
989            }
990           
991            //
992            // Special case: N=1, FFT is just identity transform.
993            // After this block we assume that N is strictly greater than 1.
994            //
995            if( n==1 )
996            {
997                a = new double[1];
998                a[0] = f[0].x;
999                return;
1000            }
1001           
1002            //
1003            // inverse real FFT is reduced to the inverse real FHT,
1004            // which is reduced to the forward real FHT,
1005            // which is reduced to the forward real FFT.
1006            //
1007            // Don't worry, it is really compact and efficient reduction :)
1008            //
1009            h = new double[n];
1010            a = new double[n];
1011            h[0] = f[0].x;
1012            for(i=1; i<=(int)Math.Floor((double)n/(double)2)-1; i++)
1013            {
1014                h[i] = f[i].x-f[i].y;
1015                h[n-i] = f[i].x+f[i].y;
1016            }
1017            if( n%2==0 )
1018            {
1019                h[(int)Math.Floor((double)n/(double)2)] = f[(int)Math.Floor((double)n/(double)2)].x;
1020            }
1021            else
1022            {
1023                h[(int)Math.Floor((double)n/(double)2)] = f[(int)Math.Floor((double)n/(double)2)].x-f[(int)Math.Floor((double)n/(double)2)].y;
1024                h[(int)Math.Floor((double)n/(double)2)+1] = f[(int)Math.Floor((double)n/(double)2)].x+f[(int)Math.Floor((double)n/(double)2)].y;
1025            }
1026            fftr1d(h, n, ref fh);
1027            for(i=0; i<=n-1; i++)
1028            {
1029                a[i] = (fh[i].x-fh[i].y)/n;
1030            }
1031        }
1032
1033
1034        /*************************************************************************
1035        Internal subroutine. Never call it directly!
1036
1037
1038          -- ALGLIB --
1039             Copyright 01.06.2009 by Bochkanov Sergey
1040        *************************************************************************/
1041        public static void fftr1dinternaleven(ref double[] a,
1042            int n,
1043            ref double[] buf,
1044            ftbase.fasttransformplan plan)
1045        {
1046            double x = 0;
1047            double y = 0;
1048            int i = 0;
1049            int n2 = 0;
1050            int idx = 0;
1051            complex hn = 0;
1052            complex hmnc = 0;
1053            complex v = 0;
1054            int i_ = 0;
1055
1056            alglib.ap.assert(n>0 && n%2==0, "FFTR1DEvenInplace: incorrect N!");
1057           
1058            //
1059            // Special cases:
1060            // * N=2
1061            //
1062            // After this block we assume that N is strictly greater than 2
1063            //
1064            if( n==2 )
1065            {
1066                x = a[0]+a[1];
1067                y = a[0]-a[1];
1068                a[0] = x;
1069                a[1] = y;
1070                return;
1071            }
1072           
1073            //
1074            // even-size real FFT, use reduction to the complex task
1075            //
1076            n2 = n/2;
1077            for(i_=0; i_<=n-1;i_++)
1078            {
1079                buf[i_] = a[i_];
1080            }
1081            ftbase.ftapplyplan(plan, buf, 0, 1);
1082            a[0] = buf[0]+buf[1];
1083            for(i=1; i<=n2-1; i++)
1084            {
1085                idx = 2*(i%n2);
1086                hn.x = buf[idx+0];
1087                hn.y = buf[idx+1];
1088                idx = 2*(n2-i);
1089                hmnc.x = buf[idx+0];
1090                hmnc.y = -buf[idx+1];
1091                v.x = -Math.Sin(-(2*Math.PI*i/n));
1092                v.y = Math.Cos(-(2*Math.PI*i/n));
1093                v = hn+hmnc-v*(hn-hmnc);
1094                a[2*i+0] = 0.5*v.x;
1095                a[2*i+1] = 0.5*v.y;
1096            }
1097            a[1] = buf[0]-buf[1];
1098        }
1099
1100
1101        /*************************************************************************
1102        Internal subroutine. Never call it directly!
1103
1104
1105          -- ALGLIB --
1106             Copyright 01.06.2009 by Bochkanov Sergey
1107        *************************************************************************/
1108        public static void fftr1dinvinternaleven(ref double[] a,
1109            int n,
1110            ref double[] buf,
1111            ftbase.fasttransformplan plan)
1112        {
1113            double x = 0;
1114            double y = 0;
1115            double t = 0;
1116            int i = 0;
1117            int n2 = 0;
1118
1119            alglib.ap.assert(n>0 && n%2==0, "FFTR1DInvInternalEven: incorrect N!");
1120           
1121            //
1122            // Special cases:
1123            // * N=2
1124            //
1125            // After this block we assume that N is strictly greater than 2
1126            //
1127            if( n==2 )
1128            {
1129                x = 0.5*(a[0]+a[1]);
1130                y = 0.5*(a[0]-a[1]);
1131                a[0] = x;
1132                a[1] = y;
1133                return;
1134            }
1135           
1136            //
1137            // inverse real FFT is reduced to the inverse real FHT,
1138            // which is reduced to the forward real FHT,
1139            // which is reduced to the forward real FFT.
1140            //
1141            // Don't worry, it is really compact and efficient reduction :)
1142            //
1143            n2 = n/2;
1144            buf[0] = a[0];
1145            for(i=1; i<=n2-1; i++)
1146            {
1147                x = a[2*i+0];
1148                y = a[2*i+1];
1149                buf[i] = x-y;
1150                buf[n-i] = x+y;
1151            }
1152            buf[n2] = a[1];
1153            fftr1dinternaleven(ref buf, n, ref a, plan);
1154            a[0] = buf[0]/n;
1155            t = (double)1/(double)n;
1156            for(i=1; i<=n2-1; i++)
1157            {
1158                x = buf[2*i+0];
1159                y = buf[2*i+1];
1160                a[i] = t*(x-y);
1161                a[n-i] = t*(x+y);
1162            }
1163            a[n2] = buf[1]/n;
1164        }
1165
1166
1167    }
1168    public class conv
1169    {
1170        /*************************************************************************
1171        1-dimensional complex convolution.
1172
1173        For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
1174        choose between three implementations: straightforward O(M*N)  formula  for
1175        very small N (or M), overlap-add algorithm for  cases  where  max(M,N)  is
1176        significantly larger than min(M,N), but O(M*N) algorithm is too slow,  and
1177        general FFT-based formula for cases where two previois algorithms are  too
1178        slow.
1179
1180        Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.
1181
1182        INPUT PARAMETERS
1183            A   -   array[0..M-1] - complex function to be transformed
1184            M   -   problem size
1185            B   -   array[0..N-1] - complex function to be transformed
1186            N   -   problem size
1187
1188        OUTPUT PARAMETERS
1189            R   -   convolution: A*B. array[0..N+M-2].
1190
1191        NOTE:
1192            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
1193        functions have non-zero values at negative T's, you  can  still  use  this
1194        subroutine - just shift its result correspondingly.
1195
1196          -- ALGLIB --
1197             Copyright 21.07.2009 by Bochkanov Sergey
1198        *************************************************************************/
1199        public static void convc1d(complex[] a,
1200            int m,
1201            complex[] b,
1202            int n,
1203            ref complex[] r)
1204        {
1205            r = new complex[0];
1206
1207            alglib.ap.assert(n>0 && m>0, "ConvC1D: incorrect N or M!");
1208           
1209            //
1210            // normalize task: make M>=N,
1211            // so A will be longer that B.
1212            //
1213            if( m<n )
1214            {
1215                convc1d(b, n, a, m, ref r);
1216                return;
1217            }
1218            convc1dx(a, m, b, n, false, -1, 0, ref r);
1219        }
1220
1221
1222        /*************************************************************************
1223        1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
1224
1225        Algorithm has M*log(M)) complexity for any M (composite or prime).
1226
1227        INPUT PARAMETERS
1228            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
1229            M   -   convolved signal length
1230            B   -   array[0..N-1] - response
1231            N   -   response length, N<=M
1232
1233        OUTPUT PARAMETERS
1234            R   -   deconvolved signal. array[0..M-N].
1235
1236        NOTE:
1237            deconvolution is unstable process and may result in division  by  zero
1238        (if your response function is degenerate, i.e. has zero Fourier coefficient).
1239
1240        NOTE:
1241            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
1242        functions have non-zero values at negative T's, you  can  still  use  this
1243        subroutine - just shift its result correspondingly.
1244
1245          -- ALGLIB --
1246             Copyright 21.07.2009 by Bochkanov Sergey
1247        *************************************************************************/
1248        public static void convc1dinv(complex[] a,
1249            int m,
1250            complex[] b,
1251            int n,
1252            ref complex[] r)
1253        {
1254            int i = 0;
1255            int p = 0;
1256            double[] buf = new double[0];
1257            double[] buf2 = new double[0];
1258            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
1259            complex c1 = 0;
1260            complex c2 = 0;
1261            complex c3 = 0;
1262            double t = 0;
1263
1264            r = new complex[0];
1265
1266            alglib.ap.assert((n>0 && m>0) && n<=m, "ConvC1DInv: incorrect N or M!");
1267            p = ftbase.ftbasefindsmooth(m);
1268            ftbase.ftcomplexfftplan(p, 1, plan);
1269            buf = new double[2*p];
1270            for(i=0; i<=m-1; i++)
1271            {
1272                buf[2*i+0] = a[i].x;
1273                buf[2*i+1] = a[i].y;
1274            }
1275            for(i=m; i<=p-1; i++)
1276            {
1277                buf[2*i+0] = 0;
1278                buf[2*i+1] = 0;
1279            }
1280            buf2 = new double[2*p];
1281            for(i=0; i<=n-1; i++)
1282            {
1283                buf2[2*i+0] = b[i].x;
1284                buf2[2*i+1] = b[i].y;
1285            }
1286            for(i=n; i<=p-1; i++)
1287            {
1288                buf2[2*i+0] = 0;
1289                buf2[2*i+1] = 0;
1290            }
1291            ftbase.ftapplyplan(plan, buf, 0, 1);
1292            ftbase.ftapplyplan(plan, buf2, 0, 1);
1293            for(i=0; i<=p-1; i++)
1294            {
1295                c1.x = buf[2*i+0];
1296                c1.y = buf[2*i+1];
1297                c2.x = buf2[2*i+0];
1298                c2.y = buf2[2*i+1];
1299                c3 = c1/c2;
1300                buf[2*i+0] = c3.x;
1301                buf[2*i+1] = -c3.y;
1302            }
1303            ftbase.ftapplyplan(plan, buf, 0, 1);
1304            t = (double)1/(double)p;
1305            r = new complex[m-n+1];
1306            for(i=0; i<=m-n; i++)
1307            {
1308                r[i].x = t*buf[2*i+0];
1309                r[i].y = -(t*buf[2*i+1]);
1310            }
1311        }
1312
1313
1314        /*************************************************************************
1315        1-dimensional circular complex convolution.
1316
1317        For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
1318        complexity for any M/N.
1319
1320        IMPORTANT:  normal convolution is commutative,  i.e.   it  is symmetric  -
1321        conv(A,B)=conv(B,A).  Cyclic convolution IS NOT.  One function - S - is  a
1322        signal,  periodic function, and another - R - is a response,  non-periodic
1323        function with limited length.
1324
1325        INPUT PARAMETERS
1326            S   -   array[0..M-1] - complex periodic signal
1327            M   -   problem size
1328            B   -   array[0..N-1] - complex non-periodic response
1329            N   -   problem size
1330
1331        OUTPUT PARAMETERS
1332            R   -   convolution: A*B. array[0..M-1].
1333
1334        NOTE:
1335            It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
1336        negative T's, you can still use this subroutine - just  shift  its  result
1337        correspondingly.
1338
1339          -- ALGLIB --
1340             Copyright 21.07.2009 by Bochkanov Sergey
1341        *************************************************************************/
1342        public static void convc1dcircular(complex[] s,
1343            int m,
1344            complex[] r,
1345            int n,
1346            ref complex[] c)
1347        {
1348            complex[] buf = new complex[0];
1349            int i1 = 0;
1350            int i2 = 0;
1351            int j2 = 0;
1352            int i_ = 0;
1353            int i1_ = 0;
1354
1355            c = new complex[0];
1356
1357            alglib.ap.assert(n>0 && m>0, "ConvC1DCircular: incorrect N or M!");
1358           
1359            //
1360            // normalize task: make M>=N,
1361            // so A will be longer (at least - not shorter) that B.
1362            //
1363            if( m<n )
1364            {
1365                buf = new complex[m];
1366                for(i1=0; i1<=m-1; i1++)
1367                {
1368                    buf[i1] = 0;
1369                }
1370                i1 = 0;
1371                while( i1<n )
1372                {
1373                    i2 = Math.Min(i1+m-1, n-1);
1374                    j2 = i2-i1;
1375                    i1_ = (i1) - (0);
1376                    for(i_=0; i_<=j2;i_++)
1377                    {
1378                        buf[i_] = buf[i_] + r[i_+i1_];
1379                    }
1380                    i1 = i1+m;
1381                }
1382                convc1dcircular(s, m, buf, m, ref c);
1383                return;
1384            }
1385            convc1dx(s, m, r, n, true, -1, 0, ref c);
1386        }
1387
1388
1389        /*************************************************************************
1390        1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
1391
1392        Algorithm has M*log(M)) complexity for any M (composite or prime).
1393
1394        INPUT PARAMETERS
1395            A   -   array[0..M-1] - convolved periodic signal, A = conv(R, B)
1396            M   -   convolved signal length
1397            B   -   array[0..N-1] - non-periodic response
1398            N   -   response length
1399
1400        OUTPUT PARAMETERS
1401            R   -   deconvolved signal. array[0..M-1].
1402
1403        NOTE:
1404            deconvolution is unstable process and may result in division  by  zero
1405        (if your response function is degenerate, i.e. has zero Fourier coefficient).
1406
1407        NOTE:
1408            It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
1409        negative T's, you can still use this subroutine - just  shift  its  result
1410        correspondingly.
1411
1412          -- ALGLIB --
1413             Copyright 21.07.2009 by Bochkanov Sergey
1414        *************************************************************************/
1415        public static void convc1dcircularinv(complex[] a,
1416            int m,
1417            complex[] b,
1418            int n,
1419            ref complex[] r)
1420        {
1421            int i = 0;
1422            int i1 = 0;
1423            int i2 = 0;
1424            int j2 = 0;
1425            double[] buf = new double[0];
1426            double[] buf2 = new double[0];
1427            complex[] cbuf = new complex[0];
1428            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
1429            complex c1 = 0;
1430            complex c2 = 0;
1431            complex c3 = 0;
1432            double t = 0;
1433            int i_ = 0;
1434            int i1_ = 0;
1435
1436            r = new complex[0];
1437
1438            alglib.ap.assert(n>0 && m>0, "ConvC1DCircularInv: incorrect N or M!");
1439           
1440            //
1441            // normalize task: make M>=N,
1442            // so A will be longer (at least - not shorter) that B.
1443            //
1444            if( m<n )
1445            {
1446                cbuf = new complex[m];
1447                for(i=0; i<=m-1; i++)
1448                {
1449                    cbuf[i] = 0;
1450                }
1451                i1 = 0;
1452                while( i1<n )
1453                {
1454                    i2 = Math.Min(i1+m-1, n-1);
1455                    j2 = i2-i1;
1456                    i1_ = (i1) - (0);
1457                    for(i_=0; i_<=j2;i_++)
1458                    {
1459                        cbuf[i_] = cbuf[i_] + b[i_+i1_];
1460                    }
1461                    i1 = i1+m;
1462                }
1463                convc1dcircularinv(a, m, cbuf, m, ref r);
1464                return;
1465            }
1466           
1467            //
1468            // Task is normalized
1469            //
1470            ftbase.ftcomplexfftplan(m, 1, plan);
1471            buf = new double[2*m];
1472            for(i=0; i<=m-1; i++)
1473            {
1474                buf[2*i+0] = a[i].x;
1475                buf[2*i+1] = a[i].y;
1476            }
1477            buf2 = new double[2*m];
1478            for(i=0; i<=n-1; i++)
1479            {
1480                buf2[2*i+0] = b[i].x;
1481                buf2[2*i+1] = b[i].y;
1482            }
1483            for(i=n; i<=m-1; i++)
1484            {
1485                buf2[2*i+0] = 0;
1486                buf2[2*i+1] = 0;
1487            }
1488            ftbase.ftapplyplan(plan, buf, 0, 1);
1489            ftbase.ftapplyplan(plan, buf2, 0, 1);
1490            for(i=0; i<=m-1; i++)
1491            {
1492                c1.x = buf[2*i+0];
1493                c1.y = buf[2*i+1];
1494                c2.x = buf2[2*i+0];
1495                c2.y = buf2[2*i+1];
1496                c3 = c1/c2;
1497                buf[2*i+0] = c3.x;
1498                buf[2*i+1] = -c3.y;
1499            }
1500            ftbase.ftapplyplan(plan, buf, 0, 1);
1501            t = (double)1/(double)m;
1502            r = new complex[m];
1503            for(i=0; i<=m-1; i++)
1504            {
1505                r[i].x = t*buf[2*i+0];
1506                r[i].y = -(t*buf[2*i+1]);
1507            }
1508        }
1509
1510
1511        /*************************************************************************
1512        1-dimensional real convolution.
1513
1514        Analogous to ConvC1D(), see ConvC1D() comments for more details.
1515
1516        INPUT PARAMETERS
1517            A   -   array[0..M-1] - real function to be transformed
1518            M   -   problem size
1519            B   -   array[0..N-1] - real function to be transformed
1520            N   -   problem size
1521
1522        OUTPUT PARAMETERS
1523            R   -   convolution: A*B. array[0..N+M-2].
1524
1525        NOTE:
1526            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
1527        functions have non-zero values at negative T's, you  can  still  use  this
1528        subroutine - just shift its result correspondingly.
1529
1530          -- ALGLIB --
1531             Copyright 21.07.2009 by Bochkanov Sergey
1532        *************************************************************************/
1533        public static void convr1d(double[] a,
1534            int m,
1535            double[] b,
1536            int n,
1537            ref double[] r)
1538        {
1539            r = new double[0];
1540
1541            alglib.ap.assert(n>0 && m>0, "ConvR1D: incorrect N or M!");
1542           
1543            //
1544            // normalize task: make M>=N,
1545            // so A will be longer that B.
1546            //
1547            if( m<n )
1548            {
1549                convr1d(b, n, a, m, ref r);
1550                return;
1551            }
1552            convr1dx(a, m, b, n, false, -1, 0, ref r);
1553        }
1554
1555
1556        /*************************************************************************
1557        1-dimensional real deconvolution (inverse of ConvC1D()).
1558
1559        Algorithm has M*log(M)) complexity for any M (composite or prime).
1560
1561        INPUT PARAMETERS
1562            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
1563            M   -   convolved signal length
1564            B   -   array[0..N-1] - response
1565            N   -   response length, N<=M
1566
1567        OUTPUT PARAMETERS
1568            R   -   deconvolved signal. array[0..M-N].
1569
1570        NOTE:
1571            deconvolution is unstable process and may result in division  by  zero
1572        (if your response function is degenerate, i.e. has zero Fourier coefficient).
1573
1574        NOTE:
1575            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
1576        functions have non-zero values at negative T's, you  can  still  use  this
1577        subroutine - just shift its result correspondingly.
1578
1579          -- ALGLIB --
1580             Copyright 21.07.2009 by Bochkanov Sergey
1581        *************************************************************************/
1582        public static void convr1dinv(double[] a,
1583            int m,
1584            double[] b,
1585            int n,
1586            ref double[] r)
1587        {
1588            int i = 0;
1589            int p = 0;
1590            double[] buf = new double[0];
1591            double[] buf2 = new double[0];
1592            double[] buf3 = new double[0];
1593            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
1594            complex c1 = 0;
1595            complex c2 = 0;
1596            complex c3 = 0;
1597            int i_ = 0;
1598
1599            r = new double[0];
1600
1601            alglib.ap.assert((n>0 && m>0) && n<=m, "ConvR1DInv: incorrect N or M!");
1602            p = ftbase.ftbasefindsmootheven(m);
1603            buf = new double[p];
1604            for(i_=0; i_<=m-1;i_++)
1605            {
1606                buf[i_] = a[i_];
1607            }
1608            for(i=m; i<=p-1; i++)
1609            {
1610                buf[i] = 0;
1611            }
1612            buf2 = new double[p];
1613            for(i_=0; i_<=n-1;i_++)
1614            {
1615                buf2[i_] = b[i_];
1616            }
1617            for(i=n; i<=p-1; i++)
1618            {
1619                buf2[i] = 0;
1620            }
1621            buf3 = new double[p];
1622            ftbase.ftcomplexfftplan(p/2, 1, plan);
1623            fft.fftr1dinternaleven(ref buf, p, ref buf3, plan);
1624            fft.fftr1dinternaleven(ref buf2, p, ref buf3, plan);
1625            buf[0] = buf[0]/buf2[0];
1626            buf[1] = buf[1]/buf2[1];
1627            for(i=1; i<=p/2-1; i++)
1628            {
1629                c1.x = buf[2*i+0];
1630                c1.y = buf[2*i+1];
1631                c2.x = buf2[2*i+0];
1632                c2.y = buf2[2*i+1];
1633                c3 = c1/c2;
1634                buf[2*i+0] = c3.x;
1635                buf[2*i+1] = c3.y;
1636            }
1637            fft.fftr1dinvinternaleven(ref buf, p, ref buf3, plan);
1638            r = new double[m-n+1];
1639            for(i_=0; i_<=m-n;i_++)
1640            {
1641                r[i_] = buf[i_];
1642            }
1643        }
1644
1645
1646        /*************************************************************************
1647        1-dimensional circular real convolution.
1648
1649        Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.
1650
1651        INPUT PARAMETERS
1652            S   -   array[0..M-1] - real signal
1653            M   -   problem size
1654            B   -   array[0..N-1] - real response
1655            N   -   problem size
1656
1657        OUTPUT PARAMETERS
1658            R   -   convolution: A*B. array[0..M-1].
1659
1660        NOTE:
1661            It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
1662        negative T's, you can still use this subroutine - just  shift  its  result
1663        correspondingly.
1664
1665          -- ALGLIB --
1666             Copyright 21.07.2009 by Bochkanov Sergey
1667        *************************************************************************/
1668        public static void convr1dcircular(double[] s,
1669            int m,
1670            double[] r,
1671            int n,
1672            ref double[] c)
1673        {
1674            double[] buf = new double[0];
1675            int i1 = 0;
1676            int i2 = 0;
1677            int j2 = 0;
1678            int i_ = 0;
1679            int i1_ = 0;
1680
1681            c = new double[0];
1682
1683            alglib.ap.assert(n>0 && m>0, "ConvC1DCircular: incorrect N or M!");
1684           
1685            //
1686            // normalize task: make M>=N,
1687            // so A will be longer (at least - not shorter) that B.
1688            //
1689            if( m<n )
1690            {
1691                buf = new double[m];
1692                for(i1=0; i1<=m-1; i1++)
1693                {
1694                    buf[i1] = 0;
1695                }
1696                i1 = 0;
1697                while( i1<n )
1698                {
1699                    i2 = Math.Min(i1+m-1, n-1);
1700                    j2 = i2-i1;
1701                    i1_ = (i1) - (0);
1702                    for(i_=0; i_<=j2;i_++)
1703                    {
1704                        buf[i_] = buf[i_] + r[i_+i1_];
1705                    }
1706                    i1 = i1+m;
1707                }
1708                convr1dcircular(s, m, buf, m, ref c);
1709                return;
1710            }
1711           
1712            //
1713            // reduce to usual convolution
1714            //
1715            convr1dx(s, m, r, n, true, -1, 0, ref c);
1716        }
1717
1718
1719        /*************************************************************************
1720        1-dimensional complex deconvolution (inverse of ConvC1D()).
1721
1722        Algorithm has M*log(M)) complexity for any M (composite or prime).
1723
1724        INPUT PARAMETERS
1725            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
1726            M   -   convolved signal length
1727            B   -   array[0..N-1] - response
1728            N   -   response length
1729
1730        OUTPUT PARAMETERS
1731            R   -   deconvolved signal. array[0..M-N].
1732
1733        NOTE:
1734            deconvolution is unstable process and may result in division  by  zero
1735        (if your response function is degenerate, i.e. has zero Fourier coefficient).
1736
1737        NOTE:
1738            It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
1739        negative T's, you can still use this subroutine - just  shift  its  result
1740        correspondingly.
1741
1742          -- ALGLIB --
1743             Copyright 21.07.2009 by Bochkanov Sergey
1744        *************************************************************************/
1745        public static void convr1dcircularinv(double[] a,
1746            int m,
1747            double[] b,
1748            int n,
1749            ref double[] r)
1750        {
1751            int i = 0;
1752            int i1 = 0;
1753            int i2 = 0;
1754            int j2 = 0;
1755            double[] buf = new double[0];
1756            double[] buf2 = new double[0];
1757            double[] buf3 = new double[0];
1758            complex[] cbuf = new complex[0];
1759            complex[] cbuf2 = new complex[0];
1760            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
1761            complex c1 = 0;
1762            complex c2 = 0;
1763            complex c3 = 0;
1764            int i_ = 0;
1765            int i1_ = 0;
1766
1767            r = new double[0];
1768
1769            alglib.ap.assert(n>0 && m>0, "ConvR1DCircularInv: incorrect N or M!");
1770           
1771            //
1772            // normalize task: make M>=N,
1773            // so A will be longer (at least - not shorter) that B.
1774            //
1775            if( m<n )
1776            {
1777                buf = new double[m];
1778                for(i=0; i<=m-1; i++)
1779                {
1780                    buf[i] = 0;
1781                }
1782                i1 = 0;
1783                while( i1<n )
1784                {
1785                    i2 = Math.Min(i1+m-1, n-1);
1786                    j2 = i2-i1;
1787                    i1_ = (i1) - (0);
1788                    for(i_=0; i_<=j2;i_++)
1789                    {
1790                        buf[i_] = buf[i_] + b[i_+i1_];
1791                    }
1792                    i1 = i1+m;
1793                }
1794                convr1dcircularinv(a, m, buf, m, ref r);
1795                return;
1796            }
1797           
1798            //
1799            // Task is normalized
1800            //
1801            if( m%2==0 )
1802            {
1803               
1804                //
1805                // size is even, use fast even-size FFT
1806                //
1807                buf = new double[m];
1808                for(i_=0; i_<=m-1;i_++)
1809                {
1810                    buf[i_] = a[i_];
1811                }
1812                buf2 = new double[m];
1813                for(i_=0; i_<=n-1;i_++)
1814                {
1815                    buf2[i_] = b[i_];
1816                }
1817                for(i=n; i<=m-1; i++)
1818                {
1819                    buf2[i] = 0;
1820                }
1821                buf3 = new double[m];
1822                ftbase.ftcomplexfftplan(m/2, 1, plan);
1823                fft.fftr1dinternaleven(ref buf, m, ref buf3, plan);
1824                fft.fftr1dinternaleven(ref buf2, m, ref buf3, plan);
1825                buf[0] = buf[0]/buf2[0];
1826                buf[1] = buf[1]/buf2[1];
1827                for(i=1; i<=m/2-1; i++)
1828                {
1829                    c1.x = buf[2*i+0];
1830                    c1.y = buf[2*i+1];
1831                    c2.x = buf2[2*i+0];
1832                    c2.y = buf2[2*i+1];
1833                    c3 = c1/c2;
1834                    buf[2*i+0] = c3.x;
1835                    buf[2*i+1] = c3.y;
1836                }
1837                fft.fftr1dinvinternaleven(ref buf, m, ref buf3, plan);
1838                r = new double[m];
1839                for(i_=0; i_<=m-1;i_++)
1840                {
1841                    r[i_] = buf[i_];
1842                }
1843            }
1844            else
1845            {
1846               
1847                //
1848                // odd-size, use general real FFT
1849                //
1850                fft.fftr1d(a, m, ref cbuf);
1851                buf2 = new double[m];
1852                for(i_=0; i_<=n-1;i_++)
1853                {
1854                    buf2[i_] = b[i_];
1855                }
1856                for(i=n; i<=m-1; i++)
1857                {
1858                    buf2[i] = 0;
1859                }
1860                fft.fftr1d(buf2, m, ref cbuf2);
1861                for(i=0; i<=(int)Math.Floor((double)m/(double)2); i++)
1862                {
1863                    cbuf[i] = cbuf[i]/cbuf2[i];
1864                }
1865                fft.fftr1dinv(cbuf, m, ref r);
1866            }
1867        }
1868
1869
1870        /*************************************************************************
1871        1-dimensional complex convolution.
1872
1873        Extended subroutine which allows to choose convolution algorithm.
1874        Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular().
1875
1876        INPUT PARAMETERS
1877            A   -   array[0..M-1] - complex function to be transformed
1878            M   -   problem size
1879            B   -   array[0..N-1] - complex function to be transformed
1880            N   -   problem size, N<=M
1881            Alg -   algorithm type:
1882                    *-2     auto-select Q for overlap-add
1883                    *-1     auto-select algorithm and parameters
1884                    * 0     straightforward formula for small N's
1885                    * 1     general FFT-based code
1886                    * 2     overlap-add with length Q
1887            Q   -   length for overlap-add
1888
1889        OUTPUT PARAMETERS
1890            R   -   convolution: A*B. array[0..N+M-1].
1891
1892          -- ALGLIB --
1893             Copyright 21.07.2009 by Bochkanov Sergey
1894        *************************************************************************/
1895        public static void convc1dx(complex[] a,
1896            int m,
1897            complex[] b,
1898            int n,
1899            bool circular,
1900            int alg,
1901            int q,
1902            ref complex[] r)
1903        {
1904            int i = 0;
1905            int j = 0;
1906            int p = 0;
1907            int ptotal = 0;
1908            int i1 = 0;
1909            int i2 = 0;
1910            int j1 = 0;
1911            int j2 = 0;
1912            complex[] bbuf = new complex[0];
1913            complex v = 0;
1914            double ax = 0;
1915            double ay = 0;
1916            double bx = 0;
1917            double by = 0;
1918            double t = 0;
1919            double tx = 0;
1920            double ty = 0;
1921            double flopcand = 0;
1922            double flopbest = 0;
1923            int algbest = 0;
1924            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
1925            double[] buf = new double[0];
1926            double[] buf2 = new double[0];
1927            int i_ = 0;
1928            int i1_ = 0;
1929
1930            r = new complex[0];
1931
1932            alglib.ap.assert(n>0 && m>0, "ConvC1DX: incorrect N or M!");
1933            alglib.ap.assert(n<=m, "ConvC1DX: N<M assumption is false!");
1934           
1935            //
1936            // Auto-select
1937            //
1938            if( alg==-1 || alg==-2 )
1939            {
1940               
1941                //
1942                // Initial candidate: straightforward implementation.
1943                //
1944                // If we want to use auto-fitted overlap-add,
1945                // flop count is initialized by large real number - to force
1946                // another algorithm selection
1947                //
1948                algbest = 0;
1949                if( alg==-1 )
1950                {
1951                    flopbest = 2*m*n;
1952                }
1953                else
1954                {
1955                    flopbest = math.maxrealnumber;
1956                }
1957               
1958                //
1959                // Another candidate - generic FFT code
1960                //
1961                if( alg==-1 )
1962                {
1963                    if( circular && ftbase.ftbaseissmooth(m) )
1964                    {
1965                       
1966                        //
1967                        // special code for circular convolution of a sequence with a smooth length
1968                        //
1969                        flopcand = 3*ftbase.ftbasegetflopestimate(m)+6*m;
1970                        if( (double)(flopcand)<(double)(flopbest) )
1971                        {
1972                            algbest = 1;
1973                            flopbest = flopcand;
1974                        }
1975                    }
1976                    else
1977                    {
1978                       
1979                        //
1980                        // general cyclic/non-cyclic convolution
1981                        //
1982                        p = ftbase.ftbasefindsmooth(m+n-1);
1983                        flopcand = 3*ftbase.ftbasegetflopestimate(p)+6*p;
1984                        if( (double)(flopcand)<(double)(flopbest) )
1985                        {
1986                            algbest = 1;
1987                            flopbest = flopcand;
1988                        }
1989                    }
1990                }
1991               
1992                //
1993                // Another candidate - overlap-add
1994                //
1995                q = 1;
1996                ptotal = 1;
1997                while( ptotal<n )
1998                {
1999                    ptotal = ptotal*2;
2000                }
2001                while( ptotal<=m+n-1 )
2002                {
2003                    p = ptotal-n+1;
2004                    flopcand = (int)Math.Ceiling((double)m/(double)p)*(2*ftbase.ftbasegetflopestimate(ptotal)+8*ptotal);
2005                    if( (double)(flopcand)<(double)(flopbest) )
2006                    {
2007                        flopbest = flopcand;
2008                        algbest = 2;
2009                        q = p;
2010                    }
2011                    ptotal = ptotal*2;
2012                }
2013                alg = algbest;
2014                convc1dx(a, m, b, n, circular, alg, q, ref r);
2015                return;
2016            }
2017           
2018            //
2019            // straightforward formula for
2020            // circular and non-circular convolutions.
2021            //
2022            // Very simple code, no further comments needed.
2023            //
2024            if( alg==0 )
2025            {
2026               
2027                //
2028                // Special case: N=1
2029                //
2030                if( n==1 )
2031                {
2032                    r = new complex[m];
2033                    v = b[0];
2034                    for(i_=0; i_<=m-1;i_++)
2035                    {
2036                        r[i_] = v*a[i_];
2037                    }
2038                    return;
2039                }
2040               
2041                //
2042                // use straightforward formula
2043                //
2044                if( circular )
2045                {
2046                   
2047                    //
2048                    // circular convolution
2049                    //
2050                    r = new complex[m];
2051                    v = b[0];
2052                    for(i_=0; i_<=m-1;i_++)
2053                    {
2054                        r[i_] = v*a[i_];
2055                    }
2056                    for(i=1; i<=n-1; i++)
2057                    {
2058                        v = b[i];
2059                        i1 = 0;
2060                        i2 = i-1;
2061                        j1 = m-i;
2062                        j2 = m-1;
2063                        i1_ = (j1) - (i1);
2064                        for(i_=i1; i_<=i2;i_++)
2065                        {
2066                            r[i_] = r[i_] + v*a[i_+i1_];
2067                        }
2068                        i1 = i;
2069                        i2 = m-1;
2070                        j1 = 0;
2071                        j2 = m-i-1;
2072                        i1_ = (j1) - (i1);
2073                        for(i_=i1; i_<=i2;i_++)
2074                        {
2075                            r[i_] = r[i_] + v*a[i_+i1_];
2076                        }
2077                    }
2078                }
2079                else
2080                {
2081                   
2082                    //
2083                    // non-circular convolution
2084                    //
2085                    r = new complex[m+n-1];
2086                    for(i=0; i<=m+n-2; i++)
2087                    {
2088                        r[i] = 0;
2089                    }
2090                    for(i=0; i<=n-1; i++)
2091                    {
2092                        v = b[i];
2093                        i1_ = (0) - (i);
2094                        for(i_=i; i_<=i+m-1;i_++)
2095                        {
2096                            r[i_] = r[i_] + v*a[i_+i1_];
2097                        }
2098                    }
2099                }
2100                return;
2101            }
2102           
2103            //
2104            // general FFT-based code for
2105            // circular and non-circular convolutions.
2106            //
2107            // First, if convolution is circular, we test whether M is smooth or not.
2108            // If it is smooth, we just use M-length FFT to calculate convolution.
2109            // If it is not, we calculate non-circular convolution and wrap it arount.
2110            //
2111            // IF convolution is non-circular, we use zero-padding + FFT.
2112            //
2113            if( alg==1 )
2114            {
2115                if( circular && ftbase.ftbaseissmooth(m) )
2116                {
2117                   
2118                    //
2119                    // special code for circular convolution with smooth M
2120                    //
2121                    ftbase.ftcomplexfftplan(m, 1, plan);
2122                    buf = new double[2*m];
2123                    for(i=0; i<=m-1; i++)
2124                    {
2125                        buf[2*i+0] = a[i].x;
2126                        buf[2*i+1] = a[i].y;
2127                    }
2128                    buf2 = new double[2*m];
2129                    for(i=0; i<=n-1; i++)
2130                    {
2131                        buf2[2*i+0] = b[i].x;
2132                        buf2[2*i+1] = b[i].y;
2133                    }
2134                    for(i=n; i<=m-1; i++)
2135                    {
2136                        buf2[2*i+0] = 0;
2137                        buf2[2*i+1] = 0;
2138                    }
2139                    ftbase.ftapplyplan(plan, buf, 0, 1);
2140                    ftbase.ftapplyplan(plan, buf2, 0, 1);
2141                    for(i=0; i<=m-1; i++)
2142                    {
2143                        ax = buf[2*i+0];
2144                        ay = buf[2*i+1];
2145                        bx = buf2[2*i+0];
2146                        by = buf2[2*i+1];
2147                        tx = ax*bx-ay*by;
2148                        ty = ax*by+ay*bx;
2149                        buf[2*i+0] = tx;
2150                        buf[2*i+1] = -ty;
2151                    }
2152                    ftbase.ftapplyplan(plan, buf, 0, 1);
2153                    t = (double)1/(double)m;
2154                    r = new complex[m];
2155                    for(i=0; i<=m-1; i++)
2156                    {
2157                        r[i].x = t*buf[2*i+0];
2158                        r[i].y = -(t*buf[2*i+1]);
2159                    }
2160                }
2161                else
2162                {
2163                   
2164                    //
2165                    // M is non-smooth, general code (circular/non-circular):
2166                    // * first part is the same for circular and non-circular
2167                    //   convolutions. zero padding, FFTs, inverse FFTs
2168                    // * second part differs:
2169                    //   * for non-circular convolution we just copy array
2170                    //   * for circular convolution we add array tail to its head
2171                    //
2172                    p = ftbase.ftbasefindsmooth(m+n-1);
2173                    ftbase.ftcomplexfftplan(p, 1, plan);
2174                    buf = new double[2*p];
2175                    for(i=0; i<=m-1; i++)
2176                    {
2177                        buf[2*i+0] = a[i].x;
2178                        buf[2*i+1] = a[i].y;
2179                    }
2180                    for(i=m; i<=p-1; i++)
2181                    {
2182                        buf[2*i+0] = 0;
2183                        buf[2*i+1] = 0;
2184                    }
2185                    buf2 = new double[2*p];
2186                    for(i=0; i<=n-1; i++)
2187                    {
2188                        buf2[2*i+0] = b[i].x;
2189                        buf2[2*i+1] = b[i].y;
2190                    }
2191                    for(i=n; i<=p-1; i++)
2192                    {
2193                        buf2[2*i+0] = 0;
2194                        buf2[2*i+1] = 0;
2195                    }
2196                    ftbase.ftapplyplan(plan, buf, 0, 1);
2197                    ftbase.ftapplyplan(plan, buf2, 0, 1);
2198                    for(i=0; i<=p-1; i++)
2199                    {
2200                        ax = buf[2*i+0];
2201                        ay = buf[2*i+1];
2202                        bx = buf2[2*i+0];
2203                        by = buf2[2*i+1];
2204                        tx = ax*bx-ay*by;
2205                        ty = ax*by+ay*bx;
2206                        buf[2*i+0] = tx;
2207                        buf[2*i+1] = -ty;
2208                    }
2209                    ftbase.ftapplyplan(plan, buf, 0, 1);
2210                    t = (double)1/(double)p;
2211                    if( circular )
2212                    {
2213                       
2214                        //
2215                        // circular, add tail to head
2216                        //
2217                        r = new complex[m];
2218                        for(i=0; i<=m-1; i++)
2219                        {
2220                            r[i].x = t*buf[2*i+0];
2221                            r[i].y = -(t*buf[2*i+1]);
2222                        }
2223                        for(i=m; i<=m+n-2; i++)
2224                        {
2225                            r[i-m].x = r[i-m].x+t*buf[2*i+0];
2226                            r[i-m].y = r[i-m].y-t*buf[2*i+1];
2227                        }
2228                    }
2229                    else
2230                    {
2231                       
2232                        //
2233                        // non-circular, just copy
2234                        //
2235                        r = new complex[m+n-1];
2236                        for(i=0; i<=m+n-2; i++)
2237                        {
2238                            r[i].x = t*buf[2*i+0];
2239                            r[i].y = -(t*buf[2*i+1]);
2240                        }
2241                    }
2242                }
2243                return;
2244            }
2245           
2246            //
2247            // overlap-add method for
2248            // circular and non-circular convolutions.
2249            //
2250            // First part of code (separate FFTs of input blocks) is the same
2251            // for all types of convolution. Second part (overlapping outputs)
2252            // differs for different types of convolution. We just copy output
2253            // when convolution is non-circular. We wrap it around, if it is
2254            // circular.
2255            //
2256            if( alg==2 )
2257            {
2258                buf = new double[2*(q+n-1)];
2259               
2260                //
2261                // prepare R
2262                //
2263                if( circular )
2264                {
2265                    r = new complex[m];
2266                    for(i=0; i<=m-1; i++)
2267                    {
2268                        r[i] = 0;
2269                    }
2270                }
2271                else
2272                {
2273                    r = new complex[m+n-1];
2274                    for(i=0; i<=m+n-2; i++)
2275                    {
2276                        r[i] = 0;
2277                    }
2278                }
2279               
2280                //
2281                // pre-calculated FFT(B)
2282                //
2283                bbuf = new complex[q+n-1];
2284                for(i_=0; i_<=n-1;i_++)
2285                {
2286                    bbuf[i_] = b[i_];
2287                }
2288                for(j=n; j<=q+n-2; j++)
2289                {
2290                    bbuf[j] = 0;
2291                }
2292                fft.fftc1d(ref bbuf, q+n-1);
2293               
2294                //
2295                // prepare FFT plan for chunks of A
2296                //
2297                ftbase.ftcomplexfftplan(q+n-1, 1, plan);
2298               
2299                //
2300                // main overlap-add cycle
2301                //
2302                i = 0;
2303                while( i<=m-1 )
2304                {
2305                    p = Math.Min(q, m-i);
2306                    for(j=0; j<=p-1; j++)
2307                    {
2308                        buf[2*j+0] = a[i+j].x;
2309                        buf[2*j+1] = a[i+j].y;
2310                    }
2311                    for(j=p; j<=q+n-2; j++)
2312                    {
2313                        buf[2*j+0] = 0;
2314                        buf[2*j+1] = 0;
2315                    }
2316                    ftbase.ftapplyplan(plan, buf, 0, 1);
2317                    for(j=0; j<=q+n-2; j++)
2318                    {
2319                        ax = buf[2*j+0];
2320                        ay = buf[2*j+1];
2321                        bx = bbuf[j].x;
2322                        by = bbuf[j].y;
2323                        tx = ax*bx-ay*by;
2324                        ty = ax*by+ay*bx;
2325                        buf[2*j+0] = tx;
2326                        buf[2*j+1] = -ty;
2327                    }
2328                    ftbase.ftapplyplan(plan, buf, 0, 1);
2329                    t = (double)1/(double)(q+n-1);
2330                    if( circular )
2331                    {
2332                        j1 = Math.Min(i+p+n-2, m-1)-i;
2333                        j2 = j1+1;
2334                    }
2335                    else
2336                    {
2337                        j1 = p+n-2;
2338                        j2 = j1+1;
2339                    }
2340                    for(j=0; j<=j1; j++)
2341                    {
2342                        r[i+j].x = r[i+j].x+buf[2*j+0]*t;
2343                        r[i+j].y = r[i+j].y-buf[2*j+1]*t;
2344                    }
2345                    for(j=j2; j<=p+n-2; j++)
2346                    {
2347                        r[j-j2].x = r[j-j2].x+buf[2*j+0]*t;
2348                        r[j-j2].y = r[j-j2].y-buf[2*j+1]*t;
2349                    }
2350                    i = i+p;
2351                }
2352                return;
2353            }
2354        }
2355
2356
2357        /*************************************************************************
2358        1-dimensional real convolution.
2359
2360        Extended subroutine which allows to choose convolution algorithm.
2361        Intended for internal use, ALGLIB users should call ConvR1D().
2362
2363        INPUT PARAMETERS
2364            A   -   array[0..M-1] - complex function to be transformed
2365            M   -   problem size
2366            B   -   array[0..N-1] - complex function to be transformed
2367            N   -   problem size, N<=M
2368            Alg -   algorithm type:
2369                    *-2     auto-select Q for overlap-add
2370                    *-1     auto-select algorithm and parameters
2371                    * 0     straightforward formula for small N's
2372                    * 1     general FFT-based code
2373                    * 2     overlap-add with length Q
2374            Q   -   length for overlap-add
2375
2376        OUTPUT PARAMETERS
2377            R   -   convolution: A*B. array[0..N+M-1].
2378
2379          -- ALGLIB --
2380             Copyright 21.07.2009 by Bochkanov Sergey
2381        *************************************************************************/
2382        public static void convr1dx(double[] a,
2383            int m,
2384            double[] b,
2385            int n,
2386            bool circular,
2387            int alg,
2388            int q,
2389            ref double[] r)
2390        {
2391            double v = 0;
2392            int i = 0;
2393            int j = 0;
2394            int p = 0;
2395            int ptotal = 0;
2396            int i1 = 0;
2397            int i2 = 0;
2398            int j1 = 0;
2399            int j2 = 0;
2400            double ax = 0;
2401            double ay = 0;
2402            double bx = 0;
2403            double by = 0;
2404            double tx = 0;
2405            double ty = 0;
2406            double flopcand = 0;
2407            double flopbest = 0;
2408            int algbest = 0;
2409            ftbase.fasttransformplan plan = new ftbase.fasttransformplan();
2410            double[] buf = new double[0];
2411            double[] buf2 = new double[0];
2412            double[] buf3 = new double[0];
2413            int i_ = 0;
2414            int i1_ = 0;
2415
2416            r = new double[0];
2417
2418            alglib.ap.assert(n>0 && m>0, "ConvC1DX: incorrect N or M!");
2419            alglib.ap.assert(n<=m, "ConvC1DX: N<M assumption is false!");
2420           
2421            //
2422            // handle special cases
2423            //
2424            if( Math.Min(m, n)<=2 )
2425            {
2426                alg = 0;
2427            }
2428           
2429            //
2430            // Auto-select
2431            //
2432            if( alg<0 )
2433            {
2434               
2435                //
2436                // Initial candidate: straightforward implementation.
2437                //
2438                // If we want to use auto-fitted overlap-add,
2439                // flop count is initialized by large real number - to force
2440                // another algorithm selection
2441                //
2442                algbest = 0;
2443                if( alg==-1 )
2444                {
2445                    flopbest = 0.15*m*n;
2446                }
2447                else
2448                {
2449                    flopbest = math.maxrealnumber;
2450                }
2451               
2452                //
2453                // Another candidate - generic FFT code
2454                //
2455                if( alg==-1 )
2456                {
2457                    if( (circular && ftbase.ftbaseissmooth(m)) && m%2==0 )
2458                    {
2459                       
2460                        //
2461                        // special code for circular convolution of a sequence with a smooth length
2462                        //
2463                        flopcand = 3*ftbase.ftbasegetflopestimate(m/2)+(double)(6*m)/(double)2;
2464                        if( (double)(flopcand)<(double)(flopbest) )
2465                        {
2466                            algbest = 1;
2467                            flopbest = flopcand;
2468                        }
2469                    }
2470                    else
2471                    {
2472                       
2473                        //
2474                        // general cyclic/non-cyclic convolution
2475                        //
2476                        p = ftbase.ftbasefindsmootheven(m+n-1);
2477                        flopcand = 3*ftbase.ftbasegetflopestimate(p/2)+(double)(6*p)/(double)2;
2478                        if( (double)(flopcand)<(double)(flopbest) )
2479                        {
2480                            algbest = 1;
2481                            flopbest = flopcand;
2482                        }
2483                    }
2484                }
2485               
2486                //
2487                // Another candidate - overlap-add
2488                //
2489                q = 1;
2490                ptotal = 1;
2491                while( ptotal<n )
2492                {
2493                    ptotal = ptotal*2;
2494                }
2495                while( ptotal<=m+n-1 )
2496                {
2497                    p = ptotal-n+1;
2498                    flopcand = (int)Math.Ceiling((double)m/(double)p)*(2*ftbase.ftbasegetflopestimate(ptotal/2)+1*(ptotal/2));
2499                    if( (double)(flopcand)<(double)(flopbest) )
2500                    {
2501                        flopbest = flopcand;
2502                        algbest = 2;
2503                        q = p;
2504                    }
2505                    ptotal = ptotal*2;
2506                }
2507                alg = algbest;
2508                convr1dx(a, m, b, n, circular, alg, q, ref r);
2509                return;
2510            }
2511           
2512            //
2513            // straightforward formula for
2514            // circular and non-circular convolutions.
2515            //
2516            // Very simple code, no further comments needed.
2517            //
2518            if( alg==0 )
2519            {
2520               
2521                //
2522                // Special case: N=1
2523                //
2524                if( n==1 )
2525                {
2526                    r = new double[m];
2527                    v = b[0];
2528                    for(i_=0; i_<=m-1;i_++)
2529                    {
2530                        r[i_] = v*a[i_];
2531                    }
2532                    return;
2533                }
2534               
2535                //
2536                // use straightforward formula
2537                //
2538                if( circular )
2539                {
2540                   
2541                    //
2542                    // circular convolution
2543                    //
2544                    r = new double[m];
2545                    v = b[0];
2546                    for(i_=0; i_<=m-1;i_++)
2547                    {
2548                        r[i_] = v*a[i_];
2549                    }
2550                    for(i=1; i<=n-1; i++)
2551                    {
2552                        v = b[i];
2553                        i1 = 0;
2554                        i2 = i-1;
2555                        j1 = m-i;
2556                        j2 = m-1;
2557                        i1_ = (j1) - (i1);
2558                        for(i_=i1; i_<=i2;i_++)
2559                        {
2560                            r[i_] = r[i_] + v*a[i_+i1_];
2561                        }
2562                        i1 = i;
2563                        i2 = m-1;
2564                        j1 = 0;
2565                        j2 = m-i-1;
2566                        i1_ = (j1) - (i1);
2567                        for(i_=i1; i_<=i2;i_++)
2568                        {
2569                            r[i_] = r[i_] + v*a[i_+i1_];
2570                        }
2571                    }
2572                }
2573                else
2574                {
2575                   
2576                    //
2577                    // non-circular convolution
2578                    //
2579                    r = new double[m+n-1];
2580                    for(i=0; i<=m+n-2; i++)
2581                    {
2582                        r[i] = 0;
2583                    }
2584                    for(i=0; i<=n-1; i++)
2585                    {
2586                        v = b[i];
2587                        i1_ = (0) - (i);
2588                        for(i_=i; i_<=i+m-1;i_++)
2589                        {
2590                            r[i_] = r[i_] + v*a[i_+i1_];
2591                        }
2592                    }
2593                }
2594                return;
2595            }
2596           
2597            //
2598            // general FFT-based code for
2599            // circular and non-circular convolutions.
2600            //
2601            // First, if convolution is circular, we test whether M is smooth or not.
2602            // If it is smooth, we just use M-length FFT to calculate convolution.
2603            // If it is not, we calculate non-circular convolution and wrap it arount.
2604            //
2605            // If convolution is non-circular, we use zero-padding + FFT.
2606            //
2607            // We assume that M+N-1>2 - we should call small case code otherwise
2608            //
2609            if( alg==1 )
2610            {
2611                alglib.ap.assert(m+n-1>2, "ConvR1DX: internal error!");
2612                if( (circular && ftbase.ftbaseissmooth(m)) && m%2==0 )
2613                {
2614                   
2615                    //
2616                    // special code for circular convolution with smooth even M
2617                    //
2618                    buf = new double[m];
2619                    for(i_=0; i_<=m-1;i_++)
2620                    {
2621                        buf[i_] = a[i_];
2622                    }
2623                    buf2 = new double[m];
2624                    for(i_=0; i_<=n-1;i_++)
2625                    {
2626                        buf2[i_] = b[i_];
2627                    }
2628                    for(i=n; i<=m-1; i++)
2629                    {
2630                        buf2[i] = 0;
2631                    }
2632                    buf3 = new double[m];
2633                    ftbase.ftcomplexfftplan(m/2, 1, plan);
2634                    fft.fftr1dinternaleven(ref buf, m, ref buf3, plan);
2635                    fft.fftr1dinternaleven(ref buf2, m, ref buf3, plan);
2636                    buf[0] = buf[0]*buf2[0];
2637                    buf[1] = buf[1]*buf2[1];
2638                    for(i=1; i<=m/2-1; i++)
2639                    {
2640                        ax = buf[2*i+0];
2641                        ay = buf[2*i+1];
2642                        bx = buf2[2*i+0];
2643                        by = buf2[2*i+1];
2644                        tx = ax*bx-ay*by;
2645                        ty = ax*by+ay*bx;
2646                        buf[2*i+0] = tx;
2647                        buf[2*i+1] = ty;
2648                    }
2649                    fft.fftr1dinvinternaleven(ref buf, m, ref buf3, plan);
2650                    r = new double[m];
2651                    for(i_=0; i_<=m-1;i_++)
2652                    {
2653                        r[i_] = buf[i_];
2654                    }
2655                }
2656                else
2657                {
2658                   
2659                    //
2660                    // M is non-smooth or non-even, general code (circular/non-circular):
2661                    // * first part is the same for circular and non-circular
2662                    //   convolutions. zero padding, FFTs, inverse FFTs
2663                    // * second part differs:
2664                    //   * for non-circular convolution we just copy array
2665                    //   * for circular convolution we add array tail to its head
2666                    //
2667                    p = ftbase.ftbasefindsmootheven(m+n-1);
2668                    buf = new double[p];
2669                    for(i_=0; i_<=m-1;i_++)
2670                    {
2671                        buf[i_] = a[i_];
2672                    }
2673                    for(i=m; i<=p-1; i++)
2674                    {
2675                        buf[i] = 0;
2676                    }
2677                    buf2 = new double[p];
2678                    for(i_=0; i_<=n-1;i_++)
2679                    {
2680                        buf2[i_] = b[i_];
2681                    }
2682                    for(i=n; i<=p-1; i++)
2683                    {
2684                        buf2[i] = 0;
2685                    }
2686                    buf3 = new double[p];
2687                    ftbase.ftcomplexfftplan(p/2, 1, plan);
2688                    fft.fftr1dinternaleven(ref buf, p, ref buf3, plan);
2689                    fft.fftr1dinternaleven(ref buf2, p, ref buf3, plan);
2690                    buf[0] = buf[0]*buf2[0];
2691                    buf[1] = buf[1]*buf2[1];
2692                    for(i=1; i<=p/2-1; i++)
2693                    {
2694                        ax = buf[2*i+0];
2695                        ay = buf[2*i+1];
2696                        bx = buf2[2*i+0];
2697                        by = buf2[2*i+1];
2698                        tx = ax*bx-ay*by;
2699                        ty = ax*by+ay*bx;
2700                        buf[2*i+0] = tx;
2701                        buf[2*i+1] = ty;
2702                    }
2703                    fft.fftr1dinvinternaleven(ref buf, p, ref buf3, plan);
2704                    if( circular )
2705                    {
2706                       
2707                        //
2708                        // circular, add tail to head
2709                        //
2710                        r = new double[m];
2711                        for(i_=0; i_<=m-1;i_++)
2712                        {
2713                            r[i_] = buf[i_];
2714                        }
2715                        if( n>=2 )
2716                        {
2717                            i1_ = (m) - (0);
2718                            for(i_=0; i_<=n-2;i_++)
2719                            {
2720                                r[i_] = r[i_] + buf[i_+i1_];
2721                            }
2722                        }
2723                    }
2724                    else
2725                    {
2726                       
2727                        //
2728                        // non-circular, just copy
2729                        //
2730                        r = new double[m+n-1];
2731                        for(i_=0; i_<=m+n-2;i_++)
2732                        {
2733                            r[i_] = buf[i_];
2734                        }
2735                    }
2736                }
2737                return;
2738            }
2739           
2740            //
2741            // overlap-add method
2742            //
2743            if( alg==2 )
2744            {
2745                alglib.ap.assert((q+n-1)%2==0, "ConvR1DX: internal error!");
2746                buf = new double[q+n-1];
2747                buf2 = new double[q+n-1];
2748                buf3 = new double[q+n-1];
2749                ftbase.ftcomplexfftplan((q+n-1)/2, 1, plan);
2750               
2751                //
2752                // prepare R
2753                //
2754                if( circular )
2755                {
2756                    r = new double[m];
2757                    for(i=0; i<=m-1; i++)
2758                    {
2759                        r[i] = 0;
2760                    }
2761                }
2762                else
2763                {
2764                    r = new double[m+n-1];
2765                    for(i=0; i<=m+n-2; i++)
2766                    {
2767                        r[i] = 0;
2768                    }
2769                }
2770               
2771                //
2772                // pre-calculated FFT(B)
2773                //
2774                for(i_=0; i_<=n-1;i_++)
2775                {
2776                    buf2[i_] = b[i_];
2777                }
2778                for(j=n; j<=q+n-2; j++)
2779                {
2780                    buf2[j] = 0;
2781                }
2782                fft.fftr1dinternaleven(ref buf2, q+n-1, ref buf3, plan);
2783               
2784                //
2785                // main overlap-add cycle
2786                //
2787                i = 0;
2788                while( i<=m-1 )
2789                {
2790                    p = Math.Min(q, m-i);
2791                    i1_ = (i) - (0);
2792                    for(i_=0; i_<=p-1;i_++)
2793                    {
2794                        buf[i_] = a[i_+i1_];
2795                    }
2796                    for(j=p; j<=q+n-2; j++)
2797                    {
2798                        buf[j] = 0;
2799                    }
2800                    fft.fftr1dinternaleven(ref buf, q+n-1, ref buf3, plan);
2801                    buf[0] = buf[0]*buf2[0];
2802                    buf[1] = buf[1]*buf2[1];
2803                    for(j=1; j<=(q+n-1)/2-1; j++)
2804                    {
2805                        ax = buf[2*j+0];
2806                        ay = buf[2*j+1];
2807                        bx = buf2[2*j+0];
2808                        by = buf2[2*j+1];
2809                        tx = ax*bx-ay*by;
2810                        ty = ax*by+ay*bx;
2811                        buf[2*j+0] = tx;
2812                        buf[2*j+1] = ty;
2813                    }
2814                    fft.fftr1dinvinternaleven(ref buf, q+n-1, ref buf3, plan);
2815                    if( circular )
2816                    {
2817                        j1 = Math.Min(i+p+n-2, m-1)-i;
2818                        j2 = j1+1;
2819                    }
2820                    else
2821                    {
2822                        j1 = p+n-2;
2823                        j2 = j1+1;
2824                    }
2825                    i1_ = (0) - (i);
2826                    for(i_=i; i_<=i+j1;i_++)
2827                    {
2828                        r[i_] = r[i_] + buf[i_+i1_];
2829                    }
2830                    if( p+n-2>=j2 )
2831                    {
2832                        i1_ = (j2) - (0);
2833                        for(i_=0; i_<=p+n-2-j2;i_++)
2834                        {
2835                            r[i_] = r[i_] + buf[i_+i1_];
2836                        }
2837                    }
2838                    i = i+p;
2839                }
2840                return;
2841            }
2842        }
2843
2844
2845    }
2846    public class corr
2847    {
2848        /*************************************************************************
2849        1-dimensional complex cross-correlation.
2850
2851        For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
2852
2853        Correlation is calculated using reduction to  convolution.  Algorithm with
2854        max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
2855        about performance).
2856
2857        IMPORTANT:
2858            for  historical reasons subroutine accepts its parameters in  reversed
2859            order: CorrC1D(Signal, Pattern) = Pattern x Signal (using  traditional
2860            definition of cross-correlation, denoting cross-correlation as "x").
2861
2862        INPUT PARAMETERS
2863            Signal  -   array[0..N-1] - complex function to be transformed,
2864                        signal containing pattern
2865            N       -   problem size
2866            Pattern -   array[0..M-1] - complex function to be transformed,
2867                        pattern to search withing signal
2868            M       -   problem size
2869
2870        OUTPUT PARAMETERS
2871            R       -   cross-correlation, array[0..N+M-2]:
2872                        * positive lags are stored in R[0..N-1],
2873                          R[i] = sum(conj(pattern[j])*signal[i+j]
2874                        * negative lags are stored in R[N..N+M-2],
2875                          R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]
2876
2877        NOTE:
2878            It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
2879        on [-K..M-1],  you can still use this subroutine, just shift result by K.
2880
2881          -- ALGLIB --
2882             Copyright 21.07.2009 by Bochkanov Sergey
2883        *************************************************************************/
2884        public static void corrc1d(complex[] signal,
2885            int n,
2886            complex[] pattern,
2887            int m,
2888            ref complex[] r)
2889        {
2890            complex[] p = new complex[0];
2891            complex[] b = new complex[0];
2892            int i = 0;
2893            int i_ = 0;
2894            int i1_ = 0;
2895
2896            r = new complex[0];
2897
2898            alglib.ap.assert(n>0 && m>0, "CorrC1D: incorrect N or M!");
2899            p = new complex[m];
2900            for(i=0; i<=m-1; i++)
2901            {
2902                p[m-1-i] = math.conj(pattern[i]);
2903            }
2904            conv.convc1d(p, m, signal, n, ref b);
2905            r = new complex[m+n-1];
2906            i1_ = (m-1) - (0);
2907            for(i_=0; i_<=n-1;i_++)
2908            {
2909                r[i_] = b[i_+i1_];
2910            }
2911            if( m+n-2>=n )
2912            {
2913                i1_ = (0) - (n);
2914                for(i_=n; i_<=m+n-2;i_++)
2915                {
2916                    r[i_] = b[i_+i1_];
2917                }
2918            }
2919        }
2920
2921
2922        /*************************************************************************
2923        1-dimensional circular complex cross-correlation.
2924
2925        For given Pattern/Signal returns corr(Pattern,Signal) (circular).
2926        Algorithm has linearithmic complexity for any M/N.
2927
2928        IMPORTANT:
2929            for  historical reasons subroutine accepts its parameters in  reversed
2930            order:   CorrC1DCircular(Signal, Pattern) = Pattern x Signal    (using
2931            traditional definition of cross-correlation, denoting cross-correlation
2932            as "x").
2933
2934        INPUT PARAMETERS
2935            Signal  -   array[0..N-1] - complex function to be transformed,
2936                        periodic signal containing pattern
2937            N       -   problem size
2938            Pattern -   array[0..M-1] - complex function to be transformed,
2939                        non-periodic pattern to search withing signal
2940            M       -   problem size
2941
2942        OUTPUT PARAMETERS
2943            R   -   convolution: A*B. array[0..M-1].
2944
2945
2946          -- ALGLIB --
2947             Copyright 21.07.2009 by Bochkanov Sergey
2948        *************************************************************************/
2949        public static void corrc1dcircular(complex[] signal,
2950            int m,
2951            complex[] pattern,
2952            int n,
2953            ref complex[] c)
2954        {
2955            complex[] p = new complex[0];
2956            complex[] b = new complex[0];
2957            int i1 = 0;
2958            int i2 = 0;
2959            int i = 0;
2960            int j2 = 0;
2961            int i_ = 0;
2962            int i1_ = 0;
2963
2964            c = new complex[0];
2965
2966            alglib.ap.assert(n>0 && m>0, "ConvC1DCircular: incorrect N or M!");
2967           
2968            //
2969            // normalize task: make M>=N,
2970            // so A will be longer (at least - not shorter) that B.
2971            //
2972            if( m<n )
2973            {
2974                b = new complex[m];
2975                for(i1=0; i1<=m-1; i1++)
2976                {
2977                    b[i1] = 0;
2978                }
2979                i1 = 0;
2980                while( i1<n )
2981                {
2982                    i2 = Math.Min(i1+m-1, n-1);
2983                    j2 = i2-i1;
2984                    i1_ = (i1) - (0);
2985                    for(i_=0; i_<=j2;i_++)
2986                    {
2987                        b[i_] = b[i_] + pattern[i_+i1_];
2988                    }
2989                    i1 = i1+m;
2990                }
2991                corrc1dcircular(signal, m, b, m, ref c);
2992                return;
2993            }
2994           
2995            //
2996            // Task is normalized
2997            //
2998            p = new complex[n];
2999            for(i=0; i<=n-1; i++)
3000            {
3001                p[n-1-i] = math.conj(pattern[i]);
3002            }
3003            conv.convc1dcircular(signal, m, p, n, ref b);
3004            c = new complex[m];
3005            i1_ = (n-1) - (0);
3006            for(i_=0; i_<=m-n;i_++)
3007            {
3008                c[i_] = b[i_+i1_];
3009            }
3010            if( m-n+1<=m-1 )
3011            {
3012                i1_ = (0) - (m-n+1);
3013                for(i_=m-n+1; i_<=m-1;i_++)
3014                {
3015                    c[i_] = b[i_+i1_];
3016                }
3017            }
3018        }
3019
3020
3021        /*************************************************************************
3022        1-dimensional real cross-correlation.
3023
3024        For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
3025
3026        Correlation is calculated using reduction to  convolution.  Algorithm with
3027        max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
3028        about performance).
3029
3030        IMPORTANT:
3031            for  historical reasons subroutine accepts its parameters in  reversed
3032            order: CorrR1D(Signal, Pattern) = Pattern x Signal (using  traditional
3033            definition of cross-correlation, denoting cross-correlation as "x").
3034
3035        INPUT PARAMETERS
3036            Signal  -   array[0..N-1] - real function to be transformed,
3037                        signal containing pattern
3038            N       -   problem size
3039            Pattern -   array[0..M-1] - real function to be transformed,
3040                        pattern to search withing signal
3041            M       -   problem size
3042
3043        OUTPUT PARAMETERS
3044            R       -   cross-correlation, array[0..N+M-2]:
3045                        * positive lags are stored in R[0..N-1],
3046                          R[i] = sum(pattern[j]*signal[i+j]
3047                        * negative lags are stored in R[N..N+M-2],
3048                          R[N+M-1-i] = sum(pattern[j]*signal[-i+j]
3049
3050        NOTE:
3051            It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
3052        on [-K..M-1],  you can still use this subroutine, just shift result by K.
3053
3054          -- ALGLIB --
3055             Copyright 21.07.2009 by Bochkanov Sergey
3056        *************************************************************************/
3057        public static void corrr1d(double[] signal,
3058            int n,
3059            double[] pattern,
3060            int m,
3061            ref double[] r)
3062        {
3063            double[] p = new double[0];
3064            double[] b = new double[0];
3065            int i = 0;
3066            int i_ = 0;
3067            int i1_ = 0;
3068
3069            r = new double[0];
3070
3071            alglib.ap.assert(n>0 && m>0, "CorrR1D: incorrect N or M!");
3072            p = new double[m];
3073            for(i=0; i<=m-1; i++)
3074            {
3075                p[m-1-i] = pattern[i];
3076            }
3077            conv.convr1d(p, m, signal, n, ref b);
3078            r = new double[m+n-1];
3079            i1_ = (m-1) - (0);
3080            for(i_=0; i_<=n-1;i_++)
3081            {
3082                r[i_] = b[i_+i1_];
3083            }
3084            if( m+n-2>=n )
3085            {
3086                i1_ = (0) - (n);
3087                for(i_=n; i_<=m+n-2;i_++)
3088                {
3089                    r[i_] = b[i_+i1_];
3090                }
3091            }
3092        }
3093
3094
3095        /*************************************************************************
3096        1-dimensional circular real cross-correlation.
3097
3098        For given Pattern/Signal returns corr(Pattern,Signal) (circular).
3099        Algorithm has linearithmic complexity for any M/N.
3100
3101        IMPORTANT:
3102            for  historical reasons subroutine accepts its parameters in  reversed
3103            order:   CorrR1DCircular(Signal, Pattern) = Pattern x Signal    (using
3104            traditional definition of cross-correlation, denoting cross-correlation
3105            as "x").
3106
3107        INPUT PARAMETERS
3108            Signal  -   array[0..N-1] - real function to be transformed,
3109                        periodic signal containing pattern
3110            N       -   problem size
3111            Pattern -   array[0..M-1] - real function to be transformed,
3112                        non-periodic pattern to search withing signal
3113            M       -   problem size
3114
3115        OUTPUT PARAMETERS
3116            R   -   convolution: A*B. array[0..M-1].
3117
3118
3119          -- ALGLIB --
3120             Copyright 21.07.2009 by Bochkanov Sergey
3121        *************************************************************************/
3122        public static void corrr1dcircular(double[] signal,
3123            int m,
3124            double[] pattern,
3125            int n,
3126            ref double[] c)
3127        {
3128            double[] p = new double[0];
3129            double[] b = new double[0];
3130            int i1 = 0;
3131            int i2 = 0;
3132            int i = 0;
3133            int j2 = 0;
3134            int i_ = 0;
3135            int i1_ = 0;
3136
3137            c = new double[0];
3138
3139            alglib.ap.assert(n>0 && m>0, "ConvC1DCircular: incorrect N or M!");
3140           
3141            //
3142            // normalize task: make M>=N,
3143            // so A will be longer (at least - not shorter) that B.
3144            //
3145            if( m<n )
3146            {
3147                b = new double[m];
3148                for(i1=0; i1<=m-1; i1++)
3149                {
3150                    b[i1] = 0;
3151                }
3152                i1 = 0;
3153                while( i1<n )
3154                {
3155                    i2 = Math.Min(i1+m-1, n-1);
3156                    j2 = i2-i1;
3157                    i1_ = (i1) - (0);
3158                    for(i_=0; i_<=j2;i_++)
3159                    {
3160                        b[i_] = b[i_] + pattern[i_+i1_];
3161                    }
3162                    i1 = i1+m;
3163                }
3164                corrr1dcircular(signal, m, b, m, ref c);
3165                return;
3166            }
3167           
3168            //
3169            // Task is normalized
3170            //
3171            p = new double[n];
3172            for(i=0; i<=n-1; i++)
3173            {
3174                p[n-1-i] = pattern[i];
3175            }
3176            conv.convr1dcircular(signal, m, p, n, ref b);
3177            c = new double[m];
3178            i1_ = (n-1) - (0);
3179            for(i_=0; i_<=m-n;i_++)
3180            {
3181                c[i_] = b[i_+i1_];
3182            }
3183            if( m-n+1<=m-1 )
3184            {
3185                i1_ = (0) - (m-n+1);
3186                for(i_=m-n+1; i_<=m-1;i_++)
3187                {
3188                    c[i_] = b[i_+i1_];
3189                }
3190            }
3191        }
3192
3193
3194    }
3195    public class fht
3196    {
3197        /*************************************************************************
3198        1-dimensional Fast Hartley Transform.
3199
3200        Algorithm has O(N*logN) complexity for any N (composite or prime).
3201
3202        INPUT PARAMETERS
3203            A   -   array[0..N-1] - real function to be transformed
3204            N   -   problem size
3205           
3206        OUTPUT PARAMETERS
3207            A   -   FHT of a input array, array[0..N-1],
3208                    A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)
3209
3210
3211          -- ALGLIB --
3212             Copyright 04.06.2009 by Bochkanov Sergey
3213        *************************************************************************/
3214        public static void fhtr1d(ref double[] a,
3215            int n)
3216        {
3217            int i = 0;
3218            complex[] fa = new complex[0];
3219
3220            alglib.ap.assert(n>0, "FHTR1D: incorrect N!");
3221           
3222            //
3223            // Special case: N=1, FHT is just identity transform.
3224            // After this block we assume that N is strictly greater than 1.
3225            //
3226            if( n==1 )
3227            {
3228                return;
3229            }
3230           
3231            //
3232            // Reduce FHt to real FFT
3233            //
3234            fft.fftr1d(a, n, ref fa);
3235            for(i=0; i<=n-1; i++)
3236            {
3237                a[i] = fa[i].x-fa[i].y;
3238            }
3239        }
3240
3241
3242        /*************************************************************************
3243        1-dimensional inverse FHT.
3244
3245        Algorithm has O(N*logN) complexity for any N (composite or prime).
3246
3247        INPUT PARAMETERS
3248            A   -   array[0..N-1] - complex array to be transformed
3249            N   -   problem size
3250
3251        OUTPUT PARAMETERS
3252            A   -   inverse FHT of a input array, array[0..N-1]
3253
3254
3255          -- ALGLIB --
3256             Copyright 29.05.2009 by Bochkanov Sergey
3257        *************************************************************************/
3258        public static void fhtr1dinv(ref double[] a,
3259            int n)
3260        {
3261            int i = 0;
3262
3263            alglib.ap.assert(n>0, "FHTR1DInv: incorrect N!");
3264           
3265            //
3266            // Special case: N=1, iFHT is just identity transform.
3267            // After this block we assume that N is strictly greater than 1.
3268            //
3269            if( n==1 )
3270            {
3271                return;
3272            }
3273           
3274            //
3275            // Inverse FHT can be expressed in terms of the FHT as
3276            //
3277            //     invfht(x) = fht(x)/N
3278            //
3279            fhtr1d(ref a, n);
3280            for(i=0; i<=n-1; i++)
3281            {
3282                a[i] = a[i]/n;
3283            }
3284        }
3285
3286
3287    }
3288}
3289
Note: See TracBrowser for help on using the repository browser.