Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/ALGLIB/conv.cs @ 2635

Last change on this file since 2635 was 2563, checked in by gkronber, 15 years ago

Updated ALGLIB to latest version. #751 (Plugin for for data-modeling with ANN (integrated into CEDMA))

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