Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.3.0/ALGLIB-2.3.0/conv.cs @ 3021

Last change on this file since 3021 was 2806, checked in by gkronber, 15 years ago

Added plugin for new version of ALGLIB. #875 (Update ALGLIB sources)

File size: 58.9 KB
Line 
1/*************************************************************************
2Copyright (c) 2009, 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
18>>> END OF LICENSE >>>
19*************************************************************************/
20
21using System;
22
23namespace alglib
24{
25    public class conv
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(ref AP.Complex[] a,
57            int m,
58            ref AP.Complex[] b,
59            int n,
60            ref AP.Complex[] r)
61        {
62            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1D: incorrect N or M!");
63           
64            //
65            // normalize task: make M>=N,
66            // so A will be longer that B.
67            //
68            if( m<n )
69            {
70                convc1d(ref b, n, ref a, m, ref r);
71                return;
72            }
73            convc1dx(ref a, m, ref b, n, false, -1, 0, ref r);
74        }
75
76
77        /*************************************************************************
78        1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
79
80        Algorithm has M*log(M)) complexity for any M (composite or prime).
81
82        INPUT PARAMETERS
83            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
84            M   -   convolved signal length
85            B   -   array[0..N-1] - response
86            N   -   response length, N<=M
87
88        OUTPUT PARAMETERS
89            R   -   deconvolved signal. array[0..M-N].
90
91        NOTE:
92            deconvolution is unstable process and may result in division  by  zero
93        (if your response function is degenerate, i.e. has zero Fourier coefficient).
94
95        NOTE:
96            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
97        functions have non-zero values at negative T's, you  can  still  use  this
98        subroutine - just shift its result correspondingly.
99
100          -- ALGLIB --
101             Copyright 21.07.2009 by Bochkanov Sergey
102        *************************************************************************/
103        public static void convc1dinv(ref AP.Complex[] a,
104            int m,
105            ref AP.Complex[] b,
106            int n,
107            ref AP.Complex[] r)
108        {
109            int i = 0;
110            int p = 0;
111            double[] buf = new double[0];
112            double[] buf2 = new double[0];
113            ftbase.ftplan plan = new ftbase.ftplan();
114            AP.Complex c1 = 0;
115            AP.Complex c2 = 0;
116            AP.Complex c3 = 0;
117            double t = 0;
118
119            System.Diagnostics.Debug.Assert(n>0 & m>0 & n<=m, "ConvC1DInv: incorrect N or M!");
120            p = ftbase.ftbasefindsmooth(m);
121            ftbase.ftbasegeneratecomplexfftplan(p, ref plan);
122            buf = new double[2*p];
123            for(i=0; i<=m-1; i++)
124            {
125                buf[2*i+0] = a[i].x;
126                buf[2*i+1] = a[i].y;
127            }
128            for(i=m; i<=p-1; i++)
129            {
130                buf[2*i+0] = 0;
131                buf[2*i+1] = 0;
132            }
133            buf2 = new double[2*p];
134            for(i=0; i<=n-1; i++)
135            {
136                buf2[2*i+0] = b[i].x;
137                buf2[2*i+1] = b[i].y;
138            }
139            for(i=n; i<=p-1; i++)
140            {
141                buf2[2*i+0] = 0;
142                buf2[2*i+1] = 0;
143            }
144            ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
145            ftbase.ftbaseexecuteplan(ref buf2, 0, p, ref plan);
146            for(i=0; i<=p-1; i++)
147            {
148                c1.x = buf[2*i+0];
149                c1.y = buf[2*i+1];
150                c2.x = buf2[2*i+0];
151                c2.y = buf2[2*i+1];
152                c3 = c1/c2;
153                buf[2*i+0] = c3.x;
154                buf[2*i+1] = -c3.y;
155            }
156            ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
157            t = (double)(1)/(double)(p);
158            r = new AP.Complex[m-n+1];
159            for(i=0; i<=m-n; i++)
160            {
161                r[i].x = +(t*buf[2*i+0]);
162                r[i].y = -(t*buf[2*i+1]);
163            }
164        }
165
166
167        /*************************************************************************
168        1-dimensional circular complex convolution.
169
170        For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
171        complexity for any M/N.
172
173        IMPORTANT:  normal convolution is commutative,  i.e.   it  is symmetric  -
174        conv(A,B)=conv(B,A).  Cyclic convolution IS NOT.  One function - S - is  a
175        signal,  periodic function, and another - R - is a response,  non-periodic
176        function with limited length.
177
178        INPUT PARAMETERS
179            S   -   array[0..M-1] - complex periodic signal
180            M   -   problem size
181            B   -   array[0..N-1] - complex non-periodic response
182            N   -   problem size
183
184        OUTPUT PARAMETERS
185            R   -   convolution: A*B. array[0..M-1].
186
187        NOTE:
188            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
189        functions have non-zero values at negative T's, you  can  still  use  this
190        subroutine - just shift its result correspondingly.
191
192          -- ALGLIB --
193             Copyright 21.07.2009 by Bochkanov Sergey
194        *************************************************************************/
195        public static void convc1dcircular(ref AP.Complex[] s,
196            int m,
197            ref AP.Complex[] r,
198            int n,
199            ref AP.Complex[] c)
200        {
201            AP.Complex[] buf = new AP.Complex[0];
202            int i1 = 0;
203            int i2 = 0;
204            int j2 = 0;
205            int i_ = 0;
206            int i1_ = 0;
207
208            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircular: incorrect N or M!");
209           
210            //
211            // normalize task: make M>=N,
212            // so A will be longer (at least - not shorter) that B.
213            //
214            if( m<n )
215            {
216                buf = new AP.Complex[m];
217                for(i1=0; i1<=m-1; i1++)
218                {
219                    buf[i1] = 0;
220                }
221                i1 = 0;
222                while( i1<n )
223                {
224                    i2 = Math.Min(i1+m-1, n-1);
225                    j2 = i2-i1;
226                    i1_ = (i1) - (0);
227                    for(i_=0; i_<=j2;i_++)
228                    {
229                        buf[i_] = buf[i_] + r[i_+i1_];
230                    }
231                    i1 = i1+m;
232                }
233                convc1dcircular(ref s, m, ref buf, m, ref c);
234                return;
235            }
236            convc1dx(ref s, m, ref r, n, true, -1, 0, ref c);
237        }
238
239
240        /*************************************************************************
241        1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
242
243        Algorithm has M*log(M)) complexity for any M (composite or prime).
244
245        INPUT PARAMETERS
246            A   -   array[0..M-1] - convolved periodic signal, A = conv(R, B)
247            M   -   convolved signal length
248            B   -   array[0..N-1] - non-periodic response
249            N   -   response length
250
251        OUTPUT PARAMETERS
252            R   -   deconvolved signal. array[0..M-1].
253
254        NOTE:
255            deconvolution is unstable process and may result in division  by  zero
256        (if your response function is degenerate, i.e. has zero Fourier coefficient).
257
258        NOTE:
259            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
260        functions have non-zero values at negative T's, you  can  still  use  this
261        subroutine - just shift its result correspondingly.
262
263          -- ALGLIB --
264             Copyright 21.07.2009 by Bochkanov Sergey
265        *************************************************************************/
266        public static void convc1dcircularinv(ref AP.Complex[] a,
267            int m,
268            ref AP.Complex[] b,
269            int n,
270            ref AP.Complex[] r)
271        {
272            int i = 0;
273            int i1 = 0;
274            int i2 = 0;
275            int j2 = 0;
276            double[] buf = new double[0];
277            double[] buf2 = new double[0];
278            AP.Complex[] cbuf = new AP.Complex[0];
279            ftbase.ftplan plan = new ftbase.ftplan();
280            AP.Complex c1 = 0;
281            AP.Complex c2 = 0;
282            AP.Complex c3 = 0;
283            double t = 0;
284            int i_ = 0;
285            int i1_ = 0;
286
287            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircularInv: incorrect N or M!");
288           
289            //
290            // normalize task: make M>=N,
291            // so A will be longer (at least - not shorter) that B.
292            //
293            if( m<n )
294            {
295                cbuf = new AP.Complex[m];
296                for(i=0; i<=m-1; i++)
297                {
298                    cbuf[i] = 0;
299                }
300                i1 = 0;
301                while( i1<n )
302                {
303                    i2 = Math.Min(i1+m-1, n-1);
304                    j2 = i2-i1;
305                    i1_ = (i1) - (0);
306                    for(i_=0; i_<=j2;i_++)
307                    {
308                        cbuf[i_] = cbuf[i_] + b[i_+i1_];
309                    }
310                    i1 = i1+m;
311                }
312                convc1dcircularinv(ref a, m, ref cbuf, m, ref r);
313                return;
314            }
315           
316            //
317            // Task is normalized
318            //
319            ftbase.ftbasegeneratecomplexfftplan(m, ref plan);
320            buf = new double[2*m];
321            for(i=0; i<=m-1; i++)
322            {
323                buf[2*i+0] = a[i].x;
324                buf[2*i+1] = a[i].y;
325            }
326            buf2 = new double[2*m];
327            for(i=0; i<=n-1; i++)
328            {
329                buf2[2*i+0] = b[i].x;
330                buf2[2*i+1] = b[i].y;
331            }
332            for(i=n; i<=m-1; i++)
333            {
334                buf2[2*i+0] = 0;
335                buf2[2*i+1] = 0;
336            }
337            ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
338            ftbase.ftbaseexecuteplan(ref buf2, 0, m, ref plan);
339            for(i=0; i<=m-1; i++)
340            {
341                c1.x = buf[2*i+0];
342                c1.y = buf[2*i+1];
343                c2.x = buf2[2*i+0];
344                c2.y = buf2[2*i+1];
345                c3 = c1/c2;
346                buf[2*i+0] = c3.x;
347                buf[2*i+1] = -c3.y;
348            }
349            ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
350            t = (double)(1)/(double)(m);
351            r = new AP.Complex[m];
352            for(i=0; i<=m-1; i++)
353            {
354                r[i].x = +(t*buf[2*i+0]);
355                r[i].y = -(t*buf[2*i+1]);
356            }
357        }
358
359
360        /*************************************************************************
361        1-dimensional real convolution.
362
363        Analogous to ConvC1D(), see ConvC1D() comments for more details.
364
365        INPUT PARAMETERS
366            A   -   array[0..M-1] - real function to be transformed
367            M   -   problem size
368            B   -   array[0..N-1] - real function to be transformed
369            N   -   problem size
370
371        OUTPUT PARAMETERS
372            R   -   convolution: A*B. array[0..N+M-2].
373
374        NOTE:
375            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
376        functions have non-zero values at negative T's, you  can  still  use  this
377        subroutine - just shift its result correspondingly.
378
379          -- ALGLIB --
380             Copyright 21.07.2009 by Bochkanov Sergey
381        *************************************************************************/
382        public static void convr1d(ref double[] a,
383            int m,
384            ref double[] b,
385            int n,
386            ref double[] r)
387        {
388            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvR1D: incorrect N or M!");
389           
390            //
391            // normalize task: make M>=N,
392            // so A will be longer that B.
393            //
394            if( m<n )
395            {
396                convr1d(ref b, n, ref a, m, ref r);
397                return;
398            }
399            convr1dx(ref a, m, ref b, n, false, -1, 0, ref r);
400        }
401
402
403        /*************************************************************************
404        1-dimensional real deconvolution (inverse of ConvC1D()).
405
406        Algorithm has M*log(M)) complexity for any M (composite or prime).
407
408        INPUT PARAMETERS
409            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
410            M   -   convolved signal length
411            B   -   array[0..N-1] - response
412            N   -   response length, N<=M
413
414        OUTPUT PARAMETERS
415            R   -   deconvolved signal. array[0..M-N].
416
417        NOTE:
418            deconvolution is unstable process and may result in division  by  zero
419        (if your response function is degenerate, i.e. has zero Fourier coefficient).
420
421        NOTE:
422            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
423        functions have non-zero values at negative T's, you  can  still  use  this
424        subroutine - just shift its result correspondingly.
425
426          -- ALGLIB --
427             Copyright 21.07.2009 by Bochkanov Sergey
428        *************************************************************************/
429        public static void convr1dinv(ref double[] a,
430            int m,
431            ref double[] b,
432            int n,
433            ref double[] r)
434        {
435            int i = 0;
436            int p = 0;
437            double[] buf = new double[0];
438            double[] buf2 = new double[0];
439            double[] buf3 = new double[0];
440            ftbase.ftplan plan = new ftbase.ftplan();
441            AP.Complex c1 = 0;
442            AP.Complex c2 = 0;
443            AP.Complex c3 = 0;
444            int i_ = 0;
445
446            System.Diagnostics.Debug.Assert(n>0 & m>0 & n<=m, "ConvR1DInv: incorrect N or M!");
447            p = ftbase.ftbasefindsmootheven(m);
448            buf = new double[p];
449            for(i_=0; i_<=m-1;i_++)
450            {
451                buf[i_] = a[i_];
452            }
453            for(i=m; i<=p-1; i++)
454            {
455                buf[i] = 0;
456            }
457            buf2 = new double[p];
458            for(i_=0; i_<=n-1;i_++)
459            {
460                buf2[i_] = b[i_];
461            }
462            for(i=n; i<=p-1; i++)
463            {
464                buf2[i] = 0;
465            }
466            buf3 = new double[p];
467            ftbase.ftbasegeneratecomplexfftplan(p/2, ref plan);
468            fft.fftr1dinternaleven(ref buf, p, ref buf3, ref plan);
469            fft.fftr1dinternaleven(ref buf2, p, ref buf3, ref plan);
470            buf[0] = buf[0]/buf2[0];
471            buf[1] = buf[1]/buf2[1];
472            for(i=1; i<=p/2-1; i++)
473            {
474                c1.x = buf[2*i+0];
475                c1.y = buf[2*i+1];
476                c2.x = buf2[2*i+0];
477                c2.y = buf2[2*i+1];
478                c3 = c1/c2;
479                buf[2*i+0] = c3.x;
480                buf[2*i+1] = c3.y;
481            }
482            fft.fftr1dinvinternaleven(ref buf, p, ref buf3, ref plan);
483            r = new double[m-n+1];
484            for(i_=0; i_<=m-n;i_++)
485            {
486                r[i_] = buf[i_];
487            }
488        }
489
490
491        /*************************************************************************
492        1-dimensional circular real convolution.
493
494        Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.
495
496        INPUT PARAMETERS
497            S   -   array[0..M-1] - real signal
498            M   -   problem size
499            B   -   array[0..N-1] - real response
500            N   -   problem size
501
502        OUTPUT PARAMETERS
503            R   -   convolution: A*B. array[0..M-1].
504
505        NOTE:
506            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
507        functions have non-zero values at negative T's, you  can  still  use  this
508        subroutine - just shift its result correspondingly.
509
510          -- ALGLIB --
511             Copyright 21.07.2009 by Bochkanov Sergey
512        *************************************************************************/
513        public static void convr1dcircular(ref double[] s,
514            int m,
515            ref double[] r,
516            int n,
517            ref double[] c)
518        {
519            double[] buf = new double[0];
520            int i1 = 0;
521            int i2 = 0;
522            int j2 = 0;
523            int i_ = 0;
524            int i1_ = 0;
525
526            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircular: incorrect N or M!");
527           
528            //
529            // normalize task: make M>=N,
530            // so A will be longer (at least - not shorter) that B.
531            //
532            if( m<n )
533            {
534                buf = new double[m];
535                for(i1=0; i1<=m-1; i1++)
536                {
537                    buf[i1] = 0;
538                }
539                i1 = 0;
540                while( i1<n )
541                {
542                    i2 = Math.Min(i1+m-1, n-1);
543                    j2 = i2-i1;
544                    i1_ = (i1) - (0);
545                    for(i_=0; i_<=j2;i_++)
546                    {
547                        buf[i_] = buf[i_] + r[i_+i1_];
548                    }
549                    i1 = i1+m;
550                }
551                convr1dcircular(ref s, m, ref buf, m, ref c);
552                return;
553            }
554           
555            //
556            // reduce to usual convolution
557            //
558            convr1dx(ref s, m, ref r, n, true, -1, 0, ref c);
559        }
560
561
562        /*************************************************************************
563        1-dimensional complex deconvolution (inverse of ConvC1D()).
564
565        Algorithm has M*log(M)) complexity for any M (composite or prime).
566
567        INPUT PARAMETERS
568            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
569            M   -   convolved signal length
570            B   -   array[0..N-1] - response
571            N   -   response length
572
573        OUTPUT PARAMETERS
574            R   -   deconvolved signal. array[0..M-N].
575
576        NOTE:
577            deconvolution is unstable process and may result in division  by  zero
578        (if your response function is degenerate, i.e. has zero Fourier coefficient).
579
580        NOTE:
581            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
582        functions have non-zero values at negative T's, you  can  still  use  this
583        subroutine - just shift its result correspondingly.
584
585          -- ALGLIB --
586             Copyright 21.07.2009 by Bochkanov Sergey
587        *************************************************************************/
588        public static void convr1dcircularinv(ref double[] a,
589            int m,
590            ref double[] b,
591            int n,
592            ref double[] r)
593        {
594            int i = 0;
595            int i1 = 0;
596            int i2 = 0;
597            int j2 = 0;
598            double[] buf = new double[0];
599            double[] buf2 = new double[0];
600            double[] buf3 = new double[0];
601            AP.Complex[] cbuf = new AP.Complex[0];
602            AP.Complex[] cbuf2 = new AP.Complex[0];
603            ftbase.ftplan plan = new ftbase.ftplan();
604            AP.Complex c1 = 0;
605            AP.Complex c2 = 0;
606            AP.Complex c3 = 0;
607            int i_ = 0;
608            int i1_ = 0;
609
610            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvR1DCircularInv: incorrect N or M!");
611           
612            //
613            // normalize task: make M>=N,
614            // so A will be longer (at least - not shorter) that B.
615            //
616            if( m<n )
617            {
618                buf = new double[m];
619                for(i=0; i<=m-1; i++)
620                {
621                    buf[i] = 0;
622                }
623                i1 = 0;
624                while( i1<n )
625                {
626                    i2 = Math.Min(i1+m-1, n-1);
627                    j2 = i2-i1;
628                    i1_ = (i1) - (0);
629                    for(i_=0; i_<=j2;i_++)
630                    {
631                        buf[i_] = buf[i_] + b[i_+i1_];
632                    }
633                    i1 = i1+m;
634                }
635                convr1dcircularinv(ref a, m, ref buf, m, ref r);
636                return;
637            }
638           
639            //
640            // Task is normalized
641            //
642            if( m%2==0 )
643            {
644               
645                //
646                // size is even, use fast even-size FFT
647                //
648                buf = new double[m];
649                for(i_=0; i_<=m-1;i_++)
650                {
651                    buf[i_] = a[i_];
652                }
653                buf2 = new double[m];
654                for(i_=0; i_<=n-1;i_++)
655                {
656                    buf2[i_] = b[i_];
657                }
658                for(i=n; i<=m-1; i++)
659                {
660                    buf2[i] = 0;
661                }
662                buf3 = new double[m];
663                ftbase.ftbasegeneratecomplexfftplan(m/2, ref plan);
664                fft.fftr1dinternaleven(ref buf, m, ref buf3, ref plan);
665                fft.fftr1dinternaleven(ref buf2, m, ref buf3, ref plan);
666                buf[0] = buf[0]/buf2[0];
667                buf[1] = buf[1]/buf2[1];
668                for(i=1; i<=m/2-1; i++)
669                {
670                    c1.x = buf[2*i+0];
671                    c1.y = buf[2*i+1];
672                    c2.x = buf2[2*i+0];
673                    c2.y = buf2[2*i+1];
674                    c3 = c1/c2;
675                    buf[2*i+0] = c3.x;
676                    buf[2*i+1] = c3.y;
677                }
678                fft.fftr1dinvinternaleven(ref buf, m, ref buf3, ref plan);
679                r = new double[m];
680                for(i_=0; i_<=m-1;i_++)
681                {
682                    r[i_] = buf[i_];
683                }
684            }
685            else
686            {
687               
688                //
689                // odd-size, use general real FFT
690                //
691                fft.fftr1d(ref a, m, ref cbuf);
692                buf2 = new double[m];
693                for(i_=0; i_<=n-1;i_++)
694                {
695                    buf2[i_] = b[i_];
696                }
697                for(i=n; i<=m-1; i++)
698                {
699                    buf2[i] = 0;
700                }
701                fft.fftr1d(ref buf2, m, ref cbuf2);
702                for(i=0; i<=(int)Math.Floor((double)(m)/(double)(2)); i++)
703                {
704                    cbuf[i] = cbuf[i]/cbuf2[i];
705                }
706                fft.fftr1dinv(ref cbuf, m, ref r);
707            }
708        }
709
710
711        /*************************************************************************
712        1-dimensional complex convolution.
713
714        Extended subroutine which allows to choose convolution algorithm.
715        Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular().
716
717        INPUT PARAMETERS
718            A   -   array[0..M-1] - complex function to be transformed
719            M   -   problem size
720            B   -   array[0..N-1] - complex function to be transformed
721            N   -   problem size, N<=M
722            Alg -   algorithm type:
723                    *-2     auto-select Q for overlap-add
724                    *-1     auto-select algorithm and parameters
725                    * 0     straightforward formula for small N's
726                    * 1     general FFT-based code
727                    * 2     overlap-add with length Q
728            Q   -   length for overlap-add
729
730        OUTPUT PARAMETERS
731            R   -   convolution: A*B. array[0..N+M-1].
732
733          -- ALGLIB --
734             Copyright 21.07.2009 by Bochkanov Sergey
735        *************************************************************************/
736        public static void convc1dx(ref AP.Complex[] a,
737            int m,
738            ref AP.Complex[] b,
739            int n,
740            bool circular,
741            int alg,
742            int q,
743            ref AP.Complex[] r)
744        {
745            int i = 0;
746            int j = 0;
747            int p = 0;
748            int ptotal = 0;
749            int i1 = 0;
750            int i2 = 0;
751            int j1 = 0;
752            int j2 = 0;
753            AP.Complex[] bbuf = new AP.Complex[0];
754            AP.Complex v = 0;
755            double ax = 0;
756            double ay = 0;
757            double bx = 0;
758            double by = 0;
759            double t = 0;
760            double tx = 0;
761            double ty = 0;
762            double flopcand = 0;
763            double flopbest = 0;
764            int algbest = 0;
765            ftbase.ftplan plan = new ftbase.ftplan();
766            double[] buf = new double[0];
767            double[] buf2 = new double[0];
768            int i_ = 0;
769            int i1_ = 0;
770
771            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DX: incorrect N or M!");
772            System.Diagnostics.Debug.Assert(n<=m, "ConvC1DX: N<M assumption is false!");
773           
774            //
775            // Auto-select
776            //
777            if( alg==-1 | alg==-2 )
778            {
779               
780                //
781                // Initial candidate: straightforward implementation.
782                //
783                // If we want to use auto-fitted overlap-add,
784                // flop count is initialized by large real number - to force
785                // another algorithm selection
786                //
787                algbest = 0;
788                if( alg==-1 )
789                {
790                    flopbest = 2*m*n;
791                }
792                else
793                {
794                    flopbest = AP.Math.MaxRealNumber;
795                }
796               
797                //
798                // Another candidate - generic FFT code
799                //
800                if( alg==-1 )
801                {
802                    if( circular & ftbase.ftbaseissmooth(m) )
803                    {
804                       
805                        //
806                        // special code for circular convolution of a sequence with a smooth length
807                        //
808                        flopcand = 3*ftbase.ftbasegetflopestimate(m)+6*m;
809                        if( (double)(flopcand)<(double)(flopbest) )
810                        {
811                            algbest = 1;
812                            flopbest = flopcand;
813                        }
814                    }
815                    else
816                    {
817                       
818                        //
819                        // general cyclic/non-cyclic convolution
820                        //
821                        p = ftbase.ftbasefindsmooth(m+n-1);
822                        flopcand = 3*ftbase.ftbasegetflopestimate(p)+6*p;
823                        if( (double)(flopcand)<(double)(flopbest) )
824                        {
825                            algbest = 1;
826                            flopbest = flopcand;
827                        }
828                    }
829                }
830               
831                //
832                // Another candidate - overlap-add
833                //
834                q = 1;
835                ptotal = 1;
836                while( ptotal<n )
837                {
838                    ptotal = ptotal*2;
839                }
840                while( ptotal<=m+n-1 )
841                {
842                    p = ptotal-n+1;
843                    flopcand = (int)Math.Ceiling((double)(m)/(double)(p))*(2*ftbase.ftbasegetflopestimate(ptotal)+8*ptotal);
844                    if( (double)(flopcand)<(double)(flopbest) )
845                    {
846                        flopbest = flopcand;
847                        algbest = 2;
848                        q = p;
849                    }
850                    ptotal = ptotal*2;
851                }
852                alg = algbest;
853                convc1dx(ref a, m, ref b, n, circular, alg, q, ref r);
854                return;
855            }
856           
857            //
858            // straightforward formula for
859            // circular and non-circular convolutions.
860            //
861            // Very simple code, no further comments needed.
862            //
863            if( alg==0 )
864            {
865               
866                //
867                // Special case: N=1
868                //
869                if( n==1 )
870                {
871                    r = new AP.Complex[m];
872                    v = b[0];
873                    for(i_=0; i_<=m-1;i_++)
874                    {
875                        r[i_] = v*a[i_];
876                    }
877                    return;
878                }
879               
880                //
881                // use straightforward formula
882                //
883                if( circular )
884                {
885                   
886                    //
887                    // circular convolution
888                    //
889                    r = new AP.Complex[m];
890                    v = b[0];
891                    for(i_=0; i_<=m-1;i_++)
892                    {
893                        r[i_] = v*a[i_];
894                    }
895                    for(i=1; i<=n-1; i++)
896                    {
897                        v = b[i];
898                        i1 = 0;
899                        i2 = i-1;
900                        j1 = m-i;
901                        j2 = m-1;
902                        i1_ = (j1) - (i1);
903                        for(i_=i1; i_<=i2;i_++)
904                        {
905                            r[i_] = r[i_] + v*a[i_+i1_];
906                        }
907                        i1 = i;
908                        i2 = m-1;
909                        j1 = 0;
910                        j2 = m-i-1;
911                        i1_ = (j1) - (i1);
912                        for(i_=i1; i_<=i2;i_++)
913                        {
914                            r[i_] = r[i_] + v*a[i_+i1_];
915                        }
916                    }
917                }
918                else
919                {
920                   
921                    //
922                    // non-circular convolution
923                    //
924                    r = new AP.Complex[m+n-1];
925                    for(i=0; i<=m+n-2; i++)
926                    {
927                        r[i] = 0;
928                    }
929                    for(i=0; i<=n-1; i++)
930                    {
931                        v = b[i];
932                        i1_ = (0) - (i);
933                        for(i_=i; i_<=i+m-1;i_++)
934                        {
935                            r[i_] = r[i_] + v*a[i_+i1_];
936                        }
937                    }
938                }
939                return;
940            }
941           
942            //
943            // general FFT-based code for
944            // circular and non-circular convolutions.
945            //
946            // First, if convolution is circular, we test whether M is smooth or not.
947            // If it is smooth, we just use M-length FFT to calculate convolution.
948            // If it is not, we calculate non-circular convolution and wrap it arount.
949            //
950            // IF convolution is non-circular, we use zero-padding + FFT.
951            //
952            if( alg==1 )
953            {
954                if( circular & ftbase.ftbaseissmooth(m) )
955                {
956                   
957                    //
958                    // special code for circular convolution with smooth M
959                    //
960                    ftbase.ftbasegeneratecomplexfftplan(m, ref plan);
961                    buf = new double[2*m];
962                    for(i=0; i<=m-1; i++)
963                    {
964                        buf[2*i+0] = a[i].x;
965                        buf[2*i+1] = a[i].y;
966                    }
967                    buf2 = new double[2*m];
968                    for(i=0; i<=n-1; i++)
969                    {
970                        buf2[2*i+0] = b[i].x;
971                        buf2[2*i+1] = b[i].y;
972                    }
973                    for(i=n; i<=m-1; i++)
974                    {
975                        buf2[2*i+0] = 0;
976                        buf2[2*i+1] = 0;
977                    }
978                    ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
979                    ftbase.ftbaseexecuteplan(ref buf2, 0, m, ref plan);
980                    for(i=0; i<=m-1; i++)
981                    {
982                        ax = buf[2*i+0];
983                        ay = buf[2*i+1];
984                        bx = buf2[2*i+0];
985                        by = buf2[2*i+1];
986                        tx = ax*bx-ay*by;
987                        ty = ax*by+ay*bx;
988                        buf[2*i+0] = tx;
989                        buf[2*i+1] = -ty;
990                    }
991                    ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
992                    t = (double)(1)/(double)(m);
993                    r = new AP.Complex[m];
994                    for(i=0; i<=m-1; i++)
995                    {
996                        r[i].x = +(t*buf[2*i+0]);
997                        r[i].y = -(t*buf[2*i+1]);
998                    }
999                }
1000                else
1001                {
1002                   
1003                    //
1004                    // M is non-smooth, general code (circular/non-circular):
1005                    // * first part is the same for circular and non-circular
1006                    //   convolutions. zero padding, FFTs, inverse FFTs
1007                    // * second part differs:
1008                    //   * for non-circular convolution we just copy array
1009                    //   * for circular convolution we add array tail to its head
1010                    //
1011                    p = ftbase.ftbasefindsmooth(m+n-1);
1012                    ftbase.ftbasegeneratecomplexfftplan(p, ref plan);
1013                    buf = new double[2*p];
1014                    for(i=0; i<=m-1; i++)
1015                    {
1016                        buf[2*i+0] = a[i].x;
1017                        buf[2*i+1] = a[i].y;
1018                    }
1019                    for(i=m; i<=p-1; i++)
1020                    {
1021                        buf[2*i+0] = 0;
1022                        buf[2*i+1] = 0;
1023                    }
1024                    buf2 = new double[2*p];
1025                    for(i=0; i<=n-1; i++)
1026                    {
1027                        buf2[2*i+0] = b[i].x;
1028                        buf2[2*i+1] = b[i].y;
1029                    }
1030                    for(i=n; i<=p-1; i++)
1031                    {
1032                        buf2[2*i+0] = 0;
1033                        buf2[2*i+1] = 0;
1034                    }
1035                    ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
1036                    ftbase.ftbaseexecuteplan(ref buf2, 0, p, ref plan);
1037                    for(i=0; i<=p-1; i++)
1038                    {
1039                        ax = buf[2*i+0];
1040                        ay = buf[2*i+1];
1041                        bx = buf2[2*i+0];
1042                        by = buf2[2*i+1];
1043                        tx = ax*bx-ay*by;
1044                        ty = ax*by+ay*bx;
1045                        buf[2*i+0] = tx;
1046                        buf[2*i+1] = -ty;
1047                    }
1048                    ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
1049                    t = (double)(1)/(double)(p);
1050                    if( circular )
1051                    {
1052                       
1053                        //
1054                        // circular, add tail to head
1055                        //
1056                        r = new AP.Complex[m];
1057                        for(i=0; i<=m-1; i++)
1058                        {
1059                            r[i].x = +(t*buf[2*i+0]);
1060                            r[i].y = -(t*buf[2*i+1]);
1061                        }
1062                        for(i=m; i<=m+n-2; i++)
1063                        {
1064                            r[i-m].x = r[i-m].x+t*buf[2*i+0];
1065                            r[i-m].y = r[i-m].y-t*buf[2*i+1];
1066                        }
1067                    }
1068                    else
1069                    {
1070                       
1071                        //
1072                        // non-circular, just copy
1073                        //
1074                        r = new AP.Complex[m+n-1];
1075                        for(i=0; i<=m+n-2; i++)
1076                        {
1077                            r[i].x = +(t*buf[2*i+0]);
1078                            r[i].y = -(t*buf[2*i+1]);
1079                        }
1080                    }
1081                }
1082                return;
1083            }
1084           
1085            //
1086            // overlap-add method for
1087            // circular and non-circular convolutions.
1088            //
1089            // First part of code (separate FFTs of input blocks) is the same
1090            // for all types of convolution. Second part (overlapping outputs)
1091            // differs for different types of convolution. We just copy output
1092            // when convolution is non-circular. We wrap it around, if it is
1093            // circular.
1094            //
1095            if( alg==2 )
1096            {
1097                buf = new double[2*(q+n-1)];
1098               
1099                //
1100                // prepare R
1101                //
1102                if( circular )
1103                {
1104                    r = new AP.Complex[m];
1105                    for(i=0; i<=m-1; i++)
1106                    {
1107                        r[i] = 0;
1108                    }
1109                }
1110                else
1111                {
1112                    r = new AP.Complex[m+n-1];
1113                    for(i=0; i<=m+n-2; i++)
1114                    {
1115                        r[i] = 0;
1116                    }
1117                }
1118               
1119                //
1120                // pre-calculated FFT(B)
1121                //
1122                bbuf = new AP.Complex[q+n-1];
1123                for(i_=0; i_<=n-1;i_++)
1124                {
1125                    bbuf[i_] = b[i_];
1126                }
1127                for(j=n; j<=q+n-2; j++)
1128                {
1129                    bbuf[j] = 0;
1130                }
1131                fft.fftc1d(ref bbuf, q+n-1);
1132               
1133                //
1134                // prepare FFT plan for chunks of A
1135                //
1136                ftbase.ftbasegeneratecomplexfftplan(q+n-1, ref plan);
1137               
1138                //
1139                // main overlap-add cycle
1140                //
1141                i = 0;
1142                while( i<=m-1 )
1143                {
1144                    p = Math.Min(q, m-i);
1145                    for(j=0; j<=p-1; j++)
1146                    {
1147                        buf[2*j+0] = a[i+j].x;
1148                        buf[2*j+1] = a[i+j].y;
1149                    }
1150                    for(j=p; j<=q+n-2; j++)
1151                    {
1152                        buf[2*j+0] = 0;
1153                        buf[2*j+1] = 0;
1154                    }
1155                    ftbase.ftbaseexecuteplan(ref buf, 0, q+n-1, ref plan);
1156                    for(j=0; j<=q+n-2; j++)
1157                    {
1158                        ax = buf[2*j+0];
1159                        ay = buf[2*j+1];
1160                        bx = bbuf[j].x;
1161                        by = bbuf[j].y;
1162                        tx = ax*bx-ay*by;
1163                        ty = ax*by+ay*bx;
1164                        buf[2*j+0] = tx;
1165                        buf[2*j+1] = -ty;
1166                    }
1167                    ftbase.ftbaseexecuteplan(ref buf, 0, q+n-1, ref plan);
1168                    t = (double)(1)/((double)(q+n-1));
1169                    if( circular )
1170                    {
1171                        j1 = Math.Min(i+p+n-2, m-1)-i;
1172                        j2 = j1+1;
1173                    }
1174                    else
1175                    {
1176                        j1 = p+n-2;
1177                        j2 = j1+1;
1178                    }
1179                    for(j=0; j<=j1; j++)
1180                    {
1181                        r[i+j].x = r[i+j].x+buf[2*j+0]*t;
1182                        r[i+j].y = r[i+j].y-buf[2*j+1]*t;
1183                    }
1184                    for(j=j2; j<=p+n-2; j++)
1185                    {
1186                        r[j-j2].x = r[j-j2].x+buf[2*j+0]*t;
1187                        r[j-j2].y = r[j-j2].y-buf[2*j+1]*t;
1188                    }
1189                    i = i+p;
1190                }
1191                return;
1192            }
1193        }
1194
1195
1196        /*************************************************************************
1197        1-dimensional real convolution.
1198
1199        Extended subroutine which allows to choose convolution algorithm.
1200        Intended for internal use, ALGLIB users should call ConvR1D().
1201
1202        INPUT PARAMETERS
1203            A   -   array[0..M-1] - complex function to be transformed
1204            M   -   problem size
1205            B   -   array[0..N-1] - complex function to be transformed
1206            N   -   problem size, N<=M
1207            Alg -   algorithm type:
1208                    *-2     auto-select Q for overlap-add
1209                    *-1     auto-select algorithm and parameters
1210                    * 0     straightforward formula for small N's
1211                    * 1     general FFT-based code
1212                    * 2     overlap-add with length Q
1213            Q   -   length for overlap-add
1214
1215        OUTPUT PARAMETERS
1216            R   -   convolution: A*B. array[0..N+M-1].
1217
1218          -- ALGLIB --
1219             Copyright 21.07.2009 by Bochkanov Sergey
1220        *************************************************************************/
1221        public static void convr1dx(ref double[] a,
1222            int m,
1223            ref double[] b,
1224            int n,
1225            bool circular,
1226            int alg,
1227            int q,
1228            ref double[] r)
1229        {
1230            double v = 0;
1231            int i = 0;
1232            int j = 0;
1233            int p = 0;
1234            int ptotal = 0;
1235            int i1 = 0;
1236            int i2 = 0;
1237            int j1 = 0;
1238            int j2 = 0;
1239            double ax = 0;
1240            double ay = 0;
1241            double bx = 0;
1242            double by = 0;
1243            double tx = 0;
1244            double ty = 0;
1245            double flopcand = 0;
1246            double flopbest = 0;
1247            int algbest = 0;
1248            ftbase.ftplan plan = new ftbase.ftplan();
1249            double[] buf = new double[0];
1250            double[] buf2 = new double[0];
1251            double[] buf3 = new double[0];
1252            int i_ = 0;
1253            int i1_ = 0;
1254
1255            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DX: incorrect N or M!");
1256            System.Diagnostics.Debug.Assert(n<=m, "ConvC1DX: N<M assumption is false!");
1257           
1258            //
1259            // handle special cases
1260            //
1261            if( Math.Min(m, n)<=2 )
1262            {
1263                alg = 0;
1264            }
1265           
1266            //
1267            // Auto-select
1268            //
1269            if( alg<0 )
1270            {
1271               
1272                //
1273                // Initial candidate: straightforward implementation.
1274                //
1275                // If we want to use auto-fitted overlap-add,
1276                // flop count is initialized by large real number - to force
1277                // another algorithm selection
1278                //
1279                algbest = 0;
1280                if( alg==-1 )
1281                {
1282                    flopbest = 0.15*m*n;
1283                }
1284                else
1285                {
1286                    flopbest = AP.Math.MaxRealNumber;
1287                }
1288               
1289                //
1290                // Another candidate - generic FFT code
1291                //
1292                if( alg==-1 )
1293                {
1294                    if( circular & ftbase.ftbaseissmooth(m) & m%2==0 )
1295                    {
1296                       
1297                        //
1298                        // special code for circular convolution of a sequence with a smooth length
1299                        //
1300                        flopcand = 3*ftbase.ftbasegetflopestimate(m/2)+(double)(6*m)/(double)(2);
1301                        if( (double)(flopcand)<(double)(flopbest) )
1302                        {
1303                            algbest = 1;
1304                            flopbest = flopcand;
1305                        }
1306                    }
1307                    else
1308                    {
1309                       
1310                        //
1311                        // general cyclic/non-cyclic convolution
1312                        //
1313                        p = ftbase.ftbasefindsmootheven(m+n-1);
1314                        flopcand = 3*ftbase.ftbasegetflopestimate(p/2)+(double)(6*p)/(double)(2);
1315                        if( (double)(flopcand)<(double)(flopbest) )
1316                        {
1317                            algbest = 1;
1318                            flopbest = flopcand;
1319                        }
1320                    }
1321                }
1322               
1323                //
1324                // Another candidate - overlap-add
1325                //
1326                q = 1;
1327                ptotal = 1;
1328                while( ptotal<n )
1329                {
1330                    ptotal = ptotal*2;
1331                }
1332                while( ptotal<=m+n-1 )
1333                {
1334                    p = ptotal-n+1;
1335                    flopcand = (int)Math.Ceiling((double)(m)/(double)(p))*(2*ftbase.ftbasegetflopestimate(ptotal/2)+1*(ptotal/2));
1336                    if( (double)(flopcand)<(double)(flopbest) )
1337                    {
1338                        flopbest = flopcand;
1339                        algbest = 2;
1340                        q = p;
1341                    }
1342                    ptotal = ptotal*2;
1343                }
1344                alg = algbest;
1345                convr1dx(ref a, m, ref b, n, circular, alg, q, ref r);
1346                return;
1347            }
1348           
1349            //
1350            // straightforward formula for
1351            // circular and non-circular convolutions.
1352            //
1353            // Very simple code, no further comments needed.
1354            //
1355            if( alg==0 )
1356            {
1357               
1358                //
1359                // Special case: N=1
1360                //
1361                if( n==1 )
1362                {
1363                    r = new double[m];
1364                    v = b[0];
1365                    for(i_=0; i_<=m-1;i_++)
1366                    {
1367                        r[i_] = v*a[i_];
1368                    }
1369                    return;
1370                }
1371               
1372                //
1373                // use straightforward formula
1374                //
1375                if( circular )
1376                {
1377                   
1378                    //
1379                    // circular convolution
1380                    //
1381                    r = new double[m];
1382                    v = b[0];
1383                    for(i_=0; i_<=m-1;i_++)
1384                    {
1385                        r[i_] = v*a[i_];
1386                    }
1387                    for(i=1; i<=n-1; i++)
1388                    {
1389                        v = b[i];
1390                        i1 = 0;
1391                        i2 = i-1;
1392                        j1 = m-i;
1393                        j2 = m-1;
1394                        i1_ = (j1) - (i1);
1395                        for(i_=i1; i_<=i2;i_++)
1396                        {
1397                            r[i_] = r[i_] + v*a[i_+i1_];
1398                        }
1399                        i1 = i;
1400                        i2 = m-1;
1401                        j1 = 0;
1402                        j2 = m-i-1;
1403                        i1_ = (j1) - (i1);
1404                        for(i_=i1; i_<=i2;i_++)
1405                        {
1406                            r[i_] = r[i_] + v*a[i_+i1_];
1407                        }
1408                    }
1409                }
1410                else
1411                {
1412                   
1413                    //
1414                    // non-circular convolution
1415                    //
1416                    r = new double[m+n-1];
1417                    for(i=0; i<=m+n-2; i++)
1418                    {
1419                        r[i] = 0;
1420                    }
1421                    for(i=0; i<=n-1; i++)
1422                    {
1423                        v = b[i];
1424                        i1_ = (0) - (i);
1425                        for(i_=i; i_<=i+m-1;i_++)
1426                        {
1427                            r[i_] = r[i_] + v*a[i_+i1_];
1428                        }
1429                    }
1430                }
1431                return;
1432            }
1433           
1434            //
1435            // general FFT-based code for
1436            // circular and non-circular convolutions.
1437            //
1438            // First, if convolution is circular, we test whether M is smooth or not.
1439            // If it is smooth, we just use M-length FFT to calculate convolution.
1440            // If it is not, we calculate non-circular convolution and wrap it arount.
1441            //
1442            // If convolution is non-circular, we use zero-padding + FFT.
1443            //
1444            // We assume that M+N-1>2 - we should call small case code otherwise
1445            //
1446            if( alg==1 )
1447            {
1448                System.Diagnostics.Debug.Assert(m+n-1>2, "ConvR1DX: internal error!");
1449                if( circular & ftbase.ftbaseissmooth(m) & m%2==0 )
1450                {
1451                   
1452                    //
1453                    // special code for circular convolution with smooth even M
1454                    //
1455                    buf = new double[m];
1456                    for(i_=0; i_<=m-1;i_++)
1457                    {
1458                        buf[i_] = a[i_];
1459                    }
1460                    buf2 = new double[m];
1461                    for(i_=0; i_<=n-1;i_++)
1462                    {
1463                        buf2[i_] = b[i_];
1464                    }
1465                    for(i=n; i<=m-1; i++)
1466                    {
1467                        buf2[i] = 0;
1468                    }
1469                    buf3 = new double[m];
1470                    ftbase.ftbasegeneratecomplexfftplan(m/2, ref plan);
1471                    fft.fftr1dinternaleven(ref buf, m, ref buf3, ref plan);
1472                    fft.fftr1dinternaleven(ref buf2, m, ref buf3, ref plan);
1473                    buf[0] = buf[0]*buf2[0];
1474                    buf[1] = buf[1]*buf2[1];
1475                    for(i=1; i<=m/2-1; i++)
1476                    {
1477                        ax = buf[2*i+0];
1478                        ay = buf[2*i+1];
1479                        bx = buf2[2*i+0];
1480                        by = buf2[2*i+1];
1481                        tx = ax*bx-ay*by;
1482                        ty = ax*by+ay*bx;
1483                        buf[2*i+0] = tx;
1484                        buf[2*i+1] = ty;
1485                    }
1486                    fft.fftr1dinvinternaleven(ref buf, m, ref buf3, ref plan);
1487                    r = new double[m];
1488                    for(i_=0; i_<=m-1;i_++)
1489                    {
1490                        r[i_] = buf[i_];
1491                    }
1492                }
1493                else
1494                {
1495                   
1496                    //
1497                    // M is non-smooth or non-even, general code (circular/non-circular):
1498                    // * first part is the same for circular and non-circular
1499                    //   convolutions. zero padding, FFTs, inverse FFTs
1500                    // * second part differs:
1501                    //   * for non-circular convolution we just copy array
1502                    //   * for circular convolution we add array tail to its head
1503                    //
1504                    p = ftbase.ftbasefindsmootheven(m+n-1);
1505                    buf = new double[p];
1506                    for(i_=0; i_<=m-1;i_++)
1507                    {
1508                        buf[i_] = a[i_];
1509                    }
1510                    for(i=m; i<=p-1; i++)
1511                    {
1512                        buf[i] = 0;
1513                    }
1514                    buf2 = new double[p];
1515                    for(i_=0; i_<=n-1;i_++)
1516                    {
1517                        buf2[i_] = b[i_];
1518                    }
1519                    for(i=n; i<=p-1; i++)
1520                    {
1521                        buf2[i] = 0;
1522                    }
1523                    buf3 = new double[p];
1524                    ftbase.ftbasegeneratecomplexfftplan(p/2, ref plan);
1525                    fft.fftr1dinternaleven(ref buf, p, ref buf3, ref plan);
1526                    fft.fftr1dinternaleven(ref buf2, p, ref buf3, ref plan);
1527                    buf[0] = buf[0]*buf2[0];
1528                    buf[1] = buf[1]*buf2[1];
1529                    for(i=1; i<=p/2-1; i++)
1530                    {
1531                        ax = buf[2*i+0];
1532                        ay = buf[2*i+1];
1533                        bx = buf2[2*i+0];
1534                        by = buf2[2*i+1];
1535                        tx = ax*bx-ay*by;
1536                        ty = ax*by+ay*bx;
1537                        buf[2*i+0] = tx;
1538                        buf[2*i+1] = ty;
1539                    }
1540                    fft.fftr1dinvinternaleven(ref buf, p, ref buf3, ref plan);
1541                    if( circular )
1542                    {
1543                       
1544                        //
1545                        // circular, add tail to head
1546                        //
1547                        r = new double[m];
1548                        for(i_=0; i_<=m-1;i_++)
1549                        {
1550                            r[i_] = buf[i_];
1551                        }
1552                        if( n>=2 )
1553                        {
1554                            i1_ = (m) - (0);
1555                            for(i_=0; i_<=n-2;i_++)
1556                            {
1557                                r[i_] = r[i_] + buf[i_+i1_];
1558                            }
1559                        }
1560                    }
1561                    else
1562                    {
1563                       
1564                        //
1565                        // non-circular, just copy
1566                        //
1567                        r = new double[m+n-1];
1568                        for(i_=0; i_<=m+n-2;i_++)
1569                        {
1570                            r[i_] = buf[i_];
1571                        }
1572                    }
1573                }
1574                return;
1575            }
1576           
1577            //
1578            // overlap-add method
1579            //
1580            if( alg==2 )
1581            {
1582                System.Diagnostics.Debug.Assert((q+n-1)%2==0, "ConvR1DX: internal error!");
1583                buf = new double[q+n-1];
1584                buf2 = new double[q+n-1];
1585                buf3 = new double[q+n-1];
1586                ftbase.ftbasegeneratecomplexfftplan((q+n-1)/2, ref plan);
1587               
1588                //
1589                // prepare R
1590                //
1591                if( circular )
1592                {
1593                    r = new double[m];
1594                    for(i=0; i<=m-1; i++)
1595                    {
1596                        r[i] = 0;
1597                    }
1598                }
1599                else
1600                {
1601                    r = new double[m+n-1];
1602                    for(i=0; i<=m+n-2; i++)
1603                    {
1604                        r[i] = 0;
1605                    }
1606                }
1607               
1608                //
1609                // pre-calculated FFT(B)
1610                //
1611                for(i_=0; i_<=n-1;i_++)
1612                {
1613                    buf2[i_] = b[i_];
1614                }
1615                for(j=n; j<=q+n-2; j++)
1616                {
1617                    buf2[j] = 0;
1618                }
1619                fft.fftr1dinternaleven(ref buf2, q+n-1, ref buf3, ref plan);
1620               
1621                //
1622                // main overlap-add cycle
1623                //
1624                i = 0;
1625                while( i<=m-1 )
1626                {
1627                    p = Math.Min(q, m-i);
1628                    i1_ = (i) - (0);
1629                    for(i_=0; i_<=p-1;i_++)
1630                    {
1631                        buf[i_] = a[i_+i1_];
1632                    }
1633                    for(j=p; j<=q+n-2; j++)
1634                    {
1635                        buf[j] = 0;
1636                    }
1637                    fft.fftr1dinternaleven(ref buf, q+n-1, ref buf3, ref plan);
1638                    buf[0] = buf[0]*buf2[0];
1639                    buf[1] = buf[1]*buf2[1];
1640                    for(j=1; j<=(q+n-1)/2-1; j++)
1641                    {
1642                        ax = buf[2*j+0];
1643                        ay = buf[2*j+1];
1644                        bx = buf2[2*j+0];
1645                        by = buf2[2*j+1];
1646                        tx = ax*bx-ay*by;
1647                        ty = ax*by+ay*bx;
1648                        buf[2*j+0] = tx;
1649                        buf[2*j+1] = ty;
1650                    }
1651                    fft.fftr1dinvinternaleven(ref buf, q+n-1, ref buf3, ref plan);
1652                    if( circular )
1653                    {
1654                        j1 = Math.Min(i+p+n-2, m-1)-i;
1655                        j2 = j1+1;
1656                    }
1657                    else
1658                    {
1659                        j1 = p+n-2;
1660                        j2 = j1+1;
1661                    }
1662                    i1_ = (0) - (i);
1663                    for(i_=i; i_<=i+j1;i_++)
1664                    {
1665                        r[i_] = r[i_] + buf[i_+i1_];
1666                    }
1667                    if( p+n-2>=j2 )
1668                    {
1669                        i1_ = (j2) - (0);
1670                        for(i_=0; i_<=p+n-2-j2;i_++)
1671                        {
1672                            r[i_] = r[i_] + buf[i_+i1_];
1673                        }
1674                    }
1675                    i = i+p;
1676                }
1677                return;
1678            }
1679        }
1680    }
1681}
Note: See TracBrowser for help on using the repository browser.