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