Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/3.1.0/ALGLIB-3.1.0/fasttransforms.cs @ 12344

Last change on this file since 12344 was 4977, checked in by gkronber, 14 years ago

Added new alglib classes (version 3.1.0) #875

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