Free cookie consent management tool by TermsFeed Policy Generator

source: branches/MathNetNumerics-Exploration-2789/HeuristicLab.Algorithms.DataAnalysis.Experimental/csharp/src/fasttransforms.cs @ 15311

Last change on this file since 15311 was 15311, checked in by gkronber, 7 years ago

#2789 exploration of alglib solver for non-linear optimization with non-linear constraints

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