alglib4 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +47 -0
  3. data/ext/alglib/alglib.cpp +537 -0
  4. data/ext/alglib/alglib_array_converters.cpp +86 -0
  5. data/ext/alglib/alglib_array_converters.h +15 -0
  6. data/ext/alglib/alglib_utils.cpp +10 -0
  7. data/ext/alglib/alglib_utils.h +6 -0
  8. data/ext/alglib/alglibinternal.cpp +21749 -0
  9. data/ext/alglib/alglibinternal.h +2168 -0
  10. data/ext/alglib/alglibmisc.cpp +9106 -0
  11. data/ext/alglib/alglibmisc.h +2114 -0
  12. data/ext/alglib/ap.cpp +20094 -0
  13. data/ext/alglib/ap.h +7244 -0
  14. data/ext/alglib/dataanalysis.cpp +52588 -0
  15. data/ext/alglib/dataanalysis.h +10601 -0
  16. data/ext/alglib/diffequations.cpp +1342 -0
  17. data/ext/alglib/diffequations.h +282 -0
  18. data/ext/alglib/extconf.rb +5 -0
  19. data/ext/alglib/fasttransforms.cpp +4696 -0
  20. data/ext/alglib/fasttransforms.h +1018 -0
  21. data/ext/alglib/integration.cpp +4249 -0
  22. data/ext/alglib/integration.h +869 -0
  23. data/ext/alglib/interpolation.cpp +74502 -0
  24. data/ext/alglib/interpolation.h +12264 -0
  25. data/ext/alglib/kernels_avx2.cpp +2171 -0
  26. data/ext/alglib/kernels_avx2.h +201 -0
  27. data/ext/alglib/kernels_fma.cpp +1065 -0
  28. data/ext/alglib/kernels_fma.h +137 -0
  29. data/ext/alglib/kernels_sse2.cpp +735 -0
  30. data/ext/alglib/kernels_sse2.h +100 -0
  31. data/ext/alglib/linalg.cpp +65182 -0
  32. data/ext/alglib/linalg.h +9927 -0
  33. data/ext/alglib/optimization.cpp +135331 -0
  34. data/ext/alglib/optimization.h +19235 -0
  35. data/ext/alglib/solvers.cpp +20488 -0
  36. data/ext/alglib/solvers.h +4781 -0
  37. data/ext/alglib/specialfunctions.cpp +10672 -0
  38. data/ext/alglib/specialfunctions.h +2305 -0
  39. data/ext/alglib/statistics.cpp +19791 -0
  40. data/ext/alglib/statistics.h +1359 -0
  41. data/ext/alglib/stdafx.h +2 -0
  42. data/gpl2.txt +339 -0
  43. data/gpl3.txt +674 -0
  44. data/lib/alglib/version.rb +3 -0
  45. data/lib/alglib.rb +4 -0
  46. metadata +101 -0
@@ -0,0 +1,4696 @@
1
+ /*************************************************************************
2
+ ALGLIB 4.04.0 (source code generated 2024-12-21)
3
+ Copyright (c) Sergey Bochkanov (ALGLIB project).
4
+
5
+ >>> SOURCE LICENSE >>>
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation (www.fsf.org); either version 2 of the
9
+ License, or (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ A copy of the GNU General Public License is available at
17
+ http://www.fsf.org/licensing/licenses
18
+ >>> END OF LICENSE >>>
19
+ *************************************************************************/
20
+ #ifdef _MSC_VER
21
+ #define _CRT_SECURE_NO_WARNINGS
22
+ #endif
23
+ #include "stdafx.h"
24
+ #include "fasttransforms.h"
25
+
26
+ // disable some irrelevant warnings
27
+ #if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS)
28
+ #pragma warning(disable:4100)
29
+ #pragma warning(disable:4127)
30
+ #pragma warning(disable:4611)
31
+ #pragma warning(disable:4702)
32
+ #pragma warning(disable:4996)
33
+ #endif
34
+
35
+ /////////////////////////////////////////////////////////////////////////
36
+ //
37
+ // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE
38
+ //
39
+ /////////////////////////////////////////////////////////////////////////
40
+ namespace alglib
41
+ {
42
+
43
+
44
+ #if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD)
45
+ /*************************************************************************
46
+ 1-dimensional complex FFT.
47
+
48
+ Array size N may be arbitrary number (composite or prime). Composite N's
49
+ are handled with cache-oblivious variation of a Cooley-Tukey algorithm.
50
+ Small prime-factors are transformed using hard coded codelets (similar to
51
+ FFTW codelets, but without low-level optimization), large prime-factors
52
+ are handled with Bluestein's algorithm.
53
+
54
+ Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only),
55
+ most fast for powers of 2. When N have prime factors larger than these,
56
+ but orders of magnitude smaller than N, computations will be about 4 times
57
+ slower than for nearby highly composite N's. When N itself is prime, speed
58
+ will be 6 times lower.
59
+
60
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
61
+
62
+ INPUT PARAMETERS
63
+ A - array[0..N-1] - complex function to be transformed
64
+ N - problem size
65
+
66
+ OUTPUT PARAMETERS
67
+ A - DFT of a input array, array[0..N-1]
68
+ A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
69
+
70
+
71
+ -- ALGLIB --
72
+ Copyright 29.05.2009 by Bochkanov Sergey
73
+ *************************************************************************/
74
+ void fftc1d(complex_1d_array &a, const ae_int_t n, const xparams _xparams)
75
+ {
76
+ jmp_buf _break_jump;
77
+ alglib_impl::ae_state _alglib_env_state;
78
+ alglib_impl::ae_state_init(&_alglib_env_state);
79
+ if( setjmp(_break_jump) )
80
+ {
81
+ #if !defined(AE_NO_EXCEPTIONS)
82
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
83
+ #else
84
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
85
+ return;
86
+ #endif
87
+ }
88
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
89
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
90
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
91
+ alglib_impl::fftc1d(a.c_ptr(), n, &_alglib_env_state);
92
+ alglib_impl::ae_state_clear(&_alglib_env_state);
93
+ return;
94
+ }
95
+
96
+ /*************************************************************************
97
+ 1-dimensional complex FFT.
98
+
99
+ Array size N may be arbitrary number (composite or prime). Composite N's
100
+ are handled with cache-oblivious variation of a Cooley-Tukey algorithm.
101
+ Small prime-factors are transformed using hard coded codelets (similar to
102
+ FFTW codelets, but without low-level optimization), large prime-factors
103
+ are handled with Bluestein's algorithm.
104
+
105
+ Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only),
106
+ most fast for powers of 2. When N have prime factors larger than these,
107
+ but orders of magnitude smaller than N, computations will be about 4 times
108
+ slower than for nearby highly composite N's. When N itself is prime, speed
109
+ will be 6 times lower.
110
+
111
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
112
+
113
+ INPUT PARAMETERS
114
+ A - array[0..N-1] - complex function to be transformed
115
+ N - problem size
116
+
117
+ OUTPUT PARAMETERS
118
+ A - DFT of a input array, array[0..N-1]
119
+ A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
120
+
121
+
122
+ -- ALGLIB --
123
+ Copyright 29.05.2009 by Bochkanov Sergey
124
+ *************************************************************************/
125
+ #if !defined(AE_NO_EXCEPTIONS)
126
+ void fftc1d(complex_1d_array &a, const xparams _xparams)
127
+ {
128
+ jmp_buf _break_jump;
129
+ alglib_impl::ae_state _alglib_env_state;
130
+ ae_int_t n;
131
+
132
+ n = a.length();
133
+ alglib_impl::ae_state_init(&_alglib_env_state);
134
+ if( setjmp(_break_jump) )
135
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
136
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
137
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
138
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
139
+ alglib_impl::fftc1d(a.c_ptr(), n, &_alglib_env_state);
140
+
141
+ alglib_impl::ae_state_clear(&_alglib_env_state);
142
+ return;
143
+ }
144
+ #endif
145
+
146
+ /*************************************************************************
147
+ 1-dimensional complex inverse FFT.
148
+
149
+ Array size N may be arbitrary number (composite or prime). Algorithm has
150
+ O(N*logN) complexity for any N (composite or prime).
151
+
152
+ See FFTC1D() description for more information about algorithm performance.
153
+
154
+ INPUT PARAMETERS
155
+ A - array[0..N-1] - complex array to be transformed
156
+ N - problem size
157
+
158
+ OUTPUT PARAMETERS
159
+ A - inverse DFT of a input array, array[0..N-1]
160
+ A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
161
+
162
+
163
+ -- ALGLIB --
164
+ Copyright 29.05.2009 by Bochkanov Sergey
165
+ *************************************************************************/
166
+ void fftc1dinv(complex_1d_array &a, const ae_int_t n, const xparams _xparams)
167
+ {
168
+ jmp_buf _break_jump;
169
+ alglib_impl::ae_state _alglib_env_state;
170
+ alglib_impl::ae_state_init(&_alglib_env_state);
171
+ if( setjmp(_break_jump) )
172
+ {
173
+ #if !defined(AE_NO_EXCEPTIONS)
174
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
175
+ #else
176
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
177
+ return;
178
+ #endif
179
+ }
180
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
181
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
182
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
183
+ alglib_impl::fftc1dinv(a.c_ptr(), n, &_alglib_env_state);
184
+ alglib_impl::ae_state_clear(&_alglib_env_state);
185
+ return;
186
+ }
187
+
188
+ /*************************************************************************
189
+ 1-dimensional complex inverse FFT.
190
+
191
+ Array size N may be arbitrary number (composite or prime). Algorithm has
192
+ O(N*logN) complexity for any N (composite or prime).
193
+
194
+ See FFTC1D() description for more information about algorithm performance.
195
+
196
+ INPUT PARAMETERS
197
+ A - array[0..N-1] - complex array to be transformed
198
+ N - problem size
199
+
200
+ OUTPUT PARAMETERS
201
+ A - inverse DFT of a input array, array[0..N-1]
202
+ A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
203
+
204
+
205
+ -- ALGLIB --
206
+ Copyright 29.05.2009 by Bochkanov Sergey
207
+ *************************************************************************/
208
+ #if !defined(AE_NO_EXCEPTIONS)
209
+ void fftc1dinv(complex_1d_array &a, const xparams _xparams)
210
+ {
211
+ jmp_buf _break_jump;
212
+ alglib_impl::ae_state _alglib_env_state;
213
+ ae_int_t n;
214
+
215
+ n = a.length();
216
+ alglib_impl::ae_state_init(&_alglib_env_state);
217
+ if( setjmp(_break_jump) )
218
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
219
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
220
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
221
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
222
+ alglib_impl::fftc1dinv(a.c_ptr(), n, &_alglib_env_state);
223
+
224
+ alglib_impl::ae_state_clear(&_alglib_env_state);
225
+ return;
226
+ }
227
+ #endif
228
+
229
+ /*************************************************************************
230
+ 1-dimensional real FFT.
231
+
232
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
233
+
234
+ INPUT PARAMETERS
235
+ A - array[0..N-1] - real function to be transformed
236
+ N - problem size
237
+
238
+ OUTPUT PARAMETERS
239
+ F - DFT of a input array, array[0..N-1]
240
+ F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
241
+
242
+ NOTE: there is a buffered version of this function, FFTR1DBuf(), which
243
+ reuses memory previously allocated for A as much as possible.
244
+
245
+ NOTE:
246
+ F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half
247
+ of array is usually needed. But for convinience subroutine returns full
248
+ complex array (with frequencies above N/2), so its result may be used by
249
+ other FFT-related subroutines.
250
+
251
+
252
+ -- ALGLIB --
253
+ Copyright 01.06.2009 by Bochkanov Sergey
254
+ *************************************************************************/
255
+ void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams)
256
+ {
257
+ jmp_buf _break_jump;
258
+ alglib_impl::ae_state _alglib_env_state;
259
+ alglib_impl::ae_state_init(&_alglib_env_state);
260
+ if( setjmp(_break_jump) )
261
+ {
262
+ #if !defined(AE_NO_EXCEPTIONS)
263
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
264
+ #else
265
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
266
+ return;
267
+ #endif
268
+ }
269
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
270
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
271
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
272
+ alglib_impl::fftr1d(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
273
+ alglib_impl::ae_state_clear(&_alglib_env_state);
274
+ return;
275
+ }
276
+
277
+ /*************************************************************************
278
+ 1-dimensional real FFT.
279
+
280
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
281
+
282
+ INPUT PARAMETERS
283
+ A - array[0..N-1] - real function to be transformed
284
+ N - problem size
285
+
286
+ OUTPUT PARAMETERS
287
+ F - DFT of a input array, array[0..N-1]
288
+ F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
289
+
290
+ NOTE: there is a buffered version of this function, FFTR1DBuf(), which
291
+ reuses memory previously allocated for A as much as possible.
292
+
293
+ NOTE:
294
+ F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half
295
+ of array is usually needed. But for convinience subroutine returns full
296
+ complex array (with frequencies above N/2), so its result may be used by
297
+ other FFT-related subroutines.
298
+
299
+
300
+ -- ALGLIB --
301
+ Copyright 01.06.2009 by Bochkanov Sergey
302
+ *************************************************************************/
303
+ #if !defined(AE_NO_EXCEPTIONS)
304
+ void fftr1d(const real_1d_array &a, complex_1d_array &f, const xparams _xparams)
305
+ {
306
+ jmp_buf _break_jump;
307
+ alglib_impl::ae_state _alglib_env_state;
308
+ ae_int_t n;
309
+
310
+ n = a.length();
311
+ alglib_impl::ae_state_init(&_alglib_env_state);
312
+ if( setjmp(_break_jump) )
313
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
314
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
315
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
316
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
317
+ alglib_impl::fftr1d(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
318
+
319
+ alglib_impl::ae_state_clear(&_alglib_env_state);
320
+ return;
321
+ }
322
+ #endif
323
+
324
+ /*************************************************************************
325
+ 1-dimensional real FFT, a buffered function which does not reallocate F[]
326
+ if its length is enough to store the result (i.e. it reuses previously
327
+ allocated memory as much as possible).
328
+
329
+ -- ALGLIB --
330
+ Copyright 01.06.2009 by Bochkanov Sergey
331
+ *************************************************************************/
332
+ void fftr1dbuf(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams)
333
+ {
334
+ jmp_buf _break_jump;
335
+ alglib_impl::ae_state _alglib_env_state;
336
+ alglib_impl::ae_state_init(&_alglib_env_state);
337
+ if( setjmp(_break_jump) )
338
+ {
339
+ #if !defined(AE_NO_EXCEPTIONS)
340
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
341
+ #else
342
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
343
+ return;
344
+ #endif
345
+ }
346
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
347
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
348
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
349
+ alglib_impl::fftr1dbuf(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
350
+ alglib_impl::ae_state_clear(&_alglib_env_state);
351
+ return;
352
+ }
353
+
354
+ /*************************************************************************
355
+ 1-dimensional real FFT, a buffered function which does not reallocate F[]
356
+ if its length is enough to store the result (i.e. it reuses previously
357
+ allocated memory as much as possible).
358
+
359
+ -- ALGLIB --
360
+ Copyright 01.06.2009 by Bochkanov Sergey
361
+ *************************************************************************/
362
+ #if !defined(AE_NO_EXCEPTIONS)
363
+ void fftr1dbuf(const real_1d_array &a, complex_1d_array &f, const xparams _xparams)
364
+ {
365
+ jmp_buf _break_jump;
366
+ alglib_impl::ae_state _alglib_env_state;
367
+ ae_int_t n;
368
+
369
+ n = a.length();
370
+ alglib_impl::ae_state_init(&_alglib_env_state);
371
+ if( setjmp(_break_jump) )
372
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
373
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
374
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
375
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
376
+ alglib_impl::fftr1dbuf(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
377
+
378
+ alglib_impl::ae_state_clear(&_alglib_env_state);
379
+ return;
380
+ }
381
+ #endif
382
+
383
+ /*************************************************************************
384
+ 1-dimensional real inverse FFT.
385
+
386
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
387
+
388
+ INPUT PARAMETERS
389
+ F - array[0..floor(N/2)] - frequencies from forward real FFT
390
+ N - problem size
391
+
392
+ OUTPUT PARAMETERS
393
+ A - inverse DFT of a input array, array[0..N-1]
394
+
395
+ NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which
396
+ reuses memory previously allocated for A as much as possible.
397
+
398
+ NOTE:
399
+ F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one
400
+ half of frequencies array is needed - elements from 0 to floor(N/2). F[0]
401
+ is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then
402
+ F[floor(N/2)] has no special properties.
403
+
404
+ Relying on properties noted above, FFTR1DInv subroutine uses only elements
405
+ from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case
406
+ N is even it ignores imaginary part of F[floor(N/2)] too.
407
+
408
+ When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
409
+ - you can pass either either frequencies array with N elements or reduced
410
+ array with roughly N/2 elements - subroutine will successfully transform
411
+ both.
412
+
413
+ If you call this function using reduced arguments list - "FFTR1DInv(F,A)"
414
+ - you must pass FULL array with N elements (although higher N/2 are still
415
+ not used) because array size is used to automatically determine FFT length
416
+
417
+ -- ALGLIB --
418
+ Copyright 01.06.2009 by Bochkanov Sergey
419
+ *************************************************************************/
420
+ void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams)
421
+ {
422
+ jmp_buf _break_jump;
423
+ alglib_impl::ae_state _alglib_env_state;
424
+ alglib_impl::ae_state_init(&_alglib_env_state);
425
+ if( setjmp(_break_jump) )
426
+ {
427
+ #if !defined(AE_NO_EXCEPTIONS)
428
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
429
+ #else
430
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
431
+ return;
432
+ #endif
433
+ }
434
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
435
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
436
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
437
+ alglib_impl::fftr1dinv(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
438
+ alglib_impl::ae_state_clear(&_alglib_env_state);
439
+ return;
440
+ }
441
+
442
+ /*************************************************************************
443
+ 1-dimensional real inverse FFT.
444
+
445
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
446
+
447
+ INPUT PARAMETERS
448
+ F - array[0..floor(N/2)] - frequencies from forward real FFT
449
+ N - problem size
450
+
451
+ OUTPUT PARAMETERS
452
+ A - inverse DFT of a input array, array[0..N-1]
453
+
454
+ NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which
455
+ reuses memory previously allocated for A as much as possible.
456
+
457
+ NOTE:
458
+ F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one
459
+ half of frequencies array is needed - elements from 0 to floor(N/2). F[0]
460
+ is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then
461
+ F[floor(N/2)] has no special properties.
462
+
463
+ Relying on properties noted above, FFTR1DInv subroutine uses only elements
464
+ from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case
465
+ N is even it ignores imaginary part of F[floor(N/2)] too.
466
+
467
+ When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
468
+ - you can pass either either frequencies array with N elements or reduced
469
+ array with roughly N/2 elements - subroutine will successfully transform
470
+ both.
471
+
472
+ If you call this function using reduced arguments list - "FFTR1DInv(F,A)"
473
+ - you must pass FULL array with N elements (although higher N/2 are still
474
+ not used) because array size is used to automatically determine FFT length
475
+
476
+ -- ALGLIB --
477
+ Copyright 01.06.2009 by Bochkanov Sergey
478
+ *************************************************************************/
479
+ #if !defined(AE_NO_EXCEPTIONS)
480
+ void fftr1dinv(const complex_1d_array &f, real_1d_array &a, const xparams _xparams)
481
+ {
482
+ jmp_buf _break_jump;
483
+ alglib_impl::ae_state _alglib_env_state;
484
+ ae_int_t n;
485
+
486
+ n = f.length();
487
+ alglib_impl::ae_state_init(&_alglib_env_state);
488
+ if( setjmp(_break_jump) )
489
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
490
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
491
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
492
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
493
+ alglib_impl::fftr1dinv(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
494
+
495
+ alglib_impl::ae_state_clear(&_alglib_env_state);
496
+ return;
497
+ }
498
+ #endif
499
+
500
+ /*************************************************************************
501
+ 1-dimensional real inverse FFT, buffered version, which does not reallocate
502
+ A[] if its length is enough to store the result (i.e. it reuses previously
503
+ allocated memory as much as possible).
504
+
505
+ -- ALGLIB --
506
+ Copyright 01.06.2009 by Bochkanov Sergey
507
+ *************************************************************************/
508
+ void fftr1dinvbuf(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams)
509
+ {
510
+ jmp_buf _break_jump;
511
+ alglib_impl::ae_state _alglib_env_state;
512
+ alglib_impl::ae_state_init(&_alglib_env_state);
513
+ if( setjmp(_break_jump) )
514
+ {
515
+ #if !defined(AE_NO_EXCEPTIONS)
516
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
517
+ #else
518
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
519
+ return;
520
+ #endif
521
+ }
522
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
523
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
524
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
525
+ alglib_impl::fftr1dinvbuf(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
526
+ alglib_impl::ae_state_clear(&_alglib_env_state);
527
+ return;
528
+ }
529
+
530
+ /*************************************************************************
531
+ 1-dimensional real inverse FFT, buffered version, which does not reallocate
532
+ A[] if its length is enough to store the result (i.e. it reuses previously
533
+ allocated memory as much as possible).
534
+
535
+ -- ALGLIB --
536
+ Copyright 01.06.2009 by Bochkanov Sergey
537
+ *************************************************************************/
538
+ #if !defined(AE_NO_EXCEPTIONS)
539
+ void fftr1dinvbuf(const complex_1d_array &f, real_1d_array &a, const xparams _xparams)
540
+ {
541
+ jmp_buf _break_jump;
542
+ alglib_impl::ae_state _alglib_env_state;
543
+ ae_int_t n;
544
+
545
+ n = f.length();
546
+ alglib_impl::ae_state_init(&_alglib_env_state);
547
+ if( setjmp(_break_jump) )
548
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
549
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
550
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
551
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
552
+ alglib_impl::fftr1dinvbuf(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
553
+
554
+ alglib_impl::ae_state_clear(&_alglib_env_state);
555
+ return;
556
+ }
557
+ #endif
558
+ #endif
559
+
560
+ #if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD)
561
+ /*************************************************************************
562
+ 1-dimensional Fast Hartley Transform.
563
+
564
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
565
+
566
+ INPUT PARAMETERS
567
+ A - array[0..N-1] - real function to be transformed
568
+ N - problem size
569
+
570
+ OUTPUT PARAMETERS
571
+ A - FHT of a input array, array[0..N-1],
572
+ A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)
573
+
574
+
575
+ -- ALGLIB --
576
+ Copyright 04.06.2009 by Bochkanov Sergey
577
+ *************************************************************************/
578
+ void fhtr1d(real_1d_array &a, const ae_int_t n, const xparams _xparams)
579
+ {
580
+ jmp_buf _break_jump;
581
+ alglib_impl::ae_state _alglib_env_state;
582
+ alglib_impl::ae_state_init(&_alglib_env_state);
583
+ if( setjmp(_break_jump) )
584
+ {
585
+ #if !defined(AE_NO_EXCEPTIONS)
586
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
587
+ #else
588
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
589
+ return;
590
+ #endif
591
+ }
592
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
593
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
594
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
595
+ alglib_impl::fhtr1d(a.c_ptr(), n, &_alglib_env_state);
596
+ alglib_impl::ae_state_clear(&_alglib_env_state);
597
+ return;
598
+ }
599
+
600
+ /*************************************************************************
601
+ 1-dimensional inverse FHT.
602
+
603
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
604
+
605
+ INPUT PARAMETERS
606
+ A - array[0..N-1] - complex array to be transformed
607
+ N - problem size
608
+
609
+ OUTPUT PARAMETERS
610
+ A - inverse FHT of a input array, array[0..N-1]
611
+
612
+
613
+ -- ALGLIB --
614
+ Copyright 29.05.2009 by Bochkanov Sergey
615
+ *************************************************************************/
616
+ void fhtr1dinv(real_1d_array &a, const ae_int_t n, const xparams _xparams)
617
+ {
618
+ jmp_buf _break_jump;
619
+ alglib_impl::ae_state _alglib_env_state;
620
+ alglib_impl::ae_state_init(&_alglib_env_state);
621
+ if( setjmp(_break_jump) )
622
+ {
623
+ #if !defined(AE_NO_EXCEPTIONS)
624
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
625
+ #else
626
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
627
+ return;
628
+ #endif
629
+ }
630
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
631
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
632
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
633
+ alglib_impl::fhtr1dinv(a.c_ptr(), n, &_alglib_env_state);
634
+ alglib_impl::ae_state_clear(&_alglib_env_state);
635
+ return;
636
+ }
637
+ #endif
638
+
639
+ #if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD)
640
+ /*************************************************************************
641
+ 1-dimensional complex convolution.
642
+
643
+ For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
644
+ choose between three implementations: straightforward O(M*N) formula for
645
+ very small N (or M), overlap-add algorithm for cases where max(M,N) is
646
+ significantly larger than min(M,N), but O(M*N) algorithm is too slow, and
647
+ general FFT-based formula for cases where two previous algorithms are too
648
+ slow.
649
+
650
+ Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.
651
+
652
+ INPUT PARAMETERS
653
+ A - array[M] - complex function to be transformed
654
+ M - problem size
655
+ B - array[N] - complex function to be transformed
656
+ N - problem size
657
+
658
+ OUTPUT PARAMETERS
659
+ R - convolution: A*B. array[N+M-1]
660
+
661
+ NOTE:
662
+ It is assumed that A is zero at T<0, B is zero too. If one or both
663
+ functions have non-zero values at negative T's, you can still use this
664
+ subroutine - just shift its result correspondingly.
665
+
666
+ NOTE: there is a buffered version of this function, ConvC1DBuf(), which
667
+ can reuse space previously allocated in its output parameter R.
668
+
669
+ -- ALGLIB --
670
+ Copyright 21.07.2009 by Bochkanov Sergey
671
+ *************************************************************************/
672
+ void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
673
+ {
674
+ jmp_buf _break_jump;
675
+ alglib_impl::ae_state _alglib_env_state;
676
+ alglib_impl::ae_state_init(&_alglib_env_state);
677
+ if( setjmp(_break_jump) )
678
+ {
679
+ #if !defined(AE_NO_EXCEPTIONS)
680
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
681
+ #else
682
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
683
+ return;
684
+ #endif
685
+ }
686
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
687
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
688
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
689
+ alglib_impl::convc1d(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
690
+ alglib_impl::ae_state_clear(&_alglib_env_state);
691
+ return;
692
+ }
693
+
694
+ /*************************************************************************
695
+ 1-dimensional complex convolution, buffered version of ConvC1DBuf(), which
696
+ does not reallocate R[] if its length is enough to store the result (i.e.
697
+ it reuses previously allocated memory as much as possible).
698
+
699
+ -- ALGLIB --
700
+ Copyright 30.11.2023 by Bochkanov Sergey
701
+ *************************************************************************/
702
+ void convc1dbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
703
+ {
704
+ jmp_buf _break_jump;
705
+ alglib_impl::ae_state _alglib_env_state;
706
+ alglib_impl::ae_state_init(&_alglib_env_state);
707
+ if( setjmp(_break_jump) )
708
+ {
709
+ #if !defined(AE_NO_EXCEPTIONS)
710
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
711
+ #else
712
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
713
+ return;
714
+ #endif
715
+ }
716
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
717
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
718
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
719
+ alglib_impl::convc1dbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
720
+ alglib_impl::ae_state_clear(&_alglib_env_state);
721
+ return;
722
+ }
723
+
724
+ /*************************************************************************
725
+ 1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
726
+
727
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
728
+
729
+ INPUT PARAMETERS
730
+ A - array[0..M-1] - convolved signal, A = conv(R, B)
731
+ M - convolved signal length
732
+ B - array[0..N-1] - response
733
+ N - response length, N<=M
734
+
735
+ OUTPUT PARAMETERS
736
+ R - deconvolved signal. array[0..M-N].
737
+
738
+ NOTE:
739
+ deconvolution is unstable process and may result in division by zero
740
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
741
+
742
+ NOTE:
743
+ It is assumed that A is zero at T<0, B is zero too. If one or both
744
+ functions have non-zero values at negative T's, you can still use this
745
+ subroutine - just shift its result correspondingly.
746
+
747
+ NOTE: there is a buffered version of this function, ConvC1DInvBuf(),
748
+ which can reuse space previously allocated in its output parameter R
749
+
750
+ -- ALGLIB --
751
+ Copyright 21.07.2009 by Bochkanov Sergey
752
+ *************************************************************************/
753
+ void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
754
+ {
755
+ jmp_buf _break_jump;
756
+ alglib_impl::ae_state _alglib_env_state;
757
+ alglib_impl::ae_state_init(&_alglib_env_state);
758
+ if( setjmp(_break_jump) )
759
+ {
760
+ #if !defined(AE_NO_EXCEPTIONS)
761
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
762
+ #else
763
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
764
+ return;
765
+ #endif
766
+ }
767
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
768
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
769
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
770
+ alglib_impl::convc1dinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
771
+ alglib_impl::ae_state_clear(&_alglib_env_state);
772
+ return;
773
+ }
774
+
775
+ /*************************************************************************
776
+ 1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
777
+
778
+ A buffered version, which does not reallocate R[] if its length is enough
779
+ to store the result (i.e. it reuses previously allocated memory as much as
780
+ possible).
781
+
782
+ -- ALGLIB --
783
+ Copyright 30.11.2023 by Bochkanov Sergey
784
+ *************************************************************************/
785
+ void convc1dinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
786
+ {
787
+ jmp_buf _break_jump;
788
+ alglib_impl::ae_state _alglib_env_state;
789
+ alglib_impl::ae_state_init(&_alglib_env_state);
790
+ if( setjmp(_break_jump) )
791
+ {
792
+ #if !defined(AE_NO_EXCEPTIONS)
793
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
794
+ #else
795
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
796
+ return;
797
+ #endif
798
+ }
799
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
800
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
801
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
802
+ alglib_impl::convc1dinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
803
+ alglib_impl::ae_state_clear(&_alglib_env_state);
804
+ return;
805
+ }
806
+
807
+ /*************************************************************************
808
+ 1-dimensional circular complex convolution.
809
+
810
+ For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
811
+ complexity for any M/N.
812
+
813
+ IMPORTANT: normal convolution is commutative, i.e. it is symmetric -
814
+ conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a
815
+ signal, periodic function, and another - R - is a response, non-periodic
816
+ function with limited length.
817
+
818
+ INPUT PARAMETERS
819
+ S - array[M] - complex periodic signal
820
+ M - problem size
821
+ B - array[N] - complex non-periodic response
822
+ N - problem size
823
+
824
+ OUTPUT PARAMETERS
825
+ R - convolution: A*B. array[M].
826
+
827
+ NOTE:
828
+ It is assumed that B is zero at T<0. If it has non-zero values at
829
+ negative T's, you can still use this subroutine - just shift its result
830
+ correspondingly.
831
+
832
+ NOTE: there is a buffered version of this function, ConvC1DCircularBuf(),
833
+ which can reuse space previously allocated in its output parameter R.
834
+
835
+ -- ALGLIB --
836
+ Copyright 21.07.2009 by Bochkanov Sergey
837
+ *************************************************************************/
838
+ void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams)
839
+ {
840
+ jmp_buf _break_jump;
841
+ alglib_impl::ae_state _alglib_env_state;
842
+ alglib_impl::ae_state_init(&_alglib_env_state);
843
+ if( setjmp(_break_jump) )
844
+ {
845
+ #if !defined(AE_NO_EXCEPTIONS)
846
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
847
+ #else
848
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
849
+ return;
850
+ #endif
851
+ }
852
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
853
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
854
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
855
+ alglib_impl::convc1dcircular(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
856
+ alglib_impl::ae_state_clear(&_alglib_env_state);
857
+ return;
858
+ }
859
+
860
+ /*************************************************************************
861
+ 1-dimensional circular complex convolution.
862
+
863
+ Buffered version of ConvC1DCircular(), which does not reallocate C[] if
864
+ its length is enough to store the result (i.e. it reuses previously
865
+ allocated memory as much as possible).
866
+
867
+ -- ALGLIB --
868
+ Copyright 30.11.2023 by Bochkanov Sergey
869
+ *************************************************************************/
870
+ void convc1dcircularbuf(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams)
871
+ {
872
+ jmp_buf _break_jump;
873
+ alglib_impl::ae_state _alglib_env_state;
874
+ alglib_impl::ae_state_init(&_alglib_env_state);
875
+ if( setjmp(_break_jump) )
876
+ {
877
+ #if !defined(AE_NO_EXCEPTIONS)
878
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
879
+ #else
880
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
881
+ return;
882
+ #endif
883
+ }
884
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
885
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
886
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
887
+ alglib_impl::convc1dcircularbuf(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
888
+ alglib_impl::ae_state_clear(&_alglib_env_state);
889
+ return;
890
+ }
891
+
892
+ /*************************************************************************
893
+ 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
894
+
895
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
896
+
897
+ INPUT PARAMETERS
898
+ A - array[0..M-1] - convolved periodic signal, A = conv(R, B)
899
+ M - convolved signal length
900
+ B - array[0..N-1] - non-periodic response
901
+ N - response length
902
+
903
+ OUTPUT PARAMETERS
904
+ R - deconvolved signal. array[0..M-1].
905
+
906
+ NOTE:
907
+ deconvolution is unstable process and may result in division by zero
908
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
909
+
910
+ NOTE:
911
+ It is assumed that B is zero at T<0. If it has non-zero values at
912
+ negative T's, you can still use this subroutine - just shift its result
913
+ correspondingly.
914
+
915
+ NOTE: there is a buffered version of this function, ConvC1DCircularInvBuf(),
916
+ which can reuse space previously allocated in its output parameter R.
917
+
918
+ -- ALGLIB --
919
+ Copyright 21.07.2009 by Bochkanov Sergey
920
+ *************************************************************************/
921
+ void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
922
+ {
923
+ jmp_buf _break_jump;
924
+ alglib_impl::ae_state _alglib_env_state;
925
+ alglib_impl::ae_state_init(&_alglib_env_state);
926
+ if( setjmp(_break_jump) )
927
+ {
928
+ #if !defined(AE_NO_EXCEPTIONS)
929
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
930
+ #else
931
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
932
+ return;
933
+ #endif
934
+ }
935
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
936
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
937
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
938
+ alglib_impl::convc1dcircularinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
939
+ alglib_impl::ae_state_clear(&_alglib_env_state);
940
+ return;
941
+ }
942
+
943
+ /*************************************************************************
944
+ 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
945
+
946
+ Buffered version of ConvC1DCircularInv(), which does not reallocate R[] if
947
+ its length is enough to store the result (i.e. it reuses previously
948
+ allocated memory as much as possible).
949
+
950
+ -- ALGLIB --
951
+ Copyright 30.11.2023 by Bochkanov Sergey
952
+ *************************************************************************/
953
+ void convc1dcircularinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
954
+ {
955
+ jmp_buf _break_jump;
956
+ alglib_impl::ae_state _alglib_env_state;
957
+ alglib_impl::ae_state_init(&_alglib_env_state);
958
+ if( setjmp(_break_jump) )
959
+ {
960
+ #if !defined(AE_NO_EXCEPTIONS)
961
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
962
+ #else
963
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
964
+ return;
965
+ #endif
966
+ }
967
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
968
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
969
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
970
+ alglib_impl::convc1dcircularinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
971
+ alglib_impl::ae_state_clear(&_alglib_env_state);
972
+ return;
973
+ }
974
+
975
+ /*************************************************************************
976
+ 1-dimensional real convolution.
977
+
978
+ Analogous to ConvC1D(), see ConvC1D() comments for more details.
979
+
980
+ INPUT PARAMETERS
981
+ A - array[0..M-1] - real function to be transformed
982
+ M - problem size
983
+ B - array[0..N-1] - real function to be transformed
984
+ N - problem size
985
+
986
+ OUTPUT PARAMETERS
987
+ R - convolution: A*B. array[0..N+M-2].
988
+
989
+ NOTE:
990
+ It is assumed that A is zero at T<0, B is zero too. If one or both
991
+ functions have non-zero values at negative T's, you can still use this
992
+ subroutine - just shift its result correspondingly.
993
+
994
+ NOTE: there is a buffered version of this function, ConvR1DBuf(),
995
+ which can reuse space previously allocated in its output parameter R.
996
+
997
+
998
+ -- ALGLIB --
999
+ Copyright 21.07.2009 by Bochkanov Sergey
1000
+ *************************************************************************/
1001
+ 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, const xparams _xparams)
1002
+ {
1003
+ jmp_buf _break_jump;
1004
+ alglib_impl::ae_state _alglib_env_state;
1005
+ alglib_impl::ae_state_init(&_alglib_env_state);
1006
+ if( setjmp(_break_jump) )
1007
+ {
1008
+ #if !defined(AE_NO_EXCEPTIONS)
1009
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1010
+ #else
1011
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1012
+ return;
1013
+ #endif
1014
+ }
1015
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1016
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1017
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1018
+ alglib_impl::convr1d(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
1019
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1020
+ return;
1021
+ }
1022
+
1023
+ /*************************************************************************
1024
+ 1-dimensional real convolution.
1025
+
1026
+ Buffered version of ConvR1D(), which does not reallocate R[] if its length
1027
+ is enough to store the result (i.e. it reuses previously allocated memory
1028
+ as much as possible).
1029
+
1030
+ -- ALGLIB --
1031
+ Copyright 30.11.2023 by Bochkanov Sergey
1032
+ *************************************************************************/
1033
+ void convr1dbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
1034
+ {
1035
+ jmp_buf _break_jump;
1036
+ alglib_impl::ae_state _alglib_env_state;
1037
+ alglib_impl::ae_state_init(&_alglib_env_state);
1038
+ if( setjmp(_break_jump) )
1039
+ {
1040
+ #if !defined(AE_NO_EXCEPTIONS)
1041
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1042
+ #else
1043
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1044
+ return;
1045
+ #endif
1046
+ }
1047
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1048
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1049
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1050
+ alglib_impl::convr1dbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
1051
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1052
+ return;
1053
+ }
1054
+
1055
+ /*************************************************************************
1056
+ 1-dimensional real deconvolution (inverse of ConvC1D()).
1057
+
1058
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
1059
+
1060
+ INPUT PARAMETERS
1061
+ A - array[0..M-1] - convolved signal, A = conv(R, B)
1062
+ M - convolved signal length
1063
+ B - array[0..N-1] - response
1064
+ N - response length, N<=M
1065
+
1066
+ OUTPUT PARAMETERS
1067
+ R - deconvolved signal. array[0..M-N].
1068
+
1069
+ NOTE:
1070
+ deconvolution is unstable process and may result in division by zero
1071
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
1072
+
1073
+ NOTE:
1074
+ It is assumed that A is zero at T<0, B is zero too. If one or both
1075
+ functions have non-zero values at negative T's, you can still use this
1076
+ subroutine - just shift its result correspondingly.
1077
+
1078
+ NOTE: there is a buffered version of this function, ConvR1DInvBuf(),
1079
+ which can reuse space previously allocated in its output parameter R.
1080
+
1081
+ -- ALGLIB --
1082
+ Copyright 21.07.2009 by Bochkanov Sergey
1083
+ *************************************************************************/
1084
+ 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, const xparams _xparams)
1085
+ {
1086
+ jmp_buf _break_jump;
1087
+ alglib_impl::ae_state _alglib_env_state;
1088
+ alglib_impl::ae_state_init(&_alglib_env_state);
1089
+ if( setjmp(_break_jump) )
1090
+ {
1091
+ #if !defined(AE_NO_EXCEPTIONS)
1092
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1093
+ #else
1094
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1095
+ return;
1096
+ #endif
1097
+ }
1098
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1099
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1100
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1101
+ alglib_impl::convr1dinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
1102
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1103
+ return;
1104
+ }
1105
+
1106
+ /*************************************************************************
1107
+ 1-dimensional real deconvolution (inverse of ConvR1D()), buffered version,
1108
+ which does not reallocate R[] if its length is enough to store the result
1109
+ (i.e. it reuses previously allocated memory as much as possible).
1110
+
1111
+
1112
+ -- ALGLIB --
1113
+ Copyright 30.11.2023 by Bochkanov Sergey
1114
+ *************************************************************************/
1115
+ void convr1dinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
1116
+ {
1117
+ jmp_buf _break_jump;
1118
+ alglib_impl::ae_state _alglib_env_state;
1119
+ alglib_impl::ae_state_init(&_alglib_env_state);
1120
+ if( setjmp(_break_jump) )
1121
+ {
1122
+ #if !defined(AE_NO_EXCEPTIONS)
1123
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1124
+ #else
1125
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1126
+ return;
1127
+ #endif
1128
+ }
1129
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1130
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1131
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1132
+ alglib_impl::convr1dinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
1133
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1134
+ return;
1135
+ }
1136
+
1137
+ /*************************************************************************
1138
+ 1-dimensional circular real convolution.
1139
+
1140
+ Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.
1141
+
1142
+ INPUT PARAMETERS
1143
+ S - array[0..M-1] - real signal
1144
+ M - problem size
1145
+ B - array[0..N-1] - real response
1146
+ N - problem size
1147
+
1148
+ OUTPUT PARAMETERS
1149
+ R - convolution: A*B. array[0..M-1].
1150
+
1151
+ NOTE:
1152
+ It is assumed that B is zero at T<0. If it has non-zero values at
1153
+ negative T's, you can still use this subroutine - just shift its result
1154
+ correspondingly.
1155
+
1156
+ NOTE: there is a buffered version of this function, ConvR1DCurcularBuf(),
1157
+ which can reuse space previously allocated in its output parameter R.
1158
+
1159
+ -- ALGLIB --
1160
+ Copyright 21.07.2009 by Bochkanov Sergey
1161
+ *************************************************************************/
1162
+ void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams)
1163
+ {
1164
+ jmp_buf _break_jump;
1165
+ alglib_impl::ae_state _alglib_env_state;
1166
+ alglib_impl::ae_state_init(&_alglib_env_state);
1167
+ if( setjmp(_break_jump) )
1168
+ {
1169
+ #if !defined(AE_NO_EXCEPTIONS)
1170
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1171
+ #else
1172
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1173
+ return;
1174
+ #endif
1175
+ }
1176
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1177
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1178
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1179
+ alglib_impl::convr1dcircular(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
1180
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1181
+ return;
1182
+ }
1183
+
1184
+ /*************************************************************************
1185
+ 1-dimensional circular real convolution, buffered version, which does not
1186
+ reallocate C[] if its length is enough to store the result (i.e. it reuses
1187
+ previously allocated memory as much as possible).
1188
+
1189
+ -- ALGLIB --
1190
+ Copyright 30.11.2023 by Bochkanov Sergey
1191
+ *************************************************************************/
1192
+ void convr1dcircularbuf(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams)
1193
+ {
1194
+ jmp_buf _break_jump;
1195
+ alglib_impl::ae_state _alglib_env_state;
1196
+ alglib_impl::ae_state_init(&_alglib_env_state);
1197
+ if( setjmp(_break_jump) )
1198
+ {
1199
+ #if !defined(AE_NO_EXCEPTIONS)
1200
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1201
+ #else
1202
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1203
+ return;
1204
+ #endif
1205
+ }
1206
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1207
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1208
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1209
+ alglib_impl::convr1dcircularbuf(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
1210
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1211
+ return;
1212
+ }
1213
+
1214
+ /*************************************************************************
1215
+ 1-dimensional complex deconvolution (inverse of ConvC1D()).
1216
+
1217
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
1218
+
1219
+ INPUT PARAMETERS
1220
+ A - array[0..M-1] - convolved signal, A = conv(R, B)
1221
+ M - convolved signal length
1222
+ B - array[0..N-1] - response
1223
+ N - response length
1224
+
1225
+ OUTPUT PARAMETERS
1226
+ R - deconvolved signal. array[0..M-N].
1227
+
1228
+ NOTE:
1229
+ deconvolution is unstable process and may result in division by zero
1230
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
1231
+
1232
+ NOTE:
1233
+ It is assumed that B is zero at T<0. If it has non-zero values at
1234
+ negative T's, you can still use this subroutine - just shift its result
1235
+ correspondingly.
1236
+
1237
+ -- ALGLIB --
1238
+ Copyright 21.07.2009 by Bochkanov Sergey
1239
+ *************************************************************************/
1240
+ void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
1241
+ {
1242
+ jmp_buf _break_jump;
1243
+ alglib_impl::ae_state _alglib_env_state;
1244
+ alglib_impl::ae_state_init(&_alglib_env_state);
1245
+ if( setjmp(_break_jump) )
1246
+ {
1247
+ #if !defined(AE_NO_EXCEPTIONS)
1248
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1249
+ #else
1250
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1251
+ return;
1252
+ #endif
1253
+ }
1254
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1255
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1256
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1257
+ alglib_impl::convr1dcircularinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
1258
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1259
+ return;
1260
+ }
1261
+
1262
+ /*************************************************************************
1263
+ 1-dimensional complex deconvolution, inverse of ConvR1DCircular().
1264
+
1265
+ Buffered version, which does not reallocate R[] if its length is enough to
1266
+ store the result (i.e. it reuses previously allocated memory as much as
1267
+ possible).
1268
+
1269
+ -- ALGLIB --
1270
+ Copyright 21.07.2009 by Bochkanov Sergey
1271
+ *************************************************************************/
1272
+ void convr1dcircularinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
1273
+ {
1274
+ jmp_buf _break_jump;
1275
+ alglib_impl::ae_state _alglib_env_state;
1276
+ alglib_impl::ae_state_init(&_alglib_env_state);
1277
+ if( setjmp(_break_jump) )
1278
+ {
1279
+ #if !defined(AE_NO_EXCEPTIONS)
1280
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1281
+ #else
1282
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1283
+ return;
1284
+ #endif
1285
+ }
1286
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1287
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1288
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1289
+ alglib_impl::convr1dcircularinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
1290
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1291
+ return;
1292
+ }
1293
+ #endif
1294
+
1295
+ #if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD)
1296
+ /*************************************************************************
1297
+ 1-dimensional complex cross-correlation.
1298
+
1299
+ For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
1300
+
1301
+ Correlation is calculated using reduction to convolution. Algorithm with
1302
+ max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
1303
+ about performance).
1304
+
1305
+ IMPORTANT:
1306
+ for historical reasons subroutine accepts its parameters in reversed
1307
+ order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional
1308
+ definition of cross-correlation, denoting cross-correlation as "x").
1309
+
1310
+ INPUT PARAMETERS
1311
+ Signal - array[0..N-1] - complex function to be transformed,
1312
+ signal containing pattern
1313
+ N - problem size
1314
+ Pattern - array[0..M-1] - complex function to be transformed,
1315
+ pattern to 'search' within a signal
1316
+ M - problem size
1317
+
1318
+ OUTPUT PARAMETERS
1319
+ R - cross-correlation, array[0..N+M-2]:
1320
+ * positive lags are stored in R[0..N-1],
1321
+ R[i] = sum(conj(pattern[j])*signal[i+j]
1322
+ * negative lags are stored in R[N..N+M-2],
1323
+ R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]
1324
+
1325
+ NOTE:
1326
+ It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
1327
+ on [-K..M-1], you can still use this subroutine, just shift result by K.
1328
+
1329
+ NOTE: there is a buffered version of this function, CorrC1DBuf(), which
1330
+ can reuse space previously allocated in its output parameter R.
1331
+
1332
+ -- ALGLIB --
1333
+ Copyright 21.07.2009 by Bochkanov Sergey
1334
+ *************************************************************************/
1335
+ 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, const xparams _xparams)
1336
+ {
1337
+ jmp_buf _break_jump;
1338
+ alglib_impl::ae_state _alglib_env_state;
1339
+ alglib_impl::ae_state_init(&_alglib_env_state);
1340
+ if( setjmp(_break_jump) )
1341
+ {
1342
+ #if !defined(AE_NO_EXCEPTIONS)
1343
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1344
+ #else
1345
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1346
+ return;
1347
+ #endif
1348
+ }
1349
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1350
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1351
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1352
+ alglib_impl::corrc1d(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
1353
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1354
+ return;
1355
+ }
1356
+
1357
+ /*************************************************************************
1358
+ 1-dimensional complex cross-correlation, a buffered version of CorrC1D()
1359
+ which does not reallocate R[] if its length is enough to store the result
1360
+ (i.e. it reuses previously allocated memory as much as possible).
1361
+
1362
+ -- ALGLIB --
1363
+ Copyright 21.07.2009 by Bochkanov Sergey
1364
+ *************************************************************************/
1365
+ void corrc1dbuf(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r, const xparams _xparams)
1366
+ {
1367
+ jmp_buf _break_jump;
1368
+ alglib_impl::ae_state _alglib_env_state;
1369
+ alglib_impl::ae_state_init(&_alglib_env_state);
1370
+ if( setjmp(_break_jump) )
1371
+ {
1372
+ #if !defined(AE_NO_EXCEPTIONS)
1373
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1374
+ #else
1375
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1376
+ return;
1377
+ #endif
1378
+ }
1379
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1380
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1381
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1382
+ alglib_impl::corrc1dbuf(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
1383
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1384
+ return;
1385
+ }
1386
+
1387
+ /*************************************************************************
1388
+ 1-dimensional circular complex cross-correlation.
1389
+
1390
+ For given Pattern/Signal returns corr(Pattern,Signal) (circular).
1391
+ Algorithm has linearithmic complexity for any M/N.
1392
+
1393
+ IMPORTANT:
1394
+ for historical reasons subroutine accepts its parameters in reversed
1395
+ order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using
1396
+ traditional definition of cross-correlation, denoting cross-correlation
1397
+ as "x").
1398
+
1399
+ INPUT PARAMETERS
1400
+ Signal - array[0..N-1] - complex function to be transformed,
1401
+ periodic signal containing pattern
1402
+ N - problem size
1403
+ Pattern - array[0..M-1] - complex function to be transformed,
1404
+ non-periodic pattern to 'search' within a signal
1405
+ M - problem size
1406
+
1407
+ OUTPUT PARAMETERS
1408
+ R - convolution: A*B. array[0..M-1].
1409
+
1410
+ NOTE: there is a buffered version of this function, CorrC1DCircular(),
1411
+ which can reuse space previously allocated in its output parameter R.
1412
+
1413
+ -- ALGLIB --
1414
+ Copyright 21.07.2009 by Bochkanov Sergey
1415
+ *************************************************************************/
1416
+ 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, const xparams _xparams)
1417
+ {
1418
+ jmp_buf _break_jump;
1419
+ alglib_impl::ae_state _alglib_env_state;
1420
+ alglib_impl::ae_state_init(&_alglib_env_state);
1421
+ if( setjmp(_break_jump) )
1422
+ {
1423
+ #if !defined(AE_NO_EXCEPTIONS)
1424
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1425
+ #else
1426
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1427
+ return;
1428
+ #endif
1429
+ }
1430
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1431
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1432
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1433
+ alglib_impl::corrc1dcircular(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
1434
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1435
+ return;
1436
+ }
1437
+
1438
+ /*************************************************************************
1439
+ 1-dimensional circular complex cross-correlation.
1440
+
1441
+ A buffered function which does not reallocate C[] if its length is enough
1442
+ to store the result (i.e. it reuses previously allocated memory as much as
1443
+ possible).
1444
+
1445
+ -- ALGLIB --
1446
+ Copyright 21.07.2009 by Bochkanov Sergey
1447
+ *************************************************************************/
1448
+ void corrc1dcircularbuf(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c, const xparams _xparams)
1449
+ {
1450
+ jmp_buf _break_jump;
1451
+ alglib_impl::ae_state _alglib_env_state;
1452
+ alglib_impl::ae_state_init(&_alglib_env_state);
1453
+ if( setjmp(_break_jump) )
1454
+ {
1455
+ #if !defined(AE_NO_EXCEPTIONS)
1456
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1457
+ #else
1458
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1459
+ return;
1460
+ #endif
1461
+ }
1462
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1463
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1464
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1465
+ alglib_impl::corrc1dcircularbuf(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
1466
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1467
+ return;
1468
+ }
1469
+
1470
+ /*************************************************************************
1471
+ 1-dimensional real cross-correlation.
1472
+
1473
+ For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
1474
+
1475
+ Correlation is calculated using reduction to convolution. Algorithm with
1476
+ max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
1477
+ about performance).
1478
+
1479
+ IMPORTANT:
1480
+ for historical reasons subroutine accepts its parameters in reversed
1481
+ order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional
1482
+ definition of cross-correlation, denoting cross-correlation as "x").
1483
+
1484
+ INPUT PARAMETERS
1485
+ Signal - array[0..N-1] - real function to be transformed,
1486
+ signal containing pattern
1487
+ N - problem size
1488
+ Pattern - array[0..M-1] - real function to be transformed,
1489
+ pattern to 'search' withing signal
1490
+ M - problem size
1491
+
1492
+ OUTPUT PARAMETERS
1493
+ R - cross-correlation, array[0..N+M-2]:
1494
+ * positive lags are stored in R[0..N-1],
1495
+ R[i] = sum(pattern[j]*signal[i+j]
1496
+ * negative lags are stored in R[N..N+M-2],
1497
+ R[N+M-1-i] = sum(pattern[j]*signal[-i+j]
1498
+
1499
+ NOTE:
1500
+ It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
1501
+ on [-K..M-1], you can still use this subroutine, just shift result by K.
1502
+
1503
+ NOTE: there is a buffered version of this function, CorrR1DBuf(), which
1504
+ can reuse space previously allocated in its output parameter R.
1505
+
1506
+ -- ALGLIB --
1507
+ Copyright 21.07.2009 by Bochkanov Sergey
1508
+ *************************************************************************/
1509
+ 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, const xparams _xparams)
1510
+ {
1511
+ jmp_buf _break_jump;
1512
+ alglib_impl::ae_state _alglib_env_state;
1513
+ alglib_impl::ae_state_init(&_alglib_env_state);
1514
+ if( setjmp(_break_jump) )
1515
+ {
1516
+ #if !defined(AE_NO_EXCEPTIONS)
1517
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1518
+ #else
1519
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1520
+ return;
1521
+ #endif
1522
+ }
1523
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1524
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1525
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1526
+ alglib_impl::corrr1d(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
1527
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1528
+ return;
1529
+ }
1530
+
1531
+ /*************************************************************************
1532
+ 1-dimensional real cross-correlation, buffered function, which does not
1533
+ reallocate R[] if its length is enough to store the result (i.e. it reuses
1534
+ previously allocated memory as much as possible).
1535
+
1536
+ -- ALGLIB --
1537
+ Copyright 21.07.2009 by Bochkanov Sergey
1538
+ *************************************************************************/
1539
+ void corrr1dbuf(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r, const xparams _xparams)
1540
+ {
1541
+ jmp_buf _break_jump;
1542
+ alglib_impl::ae_state _alglib_env_state;
1543
+ alglib_impl::ae_state_init(&_alglib_env_state);
1544
+ if( setjmp(_break_jump) )
1545
+ {
1546
+ #if !defined(AE_NO_EXCEPTIONS)
1547
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1548
+ #else
1549
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1550
+ return;
1551
+ #endif
1552
+ }
1553
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1554
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1555
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1556
+ alglib_impl::corrr1dbuf(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
1557
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1558
+ return;
1559
+ }
1560
+
1561
+ /*************************************************************************
1562
+ 1-dimensional circular real cross-correlation.
1563
+
1564
+ For given Pattern/Signal returns corr(Pattern,Signal) (circular).
1565
+ Algorithm has linearithmic complexity for any M/N.
1566
+
1567
+ IMPORTANT:
1568
+ for historical reasons subroutine accepts its parameters in reversed
1569
+ order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using
1570
+ traditional definition of cross-correlation, denoting cross-correlation
1571
+ as "x").
1572
+
1573
+ INPUT PARAMETERS
1574
+ Signal - array[0..N-1] - real function to be transformed,
1575
+ periodic signal containing pattern
1576
+ N - problem size
1577
+ Pattern - array[0..M-1] - real function to be transformed,
1578
+ non-periodic pattern to search withing signal
1579
+ M - problem size
1580
+
1581
+ OUTPUT PARAMETERS
1582
+ R - convolution: A*B. array[0..M-1].
1583
+
1584
+ NOTE: there is a buffered version of this function, CorrR1DCircularBuf(),
1585
+ which can reuse space previously allocated in its output parameter C.
1586
+
1587
+ -- ALGLIB --
1588
+ Copyright 21.07.2009 by Bochkanov Sergey
1589
+ *************************************************************************/
1590
+ 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, const xparams _xparams)
1591
+ {
1592
+ jmp_buf _break_jump;
1593
+ alglib_impl::ae_state _alglib_env_state;
1594
+ alglib_impl::ae_state_init(&_alglib_env_state);
1595
+ if( setjmp(_break_jump) )
1596
+ {
1597
+ #if !defined(AE_NO_EXCEPTIONS)
1598
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1599
+ #else
1600
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1601
+ return;
1602
+ #endif
1603
+ }
1604
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1605
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1606
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1607
+ alglib_impl::corrr1dcircular(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
1608
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1609
+ return;
1610
+ }
1611
+
1612
+ /*************************************************************************
1613
+ 1-dimensional circular real cross-correlation, buffered version , which
1614
+ does not reallocate C[] if its length is enough to store the result (i.e.
1615
+ it reuses previously allocated memory as much as possible).
1616
+
1617
+ -- ALGLIB --
1618
+ Copyright 21.07.2009 by Bochkanov Sergey
1619
+ *************************************************************************/
1620
+ void corrr1dcircularbuf(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c, const xparams _xparams)
1621
+ {
1622
+ jmp_buf _break_jump;
1623
+ alglib_impl::ae_state _alglib_env_state;
1624
+ alglib_impl::ae_state_init(&_alglib_env_state);
1625
+ if( setjmp(_break_jump) )
1626
+ {
1627
+ #if !defined(AE_NO_EXCEPTIONS)
1628
+ _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
1629
+ #else
1630
+ _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
1631
+ return;
1632
+ #endif
1633
+ }
1634
+ ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
1635
+ if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
1636
+ ae_state_set_flags(&_alglib_env_state, _xparams.flags);
1637
+ alglib_impl::corrr1dcircularbuf(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
1638
+ alglib_impl::ae_state_clear(&_alglib_env_state);
1639
+ return;
1640
+ }
1641
+ #endif
1642
+ }
1643
+
1644
+ /////////////////////////////////////////////////////////////////////////
1645
+ //
1646
+ // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE
1647
+ //
1648
+ /////////////////////////////////////////////////////////////////////////
1649
+ namespace alglib_impl
1650
+ {
1651
+ #if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD)
1652
+
1653
+
1654
+ #endif
1655
+ #if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD)
1656
+
1657
+
1658
+ #endif
1659
+ #if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD)
1660
+
1661
+
1662
+ #endif
1663
+ #if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD)
1664
+
1665
+
1666
+ #endif
1667
+
1668
+ #if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD)
1669
+
1670
+
1671
+ /*************************************************************************
1672
+ 1-dimensional complex FFT.
1673
+
1674
+ Array size N may be arbitrary number (composite or prime). Composite N's
1675
+ are handled with cache-oblivious variation of a Cooley-Tukey algorithm.
1676
+ Small prime-factors are transformed using hard coded codelets (similar to
1677
+ FFTW codelets, but without low-level optimization), large prime-factors
1678
+ are handled with Bluestein's algorithm.
1679
+
1680
+ Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only),
1681
+ most fast for powers of 2. When N have prime factors larger than these,
1682
+ but orders of magnitude smaller than N, computations will be about 4 times
1683
+ slower than for nearby highly composite N's. When N itself is prime, speed
1684
+ will be 6 times lower.
1685
+
1686
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
1687
+
1688
+ INPUT PARAMETERS
1689
+ A - array[0..N-1] - complex function to be transformed
1690
+ N - problem size
1691
+
1692
+ OUTPUT PARAMETERS
1693
+ A - DFT of a input array, array[0..N-1]
1694
+ A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
1695
+
1696
+
1697
+ -- ALGLIB --
1698
+ Copyright 29.05.2009 by Bochkanov Sergey
1699
+ *************************************************************************/
1700
+ void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state)
1701
+ {
1702
+ ae_frame _frame_block;
1703
+ fasttransformplan plan;
1704
+ ae_int_t i;
1705
+ ae_vector buf;
1706
+
1707
+ ae_frame_make(_state, &_frame_block);
1708
+ memset(&plan, 0, sizeof(plan));
1709
+ memset(&buf, 0, sizeof(buf));
1710
+ _fasttransformplan_init(&plan, _state, ae_true);
1711
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
1712
+
1713
+ ae_assert(n>0, "FFTC1D: incorrect N!", _state);
1714
+ ae_assert(a->cnt>=n, "FFTC1D: Length(A)<N!", _state);
1715
+ ae_assert(isfinitecvector(a, n, _state), "FFTC1D: A contains infinite or NAN values!", _state);
1716
+
1717
+ /*
1718
+ * Special case: N=1, FFT is just identity transform.
1719
+ * After this block we assume that N is strictly greater than 1.
1720
+ */
1721
+ if( n==1 )
1722
+ {
1723
+ ae_frame_leave(_state);
1724
+ return;
1725
+ }
1726
+
1727
+ /*
1728
+ * convert input array to the more convenient format
1729
+ */
1730
+ ae_vector_set_length(&buf, 2*n, _state);
1731
+ for(i=0; i<=n-1; i++)
1732
+ {
1733
+ buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
1734
+ buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
1735
+ }
1736
+
1737
+ /*
1738
+ * Generate plan and execute it.
1739
+ *
1740
+ * Plan is a combination of a successive factorizations of N and
1741
+ * precomputed data. It is much like a FFTW plan, but is not stored
1742
+ * between subroutine calls and is much simpler.
1743
+ */
1744
+ ftcomplexfftplan(n, 1, &plan, _state);
1745
+ ftapplyplan(&plan, &buf, 0, 1, _state);
1746
+
1747
+ /*
1748
+ * result
1749
+ */
1750
+ for(i=0; i<=n-1; i++)
1751
+ {
1752
+ a->ptr.p_complex[i].x = buf.ptr.p_double[2*i+0];
1753
+ a->ptr.p_complex[i].y = buf.ptr.p_double[2*i+1];
1754
+ }
1755
+ ae_frame_leave(_state);
1756
+ }
1757
+
1758
+
1759
+ /*************************************************************************
1760
+ 1-dimensional complex inverse FFT.
1761
+
1762
+ Array size N may be arbitrary number (composite or prime). Algorithm has
1763
+ O(N*logN) complexity for any N (composite or prime).
1764
+
1765
+ See FFTC1D() description for more information about algorithm performance.
1766
+
1767
+ INPUT PARAMETERS
1768
+ A - array[0..N-1] - complex array to be transformed
1769
+ N - problem size
1770
+
1771
+ OUTPUT PARAMETERS
1772
+ A - inverse DFT of a input array, array[0..N-1]
1773
+ A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
1774
+
1775
+
1776
+ -- ALGLIB --
1777
+ Copyright 29.05.2009 by Bochkanov Sergey
1778
+ *************************************************************************/
1779
+ void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state)
1780
+ {
1781
+ ae_int_t i;
1782
+
1783
+
1784
+ ae_assert(n>0, "FFTC1DInv: incorrect N!", _state);
1785
+ ae_assert(a->cnt>=n, "FFTC1DInv: Length(A)<N!", _state);
1786
+ ae_assert(isfinitecvector(a, n, _state), "FFTC1DInv: A contains infinite or NAN values!", _state);
1787
+
1788
+ /*
1789
+ * Inverse DFT can be expressed in terms of the DFT as
1790
+ *
1791
+ * invfft(x) = fft(x')'/N
1792
+ *
1793
+ * here x' means conj(x).
1794
+ */
1795
+ for(i=0; i<=n-1; i++)
1796
+ {
1797
+ a->ptr.p_complex[i].y = -a->ptr.p_complex[i].y;
1798
+ }
1799
+ fftc1d(a, n, _state);
1800
+ for(i=0; i<=n-1; i++)
1801
+ {
1802
+ a->ptr.p_complex[i].x = a->ptr.p_complex[i].x/(double)n;
1803
+ a->ptr.p_complex[i].y = -a->ptr.p_complex[i].y/(double)n;
1804
+ }
1805
+ }
1806
+
1807
+
1808
+ /*************************************************************************
1809
+ 1-dimensional real FFT.
1810
+
1811
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
1812
+
1813
+ INPUT PARAMETERS
1814
+ A - array[0..N-1] - real function to be transformed
1815
+ N - problem size
1816
+
1817
+ OUTPUT PARAMETERS
1818
+ F - DFT of a input array, array[0..N-1]
1819
+ F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
1820
+
1821
+ NOTE: there is a buffered version of this function, FFTR1DBuf(), which
1822
+ reuses memory previously allocated for A as much as possible.
1823
+
1824
+ NOTE:
1825
+ F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half
1826
+ of array is usually needed. But for convinience subroutine returns full
1827
+ complex array (with frequencies above N/2), so its result may be used by
1828
+ other FFT-related subroutines.
1829
+
1830
+
1831
+ -- ALGLIB --
1832
+ Copyright 01.06.2009 by Bochkanov Sergey
1833
+ *************************************************************************/
1834
+ void fftr1d(/* Real */ const ae_vector* a,
1835
+ ae_int_t n,
1836
+ /* Complex */ ae_vector* f,
1837
+ ae_state *_state)
1838
+ {
1839
+
1840
+ ae_vector_clear(f);
1841
+
1842
+ ae_assert(n>0, "FFTR1D: incorrect N!", _state);
1843
+ ae_assert(a->cnt>=n, "FFTR1D: Length(A)<N!", _state);
1844
+ ae_assert(isfinitevector(a, n, _state), "FFTR1D: A contains infinite or NAN values!", _state);
1845
+ fftr1dbuf(a, n, f, _state);
1846
+ }
1847
+
1848
+
1849
+ /*************************************************************************
1850
+ 1-dimensional real FFT, a buffered function which does not reallocate F[]
1851
+ if its length is enough to store the result (i.e. it reuses previously
1852
+ allocated memory as much as possible).
1853
+
1854
+ -- ALGLIB --
1855
+ Copyright 01.06.2009 by Bochkanov Sergey
1856
+ *************************************************************************/
1857
+ void fftr1dbuf(/* Real */ const ae_vector* a,
1858
+ ae_int_t n,
1859
+ /* Complex */ ae_vector* f,
1860
+ ae_state *_state)
1861
+ {
1862
+ ae_frame _frame_block;
1863
+ ae_int_t i;
1864
+ ae_int_t n2;
1865
+ ae_int_t idx;
1866
+ ae_complex hn;
1867
+ ae_complex hmnc;
1868
+ ae_complex v;
1869
+ ae_vector buf;
1870
+ fasttransformplan plan;
1871
+
1872
+ ae_frame_make(_state, &_frame_block);
1873
+ memset(&buf, 0, sizeof(buf));
1874
+ memset(&plan, 0, sizeof(plan));
1875
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
1876
+ _fasttransformplan_init(&plan, _state, ae_true);
1877
+
1878
+ ae_assert(n>0, "FFTR1DBuf: incorrect N!", _state);
1879
+ ae_assert(a->cnt>=n, "FFTR1DBuf: Length(A)<N!", _state);
1880
+ ae_assert(isfinitevector(a, n, _state), "FFTR1DBuf: A contains infinite or NAN values!", _state);
1881
+
1882
+ /*
1883
+ * Special cases:
1884
+ * * N=1, FFT is just identity transform.
1885
+ * * N=2, FFT is simple too
1886
+ *
1887
+ * After this block we assume that N is strictly greater than 2
1888
+ */
1889
+ if( n==1 )
1890
+ {
1891
+ callocv(1, f, _state);
1892
+ f->ptr.p_complex[0] = ae_complex_from_d(a->ptr.p_double[0]);
1893
+ ae_frame_leave(_state);
1894
+ return;
1895
+ }
1896
+ if( n==2 )
1897
+ {
1898
+ callocv(2, f, _state);
1899
+ f->ptr.p_complex[0].x = a->ptr.p_double[0]+a->ptr.p_double[1];
1900
+ f->ptr.p_complex[0].y = (double)(0);
1901
+ f->ptr.p_complex[1].x = a->ptr.p_double[0]-a->ptr.p_double[1];
1902
+ f->ptr.p_complex[1].y = (double)(0);
1903
+ ae_frame_leave(_state);
1904
+ return;
1905
+ }
1906
+
1907
+ /*
1908
+ * Choose between odd-size and even-size FFTs
1909
+ */
1910
+ if( n%2==0 )
1911
+ {
1912
+
1913
+ /*
1914
+ * even-size real FFT, use reduction to the complex task
1915
+ */
1916
+ n2 = n/2;
1917
+ ae_vector_set_length(&buf, n, _state);
1918
+ ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1));
1919
+ ftcomplexfftplan(n2, 1, &plan, _state);
1920
+ ftapplyplan(&plan, &buf, 0, 1, _state);
1921
+ callocv(n, f, _state);
1922
+ for(i=0; i<=n2; i++)
1923
+ {
1924
+ idx = 2*(i%n2);
1925
+ hn.x = buf.ptr.p_double[idx+0];
1926
+ hn.y = buf.ptr.p_double[idx+1];
1927
+ idx = 2*((n2-i)%n2);
1928
+ hmnc.x = buf.ptr.p_double[idx+0];
1929
+ hmnc.y = -buf.ptr.p_double[idx+1];
1930
+ v.x = -ae_sin(-(double)2*ae_pi*(double)i/(double)n, _state);
1931
+ v.y = ae_cos(-(double)2*ae_pi*(double)i/(double)n, _state);
1932
+ f->ptr.p_complex[i] = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc)));
1933
+ f->ptr.p_complex[i].x = 0.5*f->ptr.p_complex[i].x;
1934
+ f->ptr.p_complex[i].y = 0.5*f->ptr.p_complex[i].y;
1935
+ }
1936
+ for(i=n2+1; i<=n-1; i++)
1937
+ {
1938
+ f->ptr.p_complex[i] = ae_c_conj(f->ptr.p_complex[n-i], _state);
1939
+ }
1940
+ }
1941
+ else
1942
+ {
1943
+
1944
+ /*
1945
+ * use complex FFT
1946
+ */
1947
+ callocv(n, f, _state);
1948
+ for(i=0; i<=n-1; i++)
1949
+ {
1950
+ f->ptr.p_complex[i] = ae_complex_from_d(a->ptr.p_double[i]);
1951
+ }
1952
+ fftc1d(f, n, _state);
1953
+ }
1954
+ ae_frame_leave(_state);
1955
+ }
1956
+
1957
+
1958
+ /*************************************************************************
1959
+ 1-dimensional real inverse FFT.
1960
+
1961
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
1962
+
1963
+ INPUT PARAMETERS
1964
+ F - array[0..floor(N/2)] - frequencies from forward real FFT
1965
+ N - problem size
1966
+
1967
+ OUTPUT PARAMETERS
1968
+ A - inverse DFT of a input array, array[0..N-1]
1969
+
1970
+ NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which
1971
+ reuses memory previously allocated for A as much as possible.
1972
+
1973
+ NOTE:
1974
+ F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one
1975
+ half of frequencies array is needed - elements from 0 to floor(N/2). F[0]
1976
+ is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then
1977
+ F[floor(N/2)] has no special properties.
1978
+
1979
+ Relying on properties noted above, FFTR1DInv subroutine uses only elements
1980
+ from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case
1981
+ N is even it ignores imaginary part of F[floor(N/2)] too.
1982
+
1983
+ When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
1984
+ - you can pass either either frequencies array with N elements or reduced
1985
+ array with roughly N/2 elements - subroutine will successfully transform
1986
+ both.
1987
+
1988
+ If you call this function using reduced arguments list - "FFTR1DInv(F,A)"
1989
+ - you must pass FULL array with N elements (although higher N/2 are still
1990
+ not used) because array size is used to automatically determine FFT length
1991
+
1992
+ -- ALGLIB --
1993
+ Copyright 01.06.2009 by Bochkanov Sergey
1994
+ *************************************************************************/
1995
+ void fftr1dinv(/* Complex */ const ae_vector* f,
1996
+ ae_int_t n,
1997
+ /* Real */ ae_vector* a,
1998
+ ae_state *_state)
1999
+ {
2000
+ ae_frame _frame_block;
2001
+ ae_int_t i;
2002
+ ae_vector h;
2003
+ ae_vector fh;
2004
+
2005
+ ae_frame_make(_state, &_frame_block);
2006
+ memset(&h, 0, sizeof(h));
2007
+ memset(&fh, 0, sizeof(fh));
2008
+ ae_vector_clear(a);
2009
+ ae_vector_init(&h, 0, DT_REAL, _state, ae_true);
2010
+ ae_vector_init(&fh, 0, DT_COMPLEX, _state, ae_true);
2011
+
2012
+ ae_assert(n>0, "FFTR1DInv: incorrect N!", _state);
2013
+ ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInv: Length(F)<Floor(N/2)+1!", _state);
2014
+ ae_assert(ae_isfinite(f->ptr.p_complex[0].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state);
2015
+ for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++)
2016
+ {
2017
+ 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);
2018
+ }
2019
+ 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);
2020
+ if( n%2!=0 )
2021
+ {
2022
+ 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);
2023
+ }
2024
+ fftr1dinvbuf(f, n, a, _state);
2025
+ ae_frame_leave(_state);
2026
+ }
2027
+
2028
+
2029
+ /*************************************************************************
2030
+ 1-dimensional real inverse FFT, buffered version, which does not reallocate
2031
+ A[] if its length is enough to store the result (i.e. it reuses previously
2032
+ allocated memory as much as possible).
2033
+
2034
+ -- ALGLIB --
2035
+ Copyright 01.06.2009 by Bochkanov Sergey
2036
+ *************************************************************************/
2037
+ void fftr1dinvbuf(/* Complex */ const ae_vector* f,
2038
+ ae_int_t n,
2039
+ /* Real */ ae_vector* a,
2040
+ ae_state *_state)
2041
+ {
2042
+ ae_frame _frame_block;
2043
+ ae_int_t i;
2044
+ ae_vector h;
2045
+ ae_vector fh;
2046
+
2047
+ ae_frame_make(_state, &_frame_block);
2048
+ memset(&h, 0, sizeof(h));
2049
+ memset(&fh, 0, sizeof(fh));
2050
+ ae_vector_init(&h, 0, DT_REAL, _state, ae_true);
2051
+ ae_vector_init(&fh, 0, DT_COMPLEX, _state, ae_true);
2052
+
2053
+ ae_assert(n>0, "FFTR1DInvBuf: incorrect N!", _state);
2054
+ ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInvBuf: Length(F)<Floor(N/2)+1!", _state);
2055
+ ae_assert(ae_isfinite(f->ptr.p_complex[0].x, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
2056
+ for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++)
2057
+ {
2058
+ ae_assert(ae_isfinite(f->ptr.p_complex[i].x, _state)&&ae_isfinite(f->ptr.p_complex[i].y, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
2059
+ }
2060
+ ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
2061
+ if( n%2!=0 )
2062
+ {
2063
+ ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
2064
+ }
2065
+
2066
+ /*
2067
+ * Special case: N=1, FFT is just identity transform.
2068
+ * After this block we assume that N is strictly greater than 1.
2069
+ */
2070
+ if( n==1 )
2071
+ {
2072
+ rallocv(1, a, _state);
2073
+ a->ptr.p_double[0] = f->ptr.p_complex[0].x;
2074
+ ae_frame_leave(_state);
2075
+ return;
2076
+ }
2077
+
2078
+ /*
2079
+ * inverse real FFT is reduced to the inverse real FHT,
2080
+ * which is reduced to the forward real FHT,
2081
+ * which is reduced to the forward real FFT.
2082
+ *
2083
+ * Don't worry, it is really compact and efficient reduction :)
2084
+ */
2085
+ ae_vector_set_length(&h, n, _state);
2086
+ rallocv(n, a, _state);
2087
+ h.ptr.p_double[0] = f->ptr.p_complex[0].x;
2088
+ for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++)
2089
+ {
2090
+ h.ptr.p_double[i] = f->ptr.p_complex[i].x-f->ptr.p_complex[i].y;
2091
+ h.ptr.p_double[n-i] = f->ptr.p_complex[i].x+f->ptr.p_complex[i].y;
2092
+ }
2093
+ if( n%2==0 )
2094
+ {
2095
+ h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x;
2096
+ }
2097
+ else
2098
+ {
2099
+ 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;
2100
+ 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;
2101
+ }
2102
+ fftr1d(&h, n, &fh, _state);
2103
+ for(i=0; i<=n-1; i++)
2104
+ {
2105
+ a->ptr.p_double[i] = (fh.ptr.p_complex[i].x-fh.ptr.p_complex[i].y)/(double)n;
2106
+ }
2107
+ ae_frame_leave(_state);
2108
+ }
2109
+
2110
+
2111
+ /*************************************************************************
2112
+ Internal subroutine. Never call it directly!
2113
+
2114
+
2115
+ -- ALGLIB --
2116
+ Copyright 01.06.2009 by Bochkanov Sergey
2117
+ *************************************************************************/
2118
+ void fftr1dinternaleven(/* Real */ ae_vector* a,
2119
+ ae_int_t n,
2120
+ /* Real */ ae_vector* buf,
2121
+ fasttransformplan* plan,
2122
+ ae_state *_state)
2123
+ {
2124
+ double x;
2125
+ double y;
2126
+ ae_int_t i;
2127
+ ae_int_t n2;
2128
+ ae_int_t idx;
2129
+ ae_complex hn;
2130
+ ae_complex hmnc;
2131
+ ae_complex v;
2132
+
2133
+
2134
+ ae_assert(n>0&&n%2==0, "FFTR1DEvenInplace: incorrect N!", _state);
2135
+
2136
+ /*
2137
+ * Special cases:
2138
+ * * N=2
2139
+ *
2140
+ * After this block we assume that N is strictly greater than 2
2141
+ */
2142
+ if( n==2 )
2143
+ {
2144
+ x = a->ptr.p_double[0]+a->ptr.p_double[1];
2145
+ y = a->ptr.p_double[0]-a->ptr.p_double[1];
2146
+ a->ptr.p_double[0] = x;
2147
+ a->ptr.p_double[1] = y;
2148
+ return;
2149
+ }
2150
+
2151
+ /*
2152
+ * even-size real FFT, use reduction to the complex task
2153
+ */
2154
+ n2 = n/2;
2155
+ ae_v_move(&buf->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1));
2156
+ ftapplyplan(plan, buf, 0, 1, _state);
2157
+ a->ptr.p_double[0] = buf->ptr.p_double[0]+buf->ptr.p_double[1];
2158
+ for(i=1; i<=n2-1; i++)
2159
+ {
2160
+ idx = 2*(i%n2);
2161
+ hn.x = buf->ptr.p_double[idx+0];
2162
+ hn.y = buf->ptr.p_double[idx+1];
2163
+ idx = 2*(n2-i);
2164
+ hmnc.x = buf->ptr.p_double[idx+0];
2165
+ hmnc.y = -buf->ptr.p_double[idx+1];
2166
+ v.x = -ae_sin(-(double)2*ae_pi*(double)i/(double)n, _state);
2167
+ v.y = ae_cos(-(double)2*ae_pi*(double)i/(double)n, _state);
2168
+ v = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc)));
2169
+ a->ptr.p_double[2*i+0] = 0.5*v.x;
2170
+ a->ptr.p_double[2*i+1] = 0.5*v.y;
2171
+ }
2172
+ a->ptr.p_double[1] = buf->ptr.p_double[0]-buf->ptr.p_double[1];
2173
+ }
2174
+
2175
+
2176
+ /*************************************************************************
2177
+ Internal subroutine. Never call it directly!
2178
+
2179
+
2180
+ -- ALGLIB --
2181
+ Copyright 01.06.2009 by Bochkanov Sergey
2182
+ *************************************************************************/
2183
+ void fftr1dinvinternaleven(/* Real */ ae_vector* a,
2184
+ ae_int_t n,
2185
+ /* Real */ ae_vector* buf,
2186
+ fasttransformplan* plan,
2187
+ ae_state *_state)
2188
+ {
2189
+ double x;
2190
+ double y;
2191
+ double t;
2192
+ ae_int_t i;
2193
+ ae_int_t n2;
2194
+
2195
+
2196
+ ae_assert(n>0&&n%2==0, "FFTR1DInvInternalEven: incorrect N!", _state);
2197
+
2198
+ /*
2199
+ * Special cases:
2200
+ * * N=2
2201
+ *
2202
+ * After this block we assume that N is strictly greater than 2
2203
+ */
2204
+ if( n==2 )
2205
+ {
2206
+ x = 0.5*(a->ptr.p_double[0]+a->ptr.p_double[1]);
2207
+ y = 0.5*(a->ptr.p_double[0]-a->ptr.p_double[1]);
2208
+ a->ptr.p_double[0] = x;
2209
+ a->ptr.p_double[1] = y;
2210
+ return;
2211
+ }
2212
+
2213
+ /*
2214
+ * inverse real FFT is reduced to the inverse real FHT,
2215
+ * which is reduced to the forward real FHT,
2216
+ * which is reduced to the forward real FFT.
2217
+ *
2218
+ * Don't worry, it is really compact and efficient reduction :)
2219
+ */
2220
+ n2 = n/2;
2221
+ buf->ptr.p_double[0] = a->ptr.p_double[0];
2222
+ for(i=1; i<=n2-1; i++)
2223
+ {
2224
+ x = a->ptr.p_double[2*i+0];
2225
+ y = a->ptr.p_double[2*i+1];
2226
+ buf->ptr.p_double[i] = x-y;
2227
+ buf->ptr.p_double[n-i] = x+y;
2228
+ }
2229
+ buf->ptr.p_double[n2] = a->ptr.p_double[1];
2230
+ fftr1dinternaleven(buf, n, a, plan, _state);
2231
+ a->ptr.p_double[0] = buf->ptr.p_double[0]/(double)n;
2232
+ t = (double)1/(double)n;
2233
+ for(i=1; i<=n2-1; i++)
2234
+ {
2235
+ x = buf->ptr.p_double[2*i+0];
2236
+ y = buf->ptr.p_double[2*i+1];
2237
+ a->ptr.p_double[i] = t*(x-y);
2238
+ a->ptr.p_double[n-i] = t*(x+y);
2239
+ }
2240
+ a->ptr.p_double[n2] = buf->ptr.p_double[1]/(double)n;
2241
+ }
2242
+
2243
+
2244
+ #endif
2245
+ #if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD)
2246
+
2247
+
2248
+ /*************************************************************************
2249
+ 1-dimensional Fast Hartley Transform.
2250
+
2251
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
2252
+
2253
+ INPUT PARAMETERS
2254
+ A - array[0..N-1] - real function to be transformed
2255
+ N - problem size
2256
+
2257
+ OUTPUT PARAMETERS
2258
+ A - FHT of a input array, array[0..N-1],
2259
+ A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)
2260
+
2261
+
2262
+ -- ALGLIB --
2263
+ Copyright 04.06.2009 by Bochkanov Sergey
2264
+ *************************************************************************/
2265
+ void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state)
2266
+ {
2267
+ ae_frame _frame_block;
2268
+ ae_int_t i;
2269
+ ae_vector fa;
2270
+
2271
+ ae_frame_make(_state, &_frame_block);
2272
+ memset(&fa, 0, sizeof(fa));
2273
+ ae_vector_init(&fa, 0, DT_COMPLEX, _state, ae_true);
2274
+
2275
+ ae_assert(n>0, "FHTR1D: incorrect N!", _state);
2276
+
2277
+ /*
2278
+ * Special case: N=1, FHT is just identity transform.
2279
+ * After this block we assume that N is strictly greater than 1.
2280
+ */
2281
+ if( n==1 )
2282
+ {
2283
+ ae_frame_leave(_state);
2284
+ return;
2285
+ }
2286
+
2287
+ /*
2288
+ * Reduce FHt to real FFT
2289
+ */
2290
+ fftr1d(a, n, &fa, _state);
2291
+ for(i=0; i<=n-1; i++)
2292
+ {
2293
+ a->ptr.p_double[i] = fa.ptr.p_complex[i].x-fa.ptr.p_complex[i].y;
2294
+ }
2295
+ ae_frame_leave(_state);
2296
+ }
2297
+
2298
+
2299
+ /*************************************************************************
2300
+ 1-dimensional inverse FHT.
2301
+
2302
+ Algorithm has O(N*logN) complexity for any N (composite or prime).
2303
+
2304
+ INPUT PARAMETERS
2305
+ A - array[0..N-1] - complex array to be transformed
2306
+ N - problem size
2307
+
2308
+ OUTPUT PARAMETERS
2309
+ A - inverse FHT of a input array, array[0..N-1]
2310
+
2311
+
2312
+ -- ALGLIB --
2313
+ Copyright 29.05.2009 by Bochkanov Sergey
2314
+ *************************************************************************/
2315
+ void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state)
2316
+ {
2317
+ ae_int_t i;
2318
+
2319
+
2320
+ ae_assert(n>0, "FHTR1DInv: incorrect N!", _state);
2321
+
2322
+ /*
2323
+ * Special case: N=1, iFHT is just identity transform.
2324
+ * After this block we assume that N is strictly greater than 1.
2325
+ */
2326
+ if( n==1 )
2327
+ {
2328
+ return;
2329
+ }
2330
+
2331
+ /*
2332
+ * Inverse FHT can be expressed in terms of the FHT as
2333
+ *
2334
+ * invfht(x) = fht(x)/N
2335
+ */
2336
+ fhtr1d(a, n, _state);
2337
+ for(i=0; i<=n-1; i++)
2338
+ {
2339
+ a->ptr.p_double[i] = a->ptr.p_double[i]/(double)n;
2340
+ }
2341
+ }
2342
+
2343
+
2344
+ #endif
2345
+ #if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD)
2346
+
2347
+
2348
+ /*************************************************************************
2349
+ 1-dimensional complex convolution.
2350
+
2351
+ For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
2352
+ choose between three implementations: straightforward O(M*N) formula for
2353
+ very small N (or M), overlap-add algorithm for cases where max(M,N) is
2354
+ significantly larger than min(M,N), but O(M*N) algorithm is too slow, and
2355
+ general FFT-based formula for cases where two previous algorithms are too
2356
+ slow.
2357
+
2358
+ Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.
2359
+
2360
+ INPUT PARAMETERS
2361
+ A - array[M] - complex function to be transformed
2362
+ M - problem size
2363
+ B - array[N] - complex function to be transformed
2364
+ N - problem size
2365
+
2366
+ OUTPUT PARAMETERS
2367
+ R - convolution: A*B. array[N+M-1]
2368
+
2369
+ NOTE:
2370
+ It is assumed that A is zero at T<0, B is zero too. If one or both
2371
+ functions have non-zero values at negative T's, you can still use this
2372
+ subroutine - just shift its result correspondingly.
2373
+
2374
+ NOTE: there is a buffered version of this function, ConvC1DBuf(), which
2375
+ can reuse space previously allocated in its output parameter R.
2376
+
2377
+ -- ALGLIB --
2378
+ Copyright 21.07.2009 by Bochkanov Sergey
2379
+ *************************************************************************/
2380
+ void convc1d(/* Complex */ const ae_vector* a,
2381
+ ae_int_t m,
2382
+ /* Complex */ const ae_vector* b,
2383
+ ae_int_t n,
2384
+ /* Complex */ ae_vector* r,
2385
+ ae_state *_state)
2386
+ {
2387
+
2388
+ ae_vector_clear(r);
2389
+
2390
+ ae_assert(n>0&&m>0, "ConvC1D: incorrect N or M!", _state);
2391
+ convc1dbuf(a, m, b, n, r, _state);
2392
+ }
2393
+
2394
+
2395
+ /*************************************************************************
2396
+ 1-dimensional complex convolution, buffered version of ConvC1DBuf(), which
2397
+ does not reallocate R[] if its length is enough to store the result (i.e.
2398
+ it reuses previously allocated memory as much as possible).
2399
+
2400
+ -- ALGLIB --
2401
+ Copyright 30.11.2023 by Bochkanov Sergey
2402
+ *************************************************************************/
2403
+ void convc1dbuf(/* Complex */ const ae_vector* a,
2404
+ ae_int_t m,
2405
+ /* Complex */ const ae_vector* b,
2406
+ ae_int_t n,
2407
+ /* Complex */ ae_vector* r,
2408
+ ae_state *_state)
2409
+ {
2410
+
2411
+
2412
+ ae_assert(n>0&&m>0, "ConvC1DBuf: incorrect N or M!", _state);
2413
+
2414
+ /*
2415
+ * normalize task: make M>=N,
2416
+ * so A will be longer that B.
2417
+ */
2418
+ if( m<n )
2419
+ {
2420
+ convc1dbuf(b, n, a, m, r, _state);
2421
+ return;
2422
+ }
2423
+ convc1dx(a, m, b, n, ae_false, -1, 0, r, _state);
2424
+ }
2425
+
2426
+
2427
+ /*************************************************************************
2428
+ 1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
2429
+
2430
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
2431
+
2432
+ INPUT PARAMETERS
2433
+ A - array[0..M-1] - convolved signal, A = conv(R, B)
2434
+ M - convolved signal length
2435
+ B - array[0..N-1] - response
2436
+ N - response length, N<=M
2437
+
2438
+ OUTPUT PARAMETERS
2439
+ R - deconvolved signal. array[0..M-N].
2440
+
2441
+ NOTE:
2442
+ deconvolution is unstable process and may result in division by zero
2443
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
2444
+
2445
+ NOTE:
2446
+ It is assumed that A is zero at T<0, B is zero too. If one or both
2447
+ functions have non-zero values at negative T's, you can still use this
2448
+ subroutine - just shift its result correspondingly.
2449
+
2450
+ NOTE: there is a buffered version of this function, ConvC1DInvBuf(),
2451
+ which can reuse space previously allocated in its output parameter R
2452
+
2453
+ -- ALGLIB --
2454
+ Copyright 21.07.2009 by Bochkanov Sergey
2455
+ *************************************************************************/
2456
+ void convc1dinv(/* Complex */ const ae_vector* a,
2457
+ ae_int_t m,
2458
+ /* Complex */ const ae_vector* b,
2459
+ ae_int_t n,
2460
+ /* Complex */ ae_vector* r,
2461
+ ae_state *_state)
2462
+ {
2463
+
2464
+ ae_vector_clear(r);
2465
+
2466
+ ae_assert((n>0&&m>0)&&n<=m, "ConvC1DInv: incorrect N or M!", _state);
2467
+ convc1dinvbuf(a, m, b, n, r, _state);
2468
+ }
2469
+
2470
+
2471
+ /*************************************************************************
2472
+ 1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
2473
+
2474
+ A buffered version, which does not reallocate R[] if its length is enough
2475
+ to store the result (i.e. it reuses previously allocated memory as much as
2476
+ possible).
2477
+
2478
+ -- ALGLIB --
2479
+ Copyright 30.11.2023 by Bochkanov Sergey
2480
+ *************************************************************************/
2481
+ void convc1dinvbuf(/* Complex */ const ae_vector* a,
2482
+ ae_int_t m,
2483
+ /* Complex */ const ae_vector* b,
2484
+ ae_int_t n,
2485
+ /* Complex */ ae_vector* r,
2486
+ ae_state *_state)
2487
+ {
2488
+ ae_frame _frame_block;
2489
+ ae_int_t i;
2490
+ ae_int_t p;
2491
+ ae_vector buf;
2492
+ ae_vector buf2;
2493
+ fasttransformplan plan;
2494
+ ae_complex c1;
2495
+ ae_complex c2;
2496
+ ae_complex c3;
2497
+ double t;
2498
+
2499
+ ae_frame_make(_state, &_frame_block);
2500
+ memset(&buf, 0, sizeof(buf));
2501
+ memset(&buf2, 0, sizeof(buf2));
2502
+ memset(&plan, 0, sizeof(plan));
2503
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
2504
+ ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
2505
+ _fasttransformplan_init(&plan, _state, ae_true);
2506
+
2507
+ ae_assert((n>0&&m>0)&&n<=m, "ConvC1DInvBuf: incorrect N or M!", _state);
2508
+ p = ftbasefindsmooth(m, _state);
2509
+ ftcomplexfftplan(p, 1, &plan, _state);
2510
+ ae_vector_set_length(&buf, 2*p, _state);
2511
+ for(i=0; i<=m-1; i++)
2512
+ {
2513
+ buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
2514
+ buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
2515
+ }
2516
+ for(i=m; i<=p-1; i++)
2517
+ {
2518
+ buf.ptr.p_double[2*i+0] = (double)(0);
2519
+ buf.ptr.p_double[2*i+1] = (double)(0);
2520
+ }
2521
+ ae_vector_set_length(&buf2, 2*p, _state);
2522
+ for(i=0; i<=n-1; i++)
2523
+ {
2524
+ buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
2525
+ buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
2526
+ }
2527
+ for(i=n; i<=p-1; i++)
2528
+ {
2529
+ buf2.ptr.p_double[2*i+0] = (double)(0);
2530
+ buf2.ptr.p_double[2*i+1] = (double)(0);
2531
+ }
2532
+ ftapplyplan(&plan, &buf, 0, 1, _state);
2533
+ ftapplyplan(&plan, &buf2, 0, 1, _state);
2534
+ for(i=0; i<=p-1; i++)
2535
+ {
2536
+ c1.x = buf.ptr.p_double[2*i+0];
2537
+ c1.y = buf.ptr.p_double[2*i+1];
2538
+ c2.x = buf2.ptr.p_double[2*i+0];
2539
+ c2.y = buf2.ptr.p_double[2*i+1];
2540
+ c3 = ae_c_div(c1,c2);
2541
+ buf.ptr.p_double[2*i+0] = c3.x;
2542
+ buf.ptr.p_double[2*i+1] = -c3.y;
2543
+ }
2544
+ ftapplyplan(&plan, &buf, 0, 1, _state);
2545
+ t = (double)1/(double)p;
2546
+ callocv(m-n+1, r, _state);
2547
+ for(i=0; i<=m-n; i++)
2548
+ {
2549
+ r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
2550
+ r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
2551
+ }
2552
+ ae_frame_leave(_state);
2553
+ }
2554
+
2555
+
2556
+ /*************************************************************************
2557
+ 1-dimensional circular complex convolution.
2558
+
2559
+ For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
2560
+ complexity for any M/N.
2561
+
2562
+ IMPORTANT: normal convolution is commutative, i.e. it is symmetric -
2563
+ conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a
2564
+ signal, periodic function, and another - R - is a response, non-periodic
2565
+ function with limited length.
2566
+
2567
+ INPUT PARAMETERS
2568
+ S - array[M] - complex periodic signal
2569
+ M - problem size
2570
+ B - array[N] - complex non-periodic response
2571
+ N - problem size
2572
+
2573
+ OUTPUT PARAMETERS
2574
+ R - convolution: A*B. array[M].
2575
+
2576
+ NOTE:
2577
+ It is assumed that B is zero at T<0. If it has non-zero values at
2578
+ negative T's, you can still use this subroutine - just shift its result
2579
+ correspondingly.
2580
+
2581
+ NOTE: there is a buffered version of this function, ConvC1DCircularBuf(),
2582
+ which can reuse space previously allocated in its output parameter R.
2583
+
2584
+ -- ALGLIB --
2585
+ Copyright 21.07.2009 by Bochkanov Sergey
2586
+ *************************************************************************/
2587
+ void convc1dcircular(/* Complex */ const ae_vector* s,
2588
+ ae_int_t m,
2589
+ /* Complex */ const ae_vector* r,
2590
+ ae_int_t n,
2591
+ /* Complex */ ae_vector* c,
2592
+ ae_state *_state)
2593
+ {
2594
+
2595
+ ae_vector_clear(c);
2596
+
2597
+ ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
2598
+ convc1dcircularbuf(s, m, r, n, c, _state);
2599
+ }
2600
+
2601
+
2602
+ /*************************************************************************
2603
+ 1-dimensional circular complex convolution.
2604
+
2605
+ Buffered version of ConvC1DCircular(), which does not reallocate C[] if
2606
+ its length is enough to store the result (i.e. it reuses previously
2607
+ allocated memory as much as possible).
2608
+
2609
+ -- ALGLIB --
2610
+ Copyright 30.11.2023 by Bochkanov Sergey
2611
+ *************************************************************************/
2612
+ void convc1dcircularbuf(/* Complex */ const ae_vector* s,
2613
+ ae_int_t m,
2614
+ /* Complex */ const ae_vector* r,
2615
+ ae_int_t n,
2616
+ /* Complex */ ae_vector* c,
2617
+ ae_state *_state)
2618
+ {
2619
+ ae_frame _frame_block;
2620
+ ae_vector buf;
2621
+ ae_int_t i1;
2622
+ ae_int_t i2;
2623
+ ae_int_t j2;
2624
+
2625
+ ae_frame_make(_state, &_frame_block);
2626
+ memset(&buf, 0, sizeof(buf));
2627
+ ae_vector_init(&buf, 0, DT_COMPLEX, _state, ae_true);
2628
+
2629
+ ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
2630
+
2631
+ /*
2632
+ * normalize task: make M>=N,
2633
+ * so A will be longer (at least - not shorter) that B.
2634
+ */
2635
+ if( m<n )
2636
+ {
2637
+ ae_vector_set_length(&buf, m, _state);
2638
+ for(i1=0; i1<=m-1; i1++)
2639
+ {
2640
+ buf.ptr.p_complex[i1] = ae_complex_from_i(0);
2641
+ }
2642
+ i1 = 0;
2643
+ while(i1<n)
2644
+ {
2645
+ i2 = ae_minint(i1+m-1, n-1, _state);
2646
+ j2 = i2-i1;
2647
+ ae_v_cadd(&buf.ptr.p_complex[0], 1, &r->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
2648
+ i1 = i1+m;
2649
+ }
2650
+ convc1dcircularbuf(s, m, &buf, m, c, _state);
2651
+ ae_frame_leave(_state);
2652
+ return;
2653
+ }
2654
+ convc1dx(s, m, r, n, ae_true, -1, 0, c, _state);
2655
+ ae_frame_leave(_state);
2656
+ }
2657
+
2658
+
2659
+ /*************************************************************************
2660
+ 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
2661
+
2662
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
2663
+
2664
+ INPUT PARAMETERS
2665
+ A - array[0..M-1] - convolved periodic signal, A = conv(R, B)
2666
+ M - convolved signal length
2667
+ B - array[0..N-1] - non-periodic response
2668
+ N - response length
2669
+
2670
+ OUTPUT PARAMETERS
2671
+ R - deconvolved signal. array[0..M-1].
2672
+
2673
+ NOTE:
2674
+ deconvolution is unstable process and may result in division by zero
2675
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
2676
+
2677
+ NOTE:
2678
+ It is assumed that B is zero at T<0. If it has non-zero values at
2679
+ negative T's, you can still use this subroutine - just shift its result
2680
+ correspondingly.
2681
+
2682
+ NOTE: there is a buffered version of this function, ConvC1DCircularInvBuf(),
2683
+ which can reuse space previously allocated in its output parameter R.
2684
+
2685
+ -- ALGLIB --
2686
+ Copyright 21.07.2009 by Bochkanov Sergey
2687
+ *************************************************************************/
2688
+ void convc1dcircularinv(/* Complex */ const ae_vector* a,
2689
+ ae_int_t m,
2690
+ /* Complex */ const ae_vector* b,
2691
+ ae_int_t n,
2692
+ /* Complex */ ae_vector* r,
2693
+ ae_state *_state)
2694
+ {
2695
+
2696
+ ae_vector_clear(r);
2697
+
2698
+ ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state);
2699
+ convc1dcircularinvbuf(a, m, b, n, r, _state);
2700
+ }
2701
+
2702
+
2703
+ /*************************************************************************
2704
+ 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
2705
+
2706
+ Buffered version of ConvC1DCircularInv(), which does not reallocate R[] if
2707
+ its length is enough to store the result (i.e. it reuses previously
2708
+ allocated memory as much as possible).
2709
+
2710
+ -- ALGLIB --
2711
+ Copyright 30.11.2023 by Bochkanov Sergey
2712
+ *************************************************************************/
2713
+ void convc1dcircularinvbuf(/* Complex */ const ae_vector* a,
2714
+ ae_int_t m,
2715
+ /* Complex */ const ae_vector* b,
2716
+ ae_int_t n,
2717
+ /* Complex */ ae_vector* r,
2718
+ ae_state *_state)
2719
+ {
2720
+ ae_frame _frame_block;
2721
+ ae_int_t i;
2722
+ ae_int_t i1;
2723
+ ae_int_t i2;
2724
+ ae_int_t j2;
2725
+ ae_vector buf;
2726
+ ae_vector buf2;
2727
+ ae_vector cbuf;
2728
+ fasttransformplan plan;
2729
+ ae_complex c1;
2730
+ ae_complex c2;
2731
+ ae_complex c3;
2732
+ double t;
2733
+
2734
+ ae_frame_make(_state, &_frame_block);
2735
+ memset(&buf, 0, sizeof(buf));
2736
+ memset(&buf2, 0, sizeof(buf2));
2737
+ memset(&cbuf, 0, sizeof(cbuf));
2738
+ memset(&plan, 0, sizeof(plan));
2739
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
2740
+ ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
2741
+ ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true);
2742
+ _fasttransformplan_init(&plan, _state, ae_true);
2743
+
2744
+ ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state);
2745
+
2746
+ /*
2747
+ * normalize task: make M>=N,
2748
+ * so A will be longer (at least - not shorter) that B.
2749
+ */
2750
+ if( m<n )
2751
+ {
2752
+ ae_vector_set_length(&cbuf, m, _state);
2753
+ for(i=0; i<=m-1; i++)
2754
+ {
2755
+ cbuf.ptr.p_complex[i] = ae_complex_from_i(0);
2756
+ }
2757
+ i1 = 0;
2758
+ while(i1<n)
2759
+ {
2760
+ i2 = ae_minint(i1+m-1, n-1, _state);
2761
+ j2 = i2-i1;
2762
+ ae_v_cadd(&cbuf.ptr.p_complex[0], 1, &b->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
2763
+ i1 = i1+m;
2764
+ }
2765
+ convc1dcircularinvbuf(a, m, &cbuf, m, r, _state);
2766
+ ae_frame_leave(_state);
2767
+ return;
2768
+ }
2769
+
2770
+ /*
2771
+ * Task is normalized
2772
+ */
2773
+ ftcomplexfftplan(m, 1, &plan, _state);
2774
+ ae_vector_set_length(&buf, 2*m, _state);
2775
+ for(i=0; i<=m-1; i++)
2776
+ {
2777
+ buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
2778
+ buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
2779
+ }
2780
+ ae_vector_set_length(&buf2, 2*m, _state);
2781
+ for(i=0; i<=n-1; i++)
2782
+ {
2783
+ buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
2784
+ buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
2785
+ }
2786
+ for(i=n; i<=m-1; i++)
2787
+ {
2788
+ buf2.ptr.p_double[2*i+0] = (double)(0);
2789
+ buf2.ptr.p_double[2*i+1] = (double)(0);
2790
+ }
2791
+ ftapplyplan(&plan, &buf, 0, 1, _state);
2792
+ ftapplyplan(&plan, &buf2, 0, 1, _state);
2793
+ for(i=0; i<=m-1; i++)
2794
+ {
2795
+ c1.x = buf.ptr.p_double[2*i+0];
2796
+ c1.y = buf.ptr.p_double[2*i+1];
2797
+ c2.x = buf2.ptr.p_double[2*i+0];
2798
+ c2.y = buf2.ptr.p_double[2*i+1];
2799
+ c3 = ae_c_div(c1,c2);
2800
+ buf.ptr.p_double[2*i+0] = c3.x;
2801
+ buf.ptr.p_double[2*i+1] = -c3.y;
2802
+ }
2803
+ ftapplyplan(&plan, &buf, 0, 1, _state);
2804
+ t = (double)1/(double)m;
2805
+ callocv(m, r, _state);
2806
+ for(i=0; i<=m-1; i++)
2807
+ {
2808
+ r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
2809
+ r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
2810
+ }
2811
+ ae_frame_leave(_state);
2812
+ }
2813
+
2814
+
2815
+ /*************************************************************************
2816
+ 1-dimensional real convolution.
2817
+
2818
+ Analogous to ConvC1D(), see ConvC1D() comments for more details.
2819
+
2820
+ INPUT PARAMETERS
2821
+ A - array[0..M-1] - real function to be transformed
2822
+ M - problem size
2823
+ B - array[0..N-1] - real function to be transformed
2824
+ N - problem size
2825
+
2826
+ OUTPUT PARAMETERS
2827
+ R - convolution: A*B. array[0..N+M-2].
2828
+
2829
+ NOTE:
2830
+ It is assumed that A is zero at T<0, B is zero too. If one or both
2831
+ functions have non-zero values at negative T's, you can still use this
2832
+ subroutine - just shift its result correspondingly.
2833
+
2834
+ NOTE: there is a buffered version of this function, ConvR1DBuf(),
2835
+ which can reuse space previously allocated in its output parameter R.
2836
+
2837
+
2838
+ -- ALGLIB --
2839
+ Copyright 21.07.2009 by Bochkanov Sergey
2840
+ *************************************************************************/
2841
+ void convr1d(/* Real */ const ae_vector* a,
2842
+ ae_int_t m,
2843
+ /* Real */ const ae_vector* b,
2844
+ ae_int_t n,
2845
+ /* Real */ ae_vector* r,
2846
+ ae_state *_state)
2847
+ {
2848
+
2849
+ ae_vector_clear(r);
2850
+
2851
+ ae_assert(n>0&&m>0, "ConvR1D: incorrect N or M!", _state);
2852
+ convr1dbuf(a, m, b, n, r, _state);
2853
+ }
2854
+
2855
+
2856
+ /*************************************************************************
2857
+ 1-dimensional real convolution.
2858
+
2859
+ Buffered version of ConvR1D(), which does not reallocate R[] if its length
2860
+ is enough to store the result (i.e. it reuses previously allocated memory
2861
+ as much as possible).
2862
+
2863
+ -- ALGLIB --
2864
+ Copyright 30.11.2023 by Bochkanov Sergey
2865
+ *************************************************************************/
2866
+ void convr1dbuf(/* Real */ const ae_vector* a,
2867
+ ae_int_t m,
2868
+ /* Real */ const ae_vector* b,
2869
+ ae_int_t n,
2870
+ /* Real */ ae_vector* r,
2871
+ ae_state *_state)
2872
+ {
2873
+
2874
+
2875
+ ae_assert(n>0&&m>0, "ConvR1DBuf: incorrect N or M!", _state);
2876
+
2877
+ /*
2878
+ * normalize task: make M>=N,
2879
+ * so A will be longer that B.
2880
+ */
2881
+ if( m<n )
2882
+ {
2883
+ convr1dbuf(b, n, a, m, r, _state);
2884
+ return;
2885
+ }
2886
+ convr1dx(a, m, b, n, ae_false, -1, 0, r, _state);
2887
+ }
2888
+
2889
+
2890
+ /*************************************************************************
2891
+ 1-dimensional real deconvolution (inverse of ConvC1D()).
2892
+
2893
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
2894
+
2895
+ INPUT PARAMETERS
2896
+ A - array[0..M-1] - convolved signal, A = conv(R, B)
2897
+ M - convolved signal length
2898
+ B - array[0..N-1] - response
2899
+ N - response length, N<=M
2900
+
2901
+ OUTPUT PARAMETERS
2902
+ R - deconvolved signal. array[0..M-N].
2903
+
2904
+ NOTE:
2905
+ deconvolution is unstable process and may result in division by zero
2906
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
2907
+
2908
+ NOTE:
2909
+ It is assumed that A is zero at T<0, B is zero too. If one or both
2910
+ functions have non-zero values at negative T's, you can still use this
2911
+ subroutine - just shift its result correspondingly.
2912
+
2913
+ NOTE: there is a buffered version of this function, ConvR1DInvBuf(),
2914
+ which can reuse space previously allocated in its output parameter R.
2915
+
2916
+ -- ALGLIB --
2917
+ Copyright 21.07.2009 by Bochkanov Sergey
2918
+ *************************************************************************/
2919
+ void convr1dinv(/* Real */ const ae_vector* a,
2920
+ ae_int_t m,
2921
+ /* Real */ const ae_vector* b,
2922
+ ae_int_t n,
2923
+ /* Real */ ae_vector* r,
2924
+ ae_state *_state)
2925
+ {
2926
+
2927
+ ae_vector_clear(r);
2928
+
2929
+ ae_assert((n>0&&m>0)&&n<=m, "ConvR1DInv: incorrect N or M!", _state);
2930
+ convr1dinvbuf(a, m, b, n, r, _state);
2931
+ }
2932
+
2933
+
2934
+ /*************************************************************************
2935
+ 1-dimensional real deconvolution (inverse of ConvR1D()), buffered version,
2936
+ which does not reallocate R[] if its length is enough to store the result
2937
+ (i.e. it reuses previously allocated memory as much as possible).
2938
+
2939
+
2940
+ -- ALGLIB --
2941
+ Copyright 30.11.2023 by Bochkanov Sergey
2942
+ *************************************************************************/
2943
+ void convr1dinvbuf(/* Real */ const ae_vector* a,
2944
+ ae_int_t m,
2945
+ /* Real */ const ae_vector* b,
2946
+ ae_int_t n,
2947
+ /* Real */ ae_vector* r,
2948
+ ae_state *_state)
2949
+ {
2950
+ ae_frame _frame_block;
2951
+ ae_int_t i;
2952
+ ae_int_t p;
2953
+ ae_vector buf;
2954
+ ae_vector buf2;
2955
+ ae_vector buf3;
2956
+ fasttransformplan plan;
2957
+ ae_complex c1;
2958
+ ae_complex c2;
2959
+ ae_complex c3;
2960
+
2961
+ ae_frame_make(_state, &_frame_block);
2962
+ memset(&buf, 0, sizeof(buf));
2963
+ memset(&buf2, 0, sizeof(buf2));
2964
+ memset(&buf3, 0, sizeof(buf3));
2965
+ memset(&plan, 0, sizeof(plan));
2966
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
2967
+ ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
2968
+ ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true);
2969
+ _fasttransformplan_init(&plan, _state, ae_true);
2970
+
2971
+ ae_assert((n>0&&m>0)&&n<=m, "ConvR1DInvBuf: incorrect N or M!", _state);
2972
+ p = ftbasefindsmootheven(m, _state);
2973
+ ae_vector_set_length(&buf, p, _state);
2974
+ ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
2975
+ for(i=m; i<=p-1; i++)
2976
+ {
2977
+ buf.ptr.p_double[i] = (double)(0);
2978
+ }
2979
+ ae_vector_set_length(&buf2, p, _state);
2980
+ ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
2981
+ for(i=n; i<=p-1; i++)
2982
+ {
2983
+ buf2.ptr.p_double[i] = (double)(0);
2984
+ }
2985
+ ae_vector_set_length(&buf3, p, _state);
2986
+ ftcomplexfftplan(p/2, 1, &plan, _state);
2987
+ fftr1dinternaleven(&buf, p, &buf3, &plan, _state);
2988
+ fftr1dinternaleven(&buf2, p, &buf3, &plan, _state);
2989
+ buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0];
2990
+ buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1];
2991
+ for(i=1; i<=p/2-1; i++)
2992
+ {
2993
+ c1.x = buf.ptr.p_double[2*i+0];
2994
+ c1.y = buf.ptr.p_double[2*i+1];
2995
+ c2.x = buf2.ptr.p_double[2*i+0];
2996
+ c2.y = buf2.ptr.p_double[2*i+1];
2997
+ c3 = ae_c_div(c1,c2);
2998
+ buf.ptr.p_double[2*i+0] = c3.x;
2999
+ buf.ptr.p_double[2*i+1] = c3.y;
3000
+ }
3001
+ fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state);
3002
+ rallocv(m-n+1, r, _state);
3003
+ ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-n));
3004
+ ae_frame_leave(_state);
3005
+ }
3006
+
3007
+
3008
+ /*************************************************************************
3009
+ 1-dimensional circular real convolution.
3010
+
3011
+ Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.
3012
+
3013
+ INPUT PARAMETERS
3014
+ S - array[0..M-1] - real signal
3015
+ M - problem size
3016
+ B - array[0..N-1] - real response
3017
+ N - problem size
3018
+
3019
+ OUTPUT PARAMETERS
3020
+ R - convolution: A*B. array[0..M-1].
3021
+
3022
+ NOTE:
3023
+ It is assumed that B is zero at T<0. If it has non-zero values at
3024
+ negative T's, you can still use this subroutine - just shift its result
3025
+ correspondingly.
3026
+
3027
+ NOTE: there is a buffered version of this function, ConvR1DCurcularBuf(),
3028
+ which can reuse space previously allocated in its output parameter R.
3029
+
3030
+ -- ALGLIB --
3031
+ Copyright 21.07.2009 by Bochkanov Sergey
3032
+ *************************************************************************/
3033
+ void convr1dcircular(/* Real */ const ae_vector* s,
3034
+ ae_int_t m,
3035
+ /* Real */ const ae_vector* r,
3036
+ ae_int_t n,
3037
+ /* Real */ ae_vector* c,
3038
+ ae_state *_state)
3039
+ {
3040
+
3041
+ ae_vector_clear(c);
3042
+
3043
+ ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
3044
+ convr1dcircularbuf(s, m, r, n, c, _state);
3045
+ }
3046
+
3047
+
3048
+ /*************************************************************************
3049
+ 1-dimensional circular real convolution, buffered version, which does not
3050
+ reallocate C[] if its length is enough to store the result (i.e. it reuses
3051
+ previously allocated memory as much as possible).
3052
+
3053
+ -- ALGLIB --
3054
+ Copyright 30.11.2023 by Bochkanov Sergey
3055
+ *************************************************************************/
3056
+ void convr1dcircularbuf(/* Real */ const ae_vector* s,
3057
+ ae_int_t m,
3058
+ /* Real */ const ae_vector* r,
3059
+ ae_int_t n,
3060
+ /* Real */ ae_vector* c,
3061
+ ae_state *_state)
3062
+ {
3063
+ ae_frame _frame_block;
3064
+ ae_vector buf;
3065
+ ae_int_t i1;
3066
+ ae_int_t i2;
3067
+ ae_int_t j2;
3068
+
3069
+ ae_frame_make(_state, &_frame_block);
3070
+ memset(&buf, 0, sizeof(buf));
3071
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
3072
+
3073
+ ae_assert(n>0&&m>0, "ConvC1DCircularBuf: incorrect N or M!", _state);
3074
+
3075
+ /*
3076
+ * normalize task: make M>=N,
3077
+ * so A will be longer (at least - not shorter) that B.
3078
+ */
3079
+ if( m<n )
3080
+ {
3081
+ ae_vector_set_length(&buf, m, _state);
3082
+ for(i1=0; i1<=m-1; i1++)
3083
+ {
3084
+ buf.ptr.p_double[i1] = (double)(0);
3085
+ }
3086
+ i1 = 0;
3087
+ while(i1<n)
3088
+ {
3089
+ i2 = ae_minint(i1+m-1, n-1, _state);
3090
+ j2 = i2-i1;
3091
+ ae_v_add(&buf.ptr.p_double[0], 1, &r->ptr.p_double[i1], 1, ae_v_len(0,j2));
3092
+ i1 = i1+m;
3093
+ }
3094
+ convr1dcircularbuf(s, m, &buf, m, c, _state);
3095
+ ae_frame_leave(_state);
3096
+ return;
3097
+ }
3098
+
3099
+ /*
3100
+ * reduce to usual convolution
3101
+ */
3102
+ convr1dx(s, m, r, n, ae_true, -1, 0, c, _state);
3103
+ ae_frame_leave(_state);
3104
+ }
3105
+
3106
+
3107
+ /*************************************************************************
3108
+ 1-dimensional complex deconvolution (inverse of ConvC1D()).
3109
+
3110
+ Algorithm has M*log(M)) complexity for any M (composite or prime).
3111
+
3112
+ INPUT PARAMETERS
3113
+ A - array[0..M-1] - convolved signal, A = conv(R, B)
3114
+ M - convolved signal length
3115
+ B - array[0..N-1] - response
3116
+ N - response length
3117
+
3118
+ OUTPUT PARAMETERS
3119
+ R - deconvolved signal. array[0..M-N].
3120
+
3121
+ NOTE:
3122
+ deconvolution is unstable process and may result in division by zero
3123
+ (if your response function is degenerate, i.e. has zero Fourier coefficient).
3124
+
3125
+ NOTE:
3126
+ It is assumed that B is zero at T<0. If it has non-zero values at
3127
+ negative T's, you can still use this subroutine - just shift its result
3128
+ correspondingly.
3129
+
3130
+ -- ALGLIB --
3131
+ Copyright 21.07.2009 by Bochkanov Sergey
3132
+ *************************************************************************/
3133
+ void convr1dcircularinv(/* Real */ const ae_vector* a,
3134
+ ae_int_t m,
3135
+ /* Real */ const ae_vector* b,
3136
+ ae_int_t n,
3137
+ /* Real */ ae_vector* r,
3138
+ ae_state *_state)
3139
+ {
3140
+
3141
+ ae_vector_clear(r);
3142
+
3143
+ ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state);
3144
+ convr1dcircularinvbuf(a, m, b, n, r, _state);
3145
+ }
3146
+
3147
+
3148
+ /*************************************************************************
3149
+ 1-dimensional complex deconvolution, inverse of ConvR1DCircular().
3150
+
3151
+ Buffered version, which does not reallocate R[] if its length is enough to
3152
+ store the result (i.e. it reuses previously allocated memory as much as
3153
+ possible).
3154
+
3155
+ -- ALGLIB --
3156
+ Copyright 21.07.2009 by Bochkanov Sergey
3157
+ *************************************************************************/
3158
+ void convr1dcircularinvbuf(/* Real */ const ae_vector* a,
3159
+ ae_int_t m,
3160
+ /* Real */ const ae_vector* b,
3161
+ ae_int_t n,
3162
+ /* Real */ ae_vector* r,
3163
+ ae_state *_state)
3164
+ {
3165
+ ae_frame _frame_block;
3166
+ ae_int_t i;
3167
+ ae_int_t i1;
3168
+ ae_int_t i2;
3169
+ ae_int_t j2;
3170
+ ae_vector buf;
3171
+ ae_vector buf2;
3172
+ ae_vector buf3;
3173
+ ae_vector cbuf;
3174
+ ae_vector cbuf2;
3175
+ fasttransformplan plan;
3176
+ ae_complex c1;
3177
+ ae_complex c2;
3178
+ ae_complex c3;
3179
+
3180
+ ae_frame_make(_state, &_frame_block);
3181
+ memset(&buf, 0, sizeof(buf));
3182
+ memset(&buf2, 0, sizeof(buf2));
3183
+ memset(&buf3, 0, sizeof(buf3));
3184
+ memset(&cbuf, 0, sizeof(cbuf));
3185
+ memset(&cbuf2, 0, sizeof(cbuf2));
3186
+ memset(&plan, 0, sizeof(plan));
3187
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
3188
+ ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
3189
+ ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true);
3190
+ ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true);
3191
+ ae_vector_init(&cbuf2, 0, DT_COMPLEX, _state, ae_true);
3192
+ _fasttransformplan_init(&plan, _state, ae_true);
3193
+
3194
+ ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state);
3195
+
3196
+ /*
3197
+ * normalize task: make M>=N,
3198
+ * so A will be longer (at least - not shorter) that B.
3199
+ */
3200
+ if( m<n )
3201
+ {
3202
+ ae_vector_set_length(&buf, m, _state);
3203
+ for(i=0; i<=m-1; i++)
3204
+ {
3205
+ buf.ptr.p_double[i] = (double)(0);
3206
+ }
3207
+ i1 = 0;
3208
+ while(i1<n)
3209
+ {
3210
+ i2 = ae_minint(i1+m-1, n-1, _state);
3211
+ j2 = i2-i1;
3212
+ ae_v_add(&buf.ptr.p_double[0], 1, &b->ptr.p_double[i1], 1, ae_v_len(0,j2));
3213
+ i1 = i1+m;
3214
+ }
3215
+ convr1dcircularinvbuf(a, m, &buf, m, r, _state);
3216
+ ae_frame_leave(_state);
3217
+ return;
3218
+ }
3219
+
3220
+ /*
3221
+ * Task is normalized
3222
+ */
3223
+ if( m%2==0 )
3224
+ {
3225
+
3226
+ /*
3227
+ * size is even, use fast even-size FFT
3228
+ */
3229
+ ae_vector_set_length(&buf, m, _state);
3230
+ ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
3231
+ ae_vector_set_length(&buf2, m, _state);
3232
+ ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
3233
+ for(i=n; i<=m-1; i++)
3234
+ {
3235
+ buf2.ptr.p_double[i] = (double)(0);
3236
+ }
3237
+ ae_vector_set_length(&buf3, m, _state);
3238
+ ftcomplexfftplan(m/2, 1, &plan, _state);
3239
+ fftr1dinternaleven(&buf, m, &buf3, &plan, _state);
3240
+ fftr1dinternaleven(&buf2, m, &buf3, &plan, _state);
3241
+ buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0];
3242
+ buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1];
3243
+ for(i=1; i<=m/2-1; i++)
3244
+ {
3245
+ c1.x = buf.ptr.p_double[2*i+0];
3246
+ c1.y = buf.ptr.p_double[2*i+1];
3247
+ c2.x = buf2.ptr.p_double[2*i+0];
3248
+ c2.y = buf2.ptr.p_double[2*i+1];
3249
+ c3 = ae_c_div(c1,c2);
3250
+ buf.ptr.p_double[2*i+0] = c3.x;
3251
+ buf.ptr.p_double[2*i+1] = c3.y;
3252
+ }
3253
+ fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state);
3254
+ rallocv(m, r, _state);
3255
+ ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1));
3256
+ }
3257
+ else
3258
+ {
3259
+
3260
+ /*
3261
+ * odd-size, use general real FFT
3262
+ */
3263
+ fftr1d(a, m, &cbuf, _state);
3264
+ ae_vector_set_length(&buf2, m, _state);
3265
+ ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
3266
+ for(i=n; i<=m-1; i++)
3267
+ {
3268
+ buf2.ptr.p_double[i] = (double)(0);
3269
+ }
3270
+ fftr1d(&buf2, m, &cbuf2, _state);
3271
+ for(i=0; i<=ae_ifloor((double)m/(double)2, _state); i++)
3272
+ {
3273
+ cbuf.ptr.p_complex[i] = ae_c_div(cbuf.ptr.p_complex[i],cbuf2.ptr.p_complex[i]);
3274
+ }
3275
+ fftr1dinvbuf(&cbuf, m, r, _state);
3276
+ }
3277
+ ae_frame_leave(_state);
3278
+ }
3279
+
3280
+
3281
+ /*************************************************************************
3282
+ 1-dimensional complex convolution.
3283
+
3284
+ Extended subroutine which allows to choose convolution algorithm.
3285
+ Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular().
3286
+
3287
+ INPUT PARAMETERS
3288
+ A - array[0..M-1] - complex function to be transformed
3289
+ M - problem size
3290
+ B - array[0..N-1] - complex function to be transformed
3291
+ N - problem size, N<=M
3292
+ Alg - algorithm type:
3293
+ *-2 auto-select Q for overlap-add
3294
+ *-1 auto-select algorithm and parameters
3295
+ * 0 straightforward formula for small N's
3296
+ * 1 general FFT-based code
3297
+ * 2 overlap-add with length Q
3298
+ Q - length for overlap-add
3299
+
3300
+ OUTPUT PARAMETERS
3301
+ R - convolution: A*B. array[0..N+M-1].
3302
+
3303
+ -- ALGLIB --
3304
+ Copyright 21.07.2009 by Bochkanov Sergey
3305
+ *************************************************************************/
3306
+ void convc1dx(/* Complex */ const ae_vector* a,
3307
+ ae_int_t m,
3308
+ /* Complex */ const ae_vector* b,
3309
+ ae_int_t n,
3310
+ ae_bool circular,
3311
+ ae_int_t alg,
3312
+ ae_int_t q,
3313
+ /* Complex */ ae_vector* r,
3314
+ ae_state *_state)
3315
+ {
3316
+ ae_frame _frame_block;
3317
+ ae_int_t i;
3318
+ ae_int_t j;
3319
+ ae_int_t p;
3320
+ ae_int_t ptotal;
3321
+ ae_int_t i1;
3322
+ ae_int_t i2;
3323
+ ae_int_t j1;
3324
+ ae_int_t j2;
3325
+ ae_vector bbuf;
3326
+ ae_complex v;
3327
+ double ax;
3328
+ double ay;
3329
+ double bx;
3330
+ double by;
3331
+ double t;
3332
+ double tx;
3333
+ double ty;
3334
+ double flopcand;
3335
+ double flopbest;
3336
+ ae_int_t algbest;
3337
+ fasttransformplan plan;
3338
+ ae_vector buf;
3339
+ ae_vector buf2;
3340
+
3341
+ ae_frame_make(_state, &_frame_block);
3342
+ memset(&bbuf, 0, sizeof(bbuf));
3343
+ memset(&plan, 0, sizeof(plan));
3344
+ memset(&buf, 0, sizeof(buf));
3345
+ memset(&buf2, 0, sizeof(buf2));
3346
+ ae_vector_init(&bbuf, 0, DT_COMPLEX, _state, ae_true);
3347
+ _fasttransformplan_init(&plan, _state, ae_true);
3348
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
3349
+ ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
3350
+
3351
+ ae_assert(n>0&&m>0, "ConvC1DX: incorrect N or M!", _state);
3352
+ ae_assert(n<=m, "ConvC1DX: N<M assumption is false!", _state);
3353
+
3354
+ /*
3355
+ * Auto-select
3356
+ */
3357
+ if( alg==-1||alg==-2 )
3358
+ {
3359
+
3360
+ /*
3361
+ * Initial candidate: straightforward implementation.
3362
+ *
3363
+ * If we want to use auto-fitted overlap-add,
3364
+ * flop count is initialized by large real number - to force
3365
+ * another algorithm selection
3366
+ */
3367
+ algbest = 0;
3368
+ if( alg==-1 )
3369
+ {
3370
+ flopbest = (double)(2*m*n);
3371
+ }
3372
+ else
3373
+ {
3374
+ flopbest = ae_maxrealnumber;
3375
+ }
3376
+
3377
+ /*
3378
+ * Another candidate - generic FFT code
3379
+ */
3380
+ if( alg==-1 )
3381
+ {
3382
+ if( circular&&ftbaseissmooth(m, _state) )
3383
+ {
3384
+
3385
+ /*
3386
+ * special code for circular convolution of a sequence with a smooth length
3387
+ */
3388
+ flopcand = (double)3*ftbasegetflopestimate(m, _state)+(double)(6*m);
3389
+ if( ae_fp_less(flopcand,flopbest) )
3390
+ {
3391
+ algbest = 1;
3392
+ flopbest = flopcand;
3393
+ }
3394
+ }
3395
+ else
3396
+ {
3397
+
3398
+ /*
3399
+ * general cyclic/non-cyclic convolution
3400
+ */
3401
+ p = ftbasefindsmooth(m+n-1, _state);
3402
+ flopcand = (double)3*ftbasegetflopestimate(p, _state)+(double)(6*p);
3403
+ if( ae_fp_less(flopcand,flopbest) )
3404
+ {
3405
+ algbest = 1;
3406
+ flopbest = flopcand;
3407
+ }
3408
+ }
3409
+ }
3410
+
3411
+ /*
3412
+ * Another candidate - overlap-add
3413
+ */
3414
+ q = 1;
3415
+ ptotal = 1;
3416
+ while(ptotal<n)
3417
+ {
3418
+ ptotal = ptotal*2;
3419
+ }
3420
+ while(ptotal<=m+n-1)
3421
+ {
3422
+ p = ptotal-n+1;
3423
+ flopcand = (double)ae_iceil((double)m/(double)p, _state)*((double)2*ftbasegetflopestimate(ptotal, _state)+(double)(8*ptotal));
3424
+ if( ae_fp_less(flopcand,flopbest) )
3425
+ {
3426
+ flopbest = flopcand;
3427
+ algbest = 2;
3428
+ q = p;
3429
+ }
3430
+ ptotal = ptotal*2;
3431
+ }
3432
+ alg = algbest;
3433
+ convc1dx(a, m, b, n, circular, alg, q, r, _state);
3434
+ ae_frame_leave(_state);
3435
+ return;
3436
+ }
3437
+
3438
+ /*
3439
+ * straightforward formula for
3440
+ * circular and non-circular convolutions.
3441
+ *
3442
+ * Very simple code, no further comments needed.
3443
+ */
3444
+ if( alg==0 )
3445
+ {
3446
+
3447
+ /*
3448
+ * Special case: N=1
3449
+ */
3450
+ if( n==1 )
3451
+ {
3452
+ callocv(m, r, _state);
3453
+ v = b->ptr.p_complex[0];
3454
+ ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v);
3455
+ ae_frame_leave(_state);
3456
+ return;
3457
+ }
3458
+
3459
+ /*
3460
+ * use straightforward formula
3461
+ */
3462
+ if( circular )
3463
+ {
3464
+
3465
+ /*
3466
+ * circular convolution
3467
+ */
3468
+ callocv(m, r, _state);
3469
+ v = b->ptr.p_complex[0];
3470
+ ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v);
3471
+ for(i=1; i<=n-1; i++)
3472
+ {
3473
+ v = b->ptr.p_complex[i];
3474
+ i1 = 0;
3475
+ i2 = i-1;
3476
+ j1 = m-i;
3477
+ j2 = m-1;
3478
+ ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v);
3479
+ i1 = i;
3480
+ i2 = m-1;
3481
+ j1 = 0;
3482
+ j2 = m-i-1;
3483
+ ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v);
3484
+ }
3485
+ }
3486
+ else
3487
+ {
3488
+
3489
+ /*
3490
+ * non-circular convolution
3491
+ */
3492
+ callocv(m+n-1, r, _state);
3493
+ for(i=0; i<=m+n-2; i++)
3494
+ {
3495
+ r->ptr.p_complex[i] = ae_complex_from_i(0);
3496
+ }
3497
+ for(i=0; i<=n-1; i++)
3498
+ {
3499
+ v = b->ptr.p_complex[i];
3500
+ ae_v_caddc(&r->ptr.p_complex[i], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(i,i+m-1), v);
3501
+ }
3502
+ }
3503
+ ae_frame_leave(_state);
3504
+ return;
3505
+ }
3506
+
3507
+ /*
3508
+ * general FFT-based code for
3509
+ * circular and non-circular convolutions.
3510
+ *
3511
+ * First, if convolution is circular, we test whether M is smooth or not.
3512
+ * If it is smooth, we just use M-length FFT to calculate convolution.
3513
+ * If it is not, we calculate non-circular convolution and wrap it arount.
3514
+ *
3515
+ * IF convolution is non-circular, we use zero-padding + FFT.
3516
+ */
3517
+ if( alg==1 )
3518
+ {
3519
+ if( circular&&ftbaseissmooth(m, _state) )
3520
+ {
3521
+
3522
+ /*
3523
+ * special code for circular convolution with smooth M
3524
+ */
3525
+ ftcomplexfftplan(m, 1, &plan, _state);
3526
+ ae_vector_set_length(&buf, 2*m, _state);
3527
+ for(i=0; i<=m-1; i++)
3528
+ {
3529
+ buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
3530
+ buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
3531
+ }
3532
+ ae_vector_set_length(&buf2, 2*m, _state);
3533
+ for(i=0; i<=n-1; i++)
3534
+ {
3535
+ buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
3536
+ buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
3537
+ }
3538
+ for(i=n; i<=m-1; i++)
3539
+ {
3540
+ buf2.ptr.p_double[2*i+0] = (double)(0);
3541
+ buf2.ptr.p_double[2*i+1] = (double)(0);
3542
+ }
3543
+ ftapplyplan(&plan, &buf, 0, 1, _state);
3544
+ ftapplyplan(&plan, &buf2, 0, 1, _state);
3545
+ for(i=0; i<=m-1; i++)
3546
+ {
3547
+ ax = buf.ptr.p_double[2*i+0];
3548
+ ay = buf.ptr.p_double[2*i+1];
3549
+ bx = buf2.ptr.p_double[2*i+0];
3550
+ by = buf2.ptr.p_double[2*i+1];
3551
+ tx = ax*bx-ay*by;
3552
+ ty = ax*by+ay*bx;
3553
+ buf.ptr.p_double[2*i+0] = tx;
3554
+ buf.ptr.p_double[2*i+1] = -ty;
3555
+ }
3556
+ ftapplyplan(&plan, &buf, 0, 1, _state);
3557
+ t = (double)1/(double)m;
3558
+ callocv(m, r, _state);
3559
+ for(i=0; i<=m-1; i++)
3560
+ {
3561
+ r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
3562
+ r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
3563
+ }
3564
+ }
3565
+ else
3566
+ {
3567
+
3568
+ /*
3569
+ * M is non-smooth, general code (circular/non-circular):
3570
+ * * first part is the same for circular and non-circular
3571
+ * convolutions. zero padding, FFTs, inverse FFTs
3572
+ * * second part differs:
3573
+ * * for non-circular convolution we just copy array
3574
+ * * for circular convolution we add array tail to its head
3575
+ */
3576
+ p = ftbasefindsmooth(m+n-1, _state);
3577
+ ftcomplexfftplan(p, 1, &plan, _state);
3578
+ ae_vector_set_length(&buf, 2*p, _state);
3579
+ for(i=0; i<=m-1; i++)
3580
+ {
3581
+ buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
3582
+ buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
3583
+ }
3584
+ for(i=m; i<=p-1; i++)
3585
+ {
3586
+ buf.ptr.p_double[2*i+0] = (double)(0);
3587
+ buf.ptr.p_double[2*i+1] = (double)(0);
3588
+ }
3589
+ ae_vector_set_length(&buf2, 2*p, _state);
3590
+ for(i=0; i<=n-1; i++)
3591
+ {
3592
+ buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
3593
+ buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
3594
+ }
3595
+ for(i=n; i<=p-1; i++)
3596
+ {
3597
+ buf2.ptr.p_double[2*i+0] = (double)(0);
3598
+ buf2.ptr.p_double[2*i+1] = (double)(0);
3599
+ }
3600
+ ftapplyplan(&plan, &buf, 0, 1, _state);
3601
+ ftapplyplan(&plan, &buf2, 0, 1, _state);
3602
+ for(i=0; i<=p-1; i++)
3603
+ {
3604
+ ax = buf.ptr.p_double[2*i+0];
3605
+ ay = buf.ptr.p_double[2*i+1];
3606
+ bx = buf2.ptr.p_double[2*i+0];
3607
+ by = buf2.ptr.p_double[2*i+1];
3608
+ tx = ax*bx-ay*by;
3609
+ ty = ax*by+ay*bx;
3610
+ buf.ptr.p_double[2*i+0] = tx;
3611
+ buf.ptr.p_double[2*i+1] = -ty;
3612
+ }
3613
+ ftapplyplan(&plan, &buf, 0, 1, _state);
3614
+ t = (double)1/(double)p;
3615
+ if( circular )
3616
+ {
3617
+
3618
+ /*
3619
+ * circular, add tail to head
3620
+ */
3621
+ callocv(m, r, _state);
3622
+ for(i=0; i<=m-1; i++)
3623
+ {
3624
+ r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
3625
+ r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
3626
+ }
3627
+ for(i=m; i<=m+n-2; i++)
3628
+ {
3629
+ r->ptr.p_complex[i-m].x = r->ptr.p_complex[i-m].x+t*buf.ptr.p_double[2*i+0];
3630
+ r->ptr.p_complex[i-m].y = r->ptr.p_complex[i-m].y-t*buf.ptr.p_double[2*i+1];
3631
+ }
3632
+ }
3633
+ else
3634
+ {
3635
+
3636
+ /*
3637
+ * non-circular, just copy
3638
+ */
3639
+ callocv(m+n-1, r, _state);
3640
+ for(i=0; i<=m+n-2; i++)
3641
+ {
3642
+ r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
3643
+ r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
3644
+ }
3645
+ }
3646
+ }
3647
+ ae_frame_leave(_state);
3648
+ return;
3649
+ }
3650
+
3651
+ /*
3652
+ * overlap-add method for
3653
+ * circular and non-circular convolutions.
3654
+ *
3655
+ * First part of code (separate FFTs of input blocks) is the same
3656
+ * for all types of convolution. Second part (overlapping outputs)
3657
+ * differs for different types of convolution. We just copy output
3658
+ * when convolution is non-circular. We wrap it around, if it is
3659
+ * circular.
3660
+ */
3661
+ if( alg==2 )
3662
+ {
3663
+ ae_vector_set_length(&buf, 2*(q+n-1), _state);
3664
+
3665
+ /*
3666
+ * prepare R
3667
+ */
3668
+ if( circular )
3669
+ {
3670
+ callocv(m, r, _state);
3671
+ for(i=0; i<=m-1; i++)
3672
+ {
3673
+ r->ptr.p_complex[i] = ae_complex_from_i(0);
3674
+ }
3675
+ }
3676
+ else
3677
+ {
3678
+ callocv(m+n-1, r, _state);
3679
+ for(i=0; i<=m+n-2; i++)
3680
+ {
3681
+ r->ptr.p_complex[i] = ae_complex_from_i(0);
3682
+ }
3683
+ }
3684
+
3685
+ /*
3686
+ * pre-calculated FFT(B)
3687
+ */
3688
+ ae_vector_set_length(&bbuf, q+n-1, _state);
3689
+ ae_v_cmove(&bbuf.ptr.p_complex[0], 1, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1));
3690
+ for(j=n; j<=q+n-2; j++)
3691
+ {
3692
+ bbuf.ptr.p_complex[j] = ae_complex_from_i(0);
3693
+ }
3694
+ fftc1d(&bbuf, q+n-1, _state);
3695
+
3696
+ /*
3697
+ * prepare FFT plan for chunks of A
3698
+ */
3699
+ ftcomplexfftplan(q+n-1, 1, &plan, _state);
3700
+
3701
+ /*
3702
+ * main overlap-add cycle
3703
+ */
3704
+ i = 0;
3705
+ while(i<=m-1)
3706
+ {
3707
+ p = ae_minint(q, m-i, _state);
3708
+ for(j=0; j<=p-1; j++)
3709
+ {
3710
+ buf.ptr.p_double[2*j+0] = a->ptr.p_complex[i+j].x;
3711
+ buf.ptr.p_double[2*j+1] = a->ptr.p_complex[i+j].y;
3712
+ }
3713
+ for(j=p; j<=q+n-2; j++)
3714
+ {
3715
+ buf.ptr.p_double[2*j+0] = (double)(0);
3716
+ buf.ptr.p_double[2*j+1] = (double)(0);
3717
+ }
3718
+ ftapplyplan(&plan, &buf, 0, 1, _state);
3719
+ for(j=0; j<=q+n-2; j++)
3720
+ {
3721
+ ax = buf.ptr.p_double[2*j+0];
3722
+ ay = buf.ptr.p_double[2*j+1];
3723
+ bx = bbuf.ptr.p_complex[j].x;
3724
+ by = bbuf.ptr.p_complex[j].y;
3725
+ tx = ax*bx-ay*by;
3726
+ ty = ax*by+ay*bx;
3727
+ buf.ptr.p_double[2*j+0] = tx;
3728
+ buf.ptr.p_double[2*j+1] = -ty;
3729
+ }
3730
+ ftapplyplan(&plan, &buf, 0, 1, _state);
3731
+ t = (double)1/(double)(q+n-1);
3732
+ if( circular )
3733
+ {
3734
+ j1 = ae_minint(i+p+n-2, m-1, _state)-i;
3735
+ j2 = j1+1;
3736
+ }
3737
+ else
3738
+ {
3739
+ j1 = p+n-2;
3740
+ j2 = j1+1;
3741
+ }
3742
+ for(j=0; j<=j1; j++)
3743
+ {
3744
+ r->ptr.p_complex[i+j].x = r->ptr.p_complex[i+j].x+buf.ptr.p_double[2*j+0]*t;
3745
+ r->ptr.p_complex[i+j].y = r->ptr.p_complex[i+j].y-buf.ptr.p_double[2*j+1]*t;
3746
+ }
3747
+ for(j=j2; j<=p+n-2; j++)
3748
+ {
3749
+ r->ptr.p_complex[j-j2].x = r->ptr.p_complex[j-j2].x+buf.ptr.p_double[2*j+0]*t;
3750
+ r->ptr.p_complex[j-j2].y = r->ptr.p_complex[j-j2].y-buf.ptr.p_double[2*j+1]*t;
3751
+ }
3752
+ i = i+p;
3753
+ }
3754
+ ae_frame_leave(_state);
3755
+ return;
3756
+ }
3757
+ ae_frame_leave(_state);
3758
+ }
3759
+
3760
+
3761
+ /*************************************************************************
3762
+ 1-dimensional real convolution.
3763
+
3764
+ Extended subroutine which allows to choose convolution algorithm.
3765
+ Intended for internal use, ALGLIB users should call ConvR1D().
3766
+
3767
+ INPUT PARAMETERS
3768
+ A - array[0..M-1] - complex function to be transformed
3769
+ M - problem size
3770
+ B - array[0..N-1] - complex function to be transformed
3771
+ N - problem size, N<=M
3772
+ Alg - algorithm type:
3773
+ *-2 auto-select Q for overlap-add
3774
+ *-1 auto-select algorithm and parameters
3775
+ * 0 straightforward formula for small N's
3776
+ * 1 general FFT-based code
3777
+ * 2 overlap-add with length Q
3778
+ Q - length for overlap-add
3779
+
3780
+ OUTPUT PARAMETERS
3781
+ R - convolution: A*B. array[0..N+M-1].
3782
+
3783
+ -- ALGLIB --
3784
+ Copyright 21.07.2009 by Bochkanov Sergey
3785
+ *************************************************************************/
3786
+ void convr1dx(/* Real */ const ae_vector* a,
3787
+ ae_int_t m,
3788
+ /* Real */ const ae_vector* b,
3789
+ ae_int_t n,
3790
+ ae_bool circular,
3791
+ ae_int_t alg,
3792
+ ae_int_t q,
3793
+ /* Real */ ae_vector* r,
3794
+ ae_state *_state)
3795
+ {
3796
+ ae_frame _frame_block;
3797
+ double v;
3798
+ ae_int_t i;
3799
+ ae_int_t j;
3800
+ ae_int_t p;
3801
+ ae_int_t ptotal;
3802
+ ae_int_t i1;
3803
+ ae_int_t i2;
3804
+ ae_int_t j1;
3805
+ ae_int_t j2;
3806
+ double ax;
3807
+ double ay;
3808
+ double bx;
3809
+ double by;
3810
+ double tx;
3811
+ double ty;
3812
+ double flopcand;
3813
+ double flopbest;
3814
+ ae_int_t algbest;
3815
+ fasttransformplan plan;
3816
+ ae_vector buf;
3817
+ ae_vector buf2;
3818
+ ae_vector buf3;
3819
+
3820
+ ae_frame_make(_state, &_frame_block);
3821
+ memset(&plan, 0, sizeof(plan));
3822
+ memset(&buf, 0, sizeof(buf));
3823
+ memset(&buf2, 0, sizeof(buf2));
3824
+ memset(&buf3, 0, sizeof(buf3));
3825
+ _fasttransformplan_init(&plan, _state, ae_true);
3826
+ ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
3827
+ ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
3828
+ ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true);
3829
+
3830
+ ae_assert(n>0&&m>0, "ConvR1DX: incorrect N or M!", _state);
3831
+ ae_assert(n<=m, "ConvR1DX: N<M assumption is false!", _state);
3832
+
3833
+ /*
3834
+ * handle special cases
3835
+ */
3836
+ if( ae_minint(m, n, _state)<=2 )
3837
+ {
3838
+ alg = 0;
3839
+ }
3840
+
3841
+ /*
3842
+ * Auto-select
3843
+ */
3844
+ if( alg<0 )
3845
+ {
3846
+
3847
+ /*
3848
+ * Initial candidate: straightforward implementation.
3849
+ *
3850
+ * If we want to use auto-fitted overlap-add,
3851
+ * flop count is initialized by large real number - to force
3852
+ * another algorithm selection
3853
+ */
3854
+ algbest = 0;
3855
+ if( alg==-1 )
3856
+ {
3857
+ flopbest = 0.15*(double)m*(double)n;
3858
+ }
3859
+ else
3860
+ {
3861
+ flopbest = ae_maxrealnumber;
3862
+ }
3863
+
3864
+ /*
3865
+ * Another candidate - generic FFT code
3866
+ */
3867
+ if( alg==-1 )
3868
+ {
3869
+ if( (circular&&ftbaseissmooth(m, _state))&&m%2==0 )
3870
+ {
3871
+
3872
+ /*
3873
+ * special code for circular convolution of a sequence with a smooth length
3874
+ */
3875
+ flopcand = (double)3*ftbasegetflopestimate(m/2, _state)+(double)(6*m)/(double)2;
3876
+ if( ae_fp_less(flopcand,flopbest) )
3877
+ {
3878
+ algbest = 1;
3879
+ flopbest = flopcand;
3880
+ }
3881
+ }
3882
+ else
3883
+ {
3884
+
3885
+ /*
3886
+ * general cyclic/non-cyclic convolution
3887
+ */
3888
+ p = ftbasefindsmootheven(m+n-1, _state);
3889
+ flopcand = (double)3*ftbasegetflopestimate(p/2, _state)+(double)(6*p)/(double)2;
3890
+ if( ae_fp_less(flopcand,flopbest) )
3891
+ {
3892
+ algbest = 1;
3893
+ flopbest = flopcand;
3894
+ }
3895
+ }
3896
+ }
3897
+
3898
+ /*
3899
+ * Another candidate - overlap-add
3900
+ */
3901
+ q = 1;
3902
+ ptotal = 1;
3903
+ while(ptotal<n)
3904
+ {
3905
+ ptotal = ptotal*2;
3906
+ }
3907
+ while(ptotal<=m+n-1)
3908
+ {
3909
+ p = ptotal-n+1;
3910
+ flopcand = (double)ae_iceil((double)m/(double)p, _state)*((double)2*ftbasegetflopestimate(ptotal/2, _state)+(double)(1*(ptotal/2)));
3911
+ if( ae_fp_less(flopcand,flopbest) )
3912
+ {
3913
+ flopbest = flopcand;
3914
+ algbest = 2;
3915
+ q = p;
3916
+ }
3917
+ ptotal = ptotal*2;
3918
+ }
3919
+ alg = algbest;
3920
+ convr1dx(a, m, b, n, circular, alg, q, r, _state);
3921
+ ae_frame_leave(_state);
3922
+ return;
3923
+ }
3924
+
3925
+ /*
3926
+ * straightforward formula for
3927
+ * circular and non-circular convolutions.
3928
+ *
3929
+ * Very simple code, no further comments needed.
3930
+ */
3931
+ if( alg==0 )
3932
+ {
3933
+
3934
+ /*
3935
+ * Special case: N=1
3936
+ */
3937
+ if( n==1 )
3938
+ {
3939
+ rallocv(m, r, _state);
3940
+ v = b->ptr.p_double[0];
3941
+ ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v);
3942
+ ae_frame_leave(_state);
3943
+ return;
3944
+ }
3945
+
3946
+ /*
3947
+ * use straightforward formula
3948
+ */
3949
+ if( circular )
3950
+ {
3951
+
3952
+ /*
3953
+ * circular convolution
3954
+ */
3955
+ rallocv(m, r, _state);
3956
+ v = b->ptr.p_double[0];
3957
+ ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v);
3958
+ for(i=1; i<=n-1; i++)
3959
+ {
3960
+ v = b->ptr.p_double[i];
3961
+ i1 = 0;
3962
+ i2 = i-1;
3963
+ j1 = m-i;
3964
+ j2 = m-1;
3965
+ ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v);
3966
+ i1 = i;
3967
+ i2 = m-1;
3968
+ j1 = 0;
3969
+ j2 = m-i-1;
3970
+ ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v);
3971
+ }
3972
+ }
3973
+ else
3974
+ {
3975
+
3976
+ /*
3977
+ * non-circular convolution
3978
+ */
3979
+ rallocv(m+n-1, r, _state);
3980
+ for(i=0; i<=m+n-2; i++)
3981
+ {
3982
+ r->ptr.p_double[i] = (double)(0);
3983
+ }
3984
+ for(i=0; i<=n-1; i++)
3985
+ {
3986
+ v = b->ptr.p_double[i];
3987
+ ae_v_addd(&r->ptr.p_double[i], 1, &a->ptr.p_double[0], 1, ae_v_len(i,i+m-1), v);
3988
+ }
3989
+ }
3990
+ ae_frame_leave(_state);
3991
+ return;
3992
+ }
3993
+
3994
+ /*
3995
+ * general FFT-based code for
3996
+ * circular and non-circular convolutions.
3997
+ *
3998
+ * First, if convolution is circular, we test whether M is smooth or not.
3999
+ * If it is smooth, we just use M-length FFT to calculate convolution.
4000
+ * If it is not, we calculate non-circular convolution and wrap it arount.
4001
+ *
4002
+ * If convolution is non-circular, we use zero-padding + FFT.
4003
+ *
4004
+ * We assume that M+N-1>2 - we should call small case code otherwise
4005
+ */
4006
+ if( alg==1 )
4007
+ {
4008
+ ae_assert(m+n-1>2, "ConvR1DX: internal error!", _state);
4009
+ if( (circular&&ftbaseissmooth(m, _state))&&m%2==0 )
4010
+ {
4011
+
4012
+ /*
4013
+ * special code for circular convolution with smooth even M
4014
+ */
4015
+ ae_vector_set_length(&buf, m, _state);
4016
+ ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
4017
+ ae_vector_set_length(&buf2, m, _state);
4018
+ ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
4019
+ for(i=n; i<=m-1; i++)
4020
+ {
4021
+ buf2.ptr.p_double[i] = (double)(0);
4022
+ }
4023
+ ae_vector_set_length(&buf3, m, _state);
4024
+ ftcomplexfftplan(m/2, 1, &plan, _state);
4025
+ fftr1dinternaleven(&buf, m, &buf3, &plan, _state);
4026
+ fftr1dinternaleven(&buf2, m, &buf3, &plan, _state);
4027
+ buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0];
4028
+ buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1];
4029
+ for(i=1; i<=m/2-1; i++)
4030
+ {
4031
+ ax = buf.ptr.p_double[2*i+0];
4032
+ ay = buf.ptr.p_double[2*i+1];
4033
+ bx = buf2.ptr.p_double[2*i+0];
4034
+ by = buf2.ptr.p_double[2*i+1];
4035
+ tx = ax*bx-ay*by;
4036
+ ty = ax*by+ay*bx;
4037
+ buf.ptr.p_double[2*i+0] = tx;
4038
+ buf.ptr.p_double[2*i+1] = ty;
4039
+ }
4040
+ fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state);
4041
+ rallocv(m, r, _state);
4042
+ ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1));
4043
+ }
4044
+ else
4045
+ {
4046
+
4047
+ /*
4048
+ * M is non-smooth or non-even, general code (circular/non-circular):
4049
+ * * first part is the same for circular and non-circular
4050
+ * convolutions. zero padding, FFTs, inverse FFTs
4051
+ * * second part differs:
4052
+ * * for non-circular convolution we just copy array
4053
+ * * for circular convolution we add array tail to its head
4054
+ */
4055
+ p = ftbasefindsmootheven(m+n-1, _state);
4056
+ ae_vector_set_length(&buf, p, _state);
4057
+ ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
4058
+ for(i=m; i<=p-1; i++)
4059
+ {
4060
+ buf.ptr.p_double[i] = (double)(0);
4061
+ }
4062
+ ae_vector_set_length(&buf2, p, _state);
4063
+ ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
4064
+ for(i=n; i<=p-1; i++)
4065
+ {
4066
+ buf2.ptr.p_double[i] = (double)(0);
4067
+ }
4068
+ ae_vector_set_length(&buf3, p, _state);
4069
+ ftcomplexfftplan(p/2, 1, &plan, _state);
4070
+ fftr1dinternaleven(&buf, p, &buf3, &plan, _state);
4071
+ fftr1dinternaleven(&buf2, p, &buf3, &plan, _state);
4072
+ buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0];
4073
+ buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1];
4074
+ for(i=1; i<=p/2-1; i++)
4075
+ {
4076
+ ax = buf.ptr.p_double[2*i+0];
4077
+ ay = buf.ptr.p_double[2*i+1];
4078
+ bx = buf2.ptr.p_double[2*i+0];
4079
+ by = buf2.ptr.p_double[2*i+1];
4080
+ tx = ax*bx-ay*by;
4081
+ ty = ax*by+ay*bx;
4082
+ buf.ptr.p_double[2*i+0] = tx;
4083
+ buf.ptr.p_double[2*i+1] = ty;
4084
+ }
4085
+ fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state);
4086
+ if( circular )
4087
+ {
4088
+
4089
+ /*
4090
+ * circular, add tail to head
4091
+ */
4092
+ rallocv(m, r, _state);
4093
+ ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1));
4094
+ if( n>=2 )
4095
+ {
4096
+ ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[m], 1, ae_v_len(0,n-2));
4097
+ }
4098
+ }
4099
+ else
4100
+ {
4101
+
4102
+ /*
4103
+ * non-circular, just copy
4104
+ */
4105
+ rallocv(m+n-1, r, _state);
4106
+ ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m+n-2));
4107
+ }
4108
+ }
4109
+ ae_frame_leave(_state);
4110
+ return;
4111
+ }
4112
+
4113
+ /*
4114
+ * overlap-add method
4115
+ */
4116
+ if( alg==2 )
4117
+ {
4118
+ ae_assert((q+n-1)%2==0, "ConvR1DX: internal error!", _state);
4119
+ ae_vector_set_length(&buf, q+n-1, _state);
4120
+ ae_vector_set_length(&buf2, q+n-1, _state);
4121
+ ae_vector_set_length(&buf3, q+n-1, _state);
4122
+ ftcomplexfftplan((q+n-1)/2, 1, &plan, _state);
4123
+
4124
+ /*
4125
+ * prepare R
4126
+ */
4127
+ if( circular )
4128
+ {
4129
+ rallocv(m, r, _state);
4130
+ for(i=0; i<=m-1; i++)
4131
+ {
4132
+ r->ptr.p_double[i] = (double)(0);
4133
+ }
4134
+ }
4135
+ else
4136
+ {
4137
+ rallocv(m+n-1, r, _state);
4138
+ for(i=0; i<=m+n-2; i++)
4139
+ {
4140
+ r->ptr.p_double[i] = (double)(0);
4141
+ }
4142
+ }
4143
+
4144
+ /*
4145
+ * pre-calculated FFT(B)
4146
+ */
4147
+ ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
4148
+ for(j=n; j<=q+n-2; j++)
4149
+ {
4150
+ buf2.ptr.p_double[j] = (double)(0);
4151
+ }
4152
+ fftr1dinternaleven(&buf2, q+n-1, &buf3, &plan, _state);
4153
+
4154
+ /*
4155
+ * main overlap-add cycle
4156
+ */
4157
+ i = 0;
4158
+ while(i<=m-1)
4159
+ {
4160
+ p = ae_minint(q, m-i, _state);
4161
+ ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[i], 1, ae_v_len(0,p-1));
4162
+ for(j=p; j<=q+n-2; j++)
4163
+ {
4164
+ buf.ptr.p_double[j] = (double)(0);
4165
+ }
4166
+ fftr1dinternaleven(&buf, q+n-1, &buf3, &plan, _state);
4167
+ buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0];
4168
+ buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1];
4169
+ for(j=1; j<=(q+n-1)/2-1; j++)
4170
+ {
4171
+ ax = buf.ptr.p_double[2*j+0];
4172
+ ay = buf.ptr.p_double[2*j+1];
4173
+ bx = buf2.ptr.p_double[2*j+0];
4174
+ by = buf2.ptr.p_double[2*j+1];
4175
+ tx = ax*bx-ay*by;
4176
+ ty = ax*by+ay*bx;
4177
+ buf.ptr.p_double[2*j+0] = tx;
4178
+ buf.ptr.p_double[2*j+1] = ty;
4179
+ }
4180
+ fftr1dinvinternaleven(&buf, q+n-1, &buf3, &plan, _state);
4181
+ if( circular )
4182
+ {
4183
+ j1 = ae_minint(i+p+n-2, m-1, _state)-i;
4184
+ j2 = j1+1;
4185
+ }
4186
+ else
4187
+ {
4188
+ j1 = p+n-2;
4189
+ j2 = j1+1;
4190
+ }
4191
+ ae_v_add(&r->ptr.p_double[i], 1, &buf.ptr.p_double[0], 1, ae_v_len(i,i+j1));
4192
+ if( p+n-2>=j2 )
4193
+ {
4194
+ ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[j2], 1, ae_v_len(0,p+n-2-j2));
4195
+ }
4196
+ i = i+p;
4197
+ }
4198
+ ae_frame_leave(_state);
4199
+ return;
4200
+ }
4201
+ ae_frame_leave(_state);
4202
+ }
4203
+
4204
+
4205
+ #endif
4206
+ #if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD)
4207
+
4208
+
4209
+ /*************************************************************************
4210
+ 1-dimensional complex cross-correlation.
4211
+
4212
+ For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
4213
+
4214
+ Correlation is calculated using reduction to convolution. Algorithm with
4215
+ max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
4216
+ about performance).
4217
+
4218
+ IMPORTANT:
4219
+ for historical reasons subroutine accepts its parameters in reversed
4220
+ order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional
4221
+ definition of cross-correlation, denoting cross-correlation as "x").
4222
+
4223
+ INPUT PARAMETERS
4224
+ Signal - array[0..N-1] - complex function to be transformed,
4225
+ signal containing pattern
4226
+ N - problem size
4227
+ Pattern - array[0..M-1] - complex function to be transformed,
4228
+ pattern to 'search' within a signal
4229
+ M - problem size
4230
+
4231
+ OUTPUT PARAMETERS
4232
+ R - cross-correlation, array[0..N+M-2]:
4233
+ * positive lags are stored in R[0..N-1],
4234
+ R[i] = sum(conj(pattern[j])*signal[i+j]
4235
+ * negative lags are stored in R[N..N+M-2],
4236
+ R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]
4237
+
4238
+ NOTE:
4239
+ It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
4240
+ on [-K..M-1], you can still use this subroutine, just shift result by K.
4241
+
4242
+ NOTE: there is a buffered version of this function, CorrC1DBuf(), which
4243
+ can reuse space previously allocated in its output parameter R.
4244
+
4245
+ -- ALGLIB --
4246
+ Copyright 21.07.2009 by Bochkanov Sergey
4247
+ *************************************************************************/
4248
+ void corrc1d(/* Complex */ const ae_vector* signal,
4249
+ ae_int_t n,
4250
+ /* Complex */ const ae_vector* pattern,
4251
+ ae_int_t m,
4252
+ /* Complex */ ae_vector* r,
4253
+ ae_state *_state)
4254
+ {
4255
+
4256
+ ae_vector_clear(r);
4257
+
4258
+ ae_assert(n>0&&m>0, "CorrC1D: incorrect N or M!", _state);
4259
+ corrc1dbuf(signal, n, pattern, m, r, _state);
4260
+ }
4261
+
4262
+
4263
+ /*************************************************************************
4264
+ 1-dimensional complex cross-correlation, a buffered version of CorrC1D()
4265
+ which does not reallocate R[] if its length is enough to store the result
4266
+ (i.e. it reuses previously allocated memory as much as possible).
4267
+
4268
+ -- ALGLIB --
4269
+ Copyright 21.07.2009 by Bochkanov Sergey
4270
+ *************************************************************************/
4271
+ void corrc1dbuf(/* Complex */ const ae_vector* signal,
4272
+ ae_int_t n,
4273
+ /* Complex */ const ae_vector* pattern,
4274
+ ae_int_t m,
4275
+ /* Complex */ ae_vector* r,
4276
+ ae_state *_state)
4277
+ {
4278
+ ae_frame _frame_block;
4279
+ ae_vector p;
4280
+ ae_vector b;
4281
+ ae_int_t i;
4282
+
4283
+ ae_frame_make(_state, &_frame_block);
4284
+ memset(&p, 0, sizeof(p));
4285
+ memset(&b, 0, sizeof(b));
4286
+ ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true);
4287
+ ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true);
4288
+
4289
+ ae_assert(n>0&&m>0, "CorrC1DBuf: incorrect N or M!", _state);
4290
+ ae_vector_set_length(&p, m, _state);
4291
+ for(i=0; i<=m-1; i++)
4292
+ {
4293
+ p.ptr.p_complex[m-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state);
4294
+ }
4295
+ convc1d(&p, m, signal, n, &b, _state);
4296
+ callocv(m+n-1, r, _state);
4297
+ ae_v_cmove(&r->ptr.p_complex[0], 1, &b.ptr.p_complex[m-1], 1, "N", ae_v_len(0,n-1));
4298
+ if( m+n-2>=n )
4299
+ {
4300
+ ae_v_cmove(&r->ptr.p_complex[n], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(n,m+n-2));
4301
+ }
4302
+ ae_frame_leave(_state);
4303
+ }
4304
+
4305
+
4306
+ /*************************************************************************
4307
+ 1-dimensional circular complex cross-correlation.
4308
+
4309
+ For given Pattern/Signal returns corr(Pattern,Signal) (circular).
4310
+ Algorithm has linearithmic complexity for any M/N.
4311
+
4312
+ IMPORTANT:
4313
+ for historical reasons subroutine accepts its parameters in reversed
4314
+ order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using
4315
+ traditional definition of cross-correlation, denoting cross-correlation
4316
+ as "x").
4317
+
4318
+ INPUT PARAMETERS
4319
+ Signal - array[0..N-1] - complex function to be transformed,
4320
+ periodic signal containing pattern
4321
+ N - problem size
4322
+ Pattern - array[0..M-1] - complex function to be transformed,
4323
+ non-periodic pattern to 'search' within a signal
4324
+ M - problem size
4325
+
4326
+ OUTPUT PARAMETERS
4327
+ R - convolution: A*B. array[0..M-1].
4328
+
4329
+ NOTE: there is a buffered version of this function, CorrC1DCircular(),
4330
+ which can reuse space previously allocated in its output parameter R.
4331
+
4332
+ -- ALGLIB --
4333
+ Copyright 21.07.2009 by Bochkanov Sergey
4334
+ *************************************************************************/
4335
+ void corrc1dcircular(/* Complex */ const ae_vector* signal,
4336
+ ae_int_t m,
4337
+ /* Complex */ const ae_vector* pattern,
4338
+ ae_int_t n,
4339
+ /* Complex */ ae_vector* c,
4340
+ ae_state *_state)
4341
+ {
4342
+ ae_frame _frame_block;
4343
+ ae_vector p;
4344
+ ae_vector b;
4345
+ ae_int_t i1;
4346
+ ae_int_t i2;
4347
+ ae_int_t i;
4348
+ ae_int_t j2;
4349
+
4350
+ ae_frame_make(_state, &_frame_block);
4351
+ memset(&p, 0, sizeof(p));
4352
+ memset(&b, 0, sizeof(b));
4353
+ ae_vector_clear(c);
4354
+ ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true);
4355
+ ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true);
4356
+
4357
+ ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
4358
+
4359
+ /*
4360
+ * normalize task: make M>=N,
4361
+ * so A will be longer (at least - not shorter) that B.
4362
+ */
4363
+ if( m<n )
4364
+ {
4365
+ ae_vector_set_length(&b, m, _state);
4366
+ for(i1=0; i1<=m-1; i1++)
4367
+ {
4368
+ b.ptr.p_complex[i1] = ae_complex_from_i(0);
4369
+ }
4370
+ i1 = 0;
4371
+ while(i1<n)
4372
+ {
4373
+ i2 = ae_minint(i1+m-1, n-1, _state);
4374
+ j2 = i2-i1;
4375
+ ae_v_cadd(&b.ptr.p_complex[0], 1, &pattern->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
4376
+ i1 = i1+m;
4377
+ }
4378
+ corrc1dcircular(signal, m, &b, m, c, _state);
4379
+ ae_frame_leave(_state);
4380
+ return;
4381
+ }
4382
+
4383
+ /*
4384
+ * Task is normalized
4385
+ */
4386
+ ae_vector_set_length(&p, n, _state);
4387
+ for(i=0; i<=n-1; i++)
4388
+ {
4389
+ p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state);
4390
+ }
4391
+ convc1dcircular(signal, m, &p, n, &b, _state);
4392
+ ae_vector_set_length(c, m, _state);
4393
+ ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n));
4394
+ if( m-n+1<=m-1 )
4395
+ {
4396
+ 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));
4397
+ }
4398
+ ae_frame_leave(_state);
4399
+ }
4400
+
4401
+
4402
+ /*************************************************************************
4403
+ 1-dimensional circular complex cross-correlation.
4404
+
4405
+ A buffered function which does not reallocate C[] if its length is enough
4406
+ to store the result (i.e. it reuses previously allocated memory as much as
4407
+ possible).
4408
+
4409
+ -- ALGLIB --
4410
+ Copyright 21.07.2009 by Bochkanov Sergey
4411
+ *************************************************************************/
4412
+ void corrc1dcircularbuf(/* Complex */ const ae_vector* signal,
4413
+ ae_int_t m,
4414
+ /* Complex */ const ae_vector* pattern,
4415
+ ae_int_t n,
4416
+ /* Complex */ ae_vector* c,
4417
+ ae_state *_state)
4418
+ {
4419
+ ae_frame _frame_block;
4420
+ ae_vector p;
4421
+ ae_vector b;
4422
+ ae_int_t i1;
4423
+ ae_int_t i2;
4424
+ ae_int_t i;
4425
+ ae_int_t j2;
4426
+
4427
+ ae_frame_make(_state, &_frame_block);
4428
+ memset(&p, 0, sizeof(p));
4429
+ memset(&b, 0, sizeof(b));
4430
+ ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true);
4431
+ ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true);
4432
+
4433
+ ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
4434
+
4435
+ /*
4436
+ * normalize task: make M>=N,
4437
+ * so A will be longer (at least - not shorter) that B.
4438
+ */
4439
+ if( m<n )
4440
+ {
4441
+ ae_vector_set_length(&b, m, _state);
4442
+ for(i1=0; i1<=m-1; i1++)
4443
+ {
4444
+ b.ptr.p_complex[i1] = ae_complex_from_i(0);
4445
+ }
4446
+ i1 = 0;
4447
+ while(i1<n)
4448
+ {
4449
+ i2 = ae_minint(i1+m-1, n-1, _state);
4450
+ j2 = i2-i1;
4451
+ ae_v_cadd(&b.ptr.p_complex[0], 1, &pattern->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
4452
+ i1 = i1+m;
4453
+ }
4454
+ corrc1dcircularbuf(signal, m, &b, m, c, _state);
4455
+ ae_frame_leave(_state);
4456
+ return;
4457
+ }
4458
+
4459
+ /*
4460
+ * Task is normalized
4461
+ */
4462
+ ae_vector_set_length(&p, n, _state);
4463
+ for(i=0; i<=n-1; i++)
4464
+ {
4465
+ p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state);
4466
+ }
4467
+ convc1dcircular(signal, m, &p, n, &b, _state);
4468
+ callocv(m, c, _state);
4469
+ ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n));
4470
+ if( m-n+1<=m-1 )
4471
+ {
4472
+ 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));
4473
+ }
4474
+ ae_frame_leave(_state);
4475
+ }
4476
+
4477
+
4478
+ /*************************************************************************
4479
+ 1-dimensional real cross-correlation.
4480
+
4481
+ For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
4482
+
4483
+ Correlation is calculated using reduction to convolution. Algorithm with
4484
+ max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
4485
+ about performance).
4486
+
4487
+ IMPORTANT:
4488
+ for historical reasons subroutine accepts its parameters in reversed
4489
+ order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional
4490
+ definition of cross-correlation, denoting cross-correlation as "x").
4491
+
4492
+ INPUT PARAMETERS
4493
+ Signal - array[0..N-1] - real function to be transformed,
4494
+ signal containing pattern
4495
+ N - problem size
4496
+ Pattern - array[0..M-1] - real function to be transformed,
4497
+ pattern to 'search' withing signal
4498
+ M - problem size
4499
+
4500
+ OUTPUT PARAMETERS
4501
+ R - cross-correlation, array[0..N+M-2]:
4502
+ * positive lags are stored in R[0..N-1],
4503
+ R[i] = sum(pattern[j]*signal[i+j]
4504
+ * negative lags are stored in R[N..N+M-2],
4505
+ R[N+M-1-i] = sum(pattern[j]*signal[-i+j]
4506
+
4507
+ NOTE:
4508
+ It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
4509
+ on [-K..M-1], you can still use this subroutine, just shift result by K.
4510
+
4511
+ NOTE: there is a buffered version of this function, CorrR1DBuf(), which
4512
+ can reuse space previously allocated in its output parameter R.
4513
+
4514
+ -- ALGLIB --
4515
+ Copyright 21.07.2009 by Bochkanov Sergey
4516
+ *************************************************************************/
4517
+ void corrr1d(/* Real */ const ae_vector* signal,
4518
+ ae_int_t n,
4519
+ /* Real */ const ae_vector* pattern,
4520
+ ae_int_t m,
4521
+ /* Real */ ae_vector* r,
4522
+ ae_state *_state)
4523
+ {
4524
+
4525
+ ae_vector_clear(r);
4526
+
4527
+ ae_assert(n>0&&m>0, "CorrR1D: incorrect N or M!", _state);
4528
+ corrr1dbuf(signal, n, pattern, m, r, _state);
4529
+ }
4530
+
4531
+
4532
+ /*************************************************************************
4533
+ 1-dimensional real cross-correlation, buffered function, which does not
4534
+ reallocate R[] if its length is enough to store the result (i.e. it reuses
4535
+ previously allocated memory as much as possible).
4536
+
4537
+ -- ALGLIB --
4538
+ Copyright 21.07.2009 by Bochkanov Sergey
4539
+ *************************************************************************/
4540
+ void corrr1dbuf(/* Real */ const ae_vector* signal,
4541
+ ae_int_t n,
4542
+ /* Real */ const ae_vector* pattern,
4543
+ ae_int_t m,
4544
+ /* Real */ ae_vector* r,
4545
+ ae_state *_state)
4546
+ {
4547
+ ae_frame _frame_block;
4548
+ ae_vector p;
4549
+ ae_vector b;
4550
+ ae_int_t i;
4551
+
4552
+ ae_frame_make(_state, &_frame_block);
4553
+ memset(&p, 0, sizeof(p));
4554
+ memset(&b, 0, sizeof(b));
4555
+ ae_vector_init(&p, 0, DT_REAL, _state, ae_true);
4556
+ ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
4557
+
4558
+ ae_assert(n>0&&m>0, "CorrR1DBuf: incorrect N or M!", _state);
4559
+ ae_vector_set_length(&p, m, _state);
4560
+ for(i=0; i<=m-1; i++)
4561
+ {
4562
+ p.ptr.p_double[m-1-i] = pattern->ptr.p_double[i];
4563
+ }
4564
+ convr1d(&p, m, signal, n, &b, _state);
4565
+ rallocv(m+n-1, r, _state);
4566
+ ae_v_move(&r->ptr.p_double[0], 1, &b.ptr.p_double[m-1], 1, ae_v_len(0,n-1));
4567
+ if( m+n-2>=n )
4568
+ {
4569
+ ae_v_move(&r->ptr.p_double[n], 1, &b.ptr.p_double[0], 1, ae_v_len(n,m+n-2));
4570
+ }
4571
+ ae_frame_leave(_state);
4572
+ }
4573
+
4574
+
4575
+ /*************************************************************************
4576
+ 1-dimensional circular real cross-correlation.
4577
+
4578
+ For given Pattern/Signal returns corr(Pattern,Signal) (circular).
4579
+ Algorithm has linearithmic complexity for any M/N.
4580
+
4581
+ IMPORTANT:
4582
+ for historical reasons subroutine accepts its parameters in reversed
4583
+ order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using
4584
+ traditional definition of cross-correlation, denoting cross-correlation
4585
+ as "x").
4586
+
4587
+ INPUT PARAMETERS
4588
+ Signal - array[0..N-1] - real function to be transformed,
4589
+ periodic signal containing pattern
4590
+ N - problem size
4591
+ Pattern - array[0..M-1] - real function to be transformed,
4592
+ non-periodic pattern to search withing signal
4593
+ M - problem size
4594
+
4595
+ OUTPUT PARAMETERS
4596
+ R - convolution: A*B. array[0..M-1].
4597
+
4598
+ NOTE: there is a buffered version of this function, CorrR1DCircularBuf(),
4599
+ which can reuse space previously allocated in its output parameter C.
4600
+
4601
+ -- ALGLIB --
4602
+ Copyright 21.07.2009 by Bochkanov Sergey
4603
+ *************************************************************************/
4604
+ void corrr1dcircular(/* Real */ const ae_vector* signal,
4605
+ ae_int_t m,
4606
+ /* Real */ const ae_vector* pattern,
4607
+ ae_int_t n,
4608
+ /* Real */ ae_vector* c,
4609
+ ae_state *_state)
4610
+ {
4611
+
4612
+ ae_vector_clear(c);
4613
+
4614
+ ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
4615
+ corrr1dcircularbuf(signal, m, pattern, n, c, _state);
4616
+ }
4617
+
4618
+
4619
+ /*************************************************************************
4620
+ 1-dimensional circular real cross-correlation, buffered version , which
4621
+ does not reallocate C[] if its length is enough to store the result (i.e.
4622
+ it reuses previously allocated memory as much as possible).
4623
+
4624
+ -- ALGLIB --
4625
+ Copyright 21.07.2009 by Bochkanov Sergey
4626
+ *************************************************************************/
4627
+ void corrr1dcircularbuf(/* Real */ const ae_vector* signal,
4628
+ ae_int_t m,
4629
+ /* Real */ const ae_vector* pattern,
4630
+ ae_int_t n,
4631
+ /* Real */ ae_vector* c,
4632
+ ae_state *_state)
4633
+ {
4634
+ ae_frame _frame_block;
4635
+ ae_vector p;
4636
+ ae_vector b;
4637
+ ae_int_t i1;
4638
+ ae_int_t i2;
4639
+ ae_int_t i;
4640
+ ae_int_t j2;
4641
+
4642
+ ae_frame_make(_state, &_frame_block);
4643
+ memset(&p, 0, sizeof(p));
4644
+ memset(&b, 0, sizeof(b));
4645
+ ae_vector_init(&p, 0, DT_REAL, _state, ae_true);
4646
+ ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
4647
+
4648
+ ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
4649
+
4650
+ /*
4651
+ * normalize task: make M>=N,
4652
+ * so A will be longer (at least - not shorter) that B.
4653
+ */
4654
+ if( m<n )
4655
+ {
4656
+ ae_vector_set_length(&b, m, _state);
4657
+ for(i1=0; i1<=m-1; i1++)
4658
+ {
4659
+ b.ptr.p_double[i1] = (double)(0);
4660
+ }
4661
+ i1 = 0;
4662
+ while(i1<n)
4663
+ {
4664
+ i2 = ae_minint(i1+m-1, n-1, _state);
4665
+ j2 = i2-i1;
4666
+ ae_v_add(&b.ptr.p_double[0], 1, &pattern->ptr.p_double[i1], 1, ae_v_len(0,j2));
4667
+ i1 = i1+m;
4668
+ }
4669
+ corrr1dcircularbuf(signal, m, &b, m, c, _state);
4670
+ ae_frame_leave(_state);
4671
+ return;
4672
+ }
4673
+
4674
+ /*
4675
+ * Task is normalized
4676
+ */
4677
+ ae_vector_set_length(&p, n, _state);
4678
+ for(i=0; i<=n-1; i++)
4679
+ {
4680
+ p.ptr.p_double[n-1-i] = pattern->ptr.p_double[i];
4681
+ }
4682
+ convr1dcircularbuf(signal, m, &p, n, &b, _state);
4683
+ rallocv(m, c, _state);
4684
+ ae_v_move(&c->ptr.p_double[0], 1, &b.ptr.p_double[n-1], 1, ae_v_len(0,m-n));
4685
+ if( m-n+1<=m-1 )
4686
+ {
4687
+ 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));
4688
+ }
4689
+ ae_frame_leave(_state);
4690
+ }
4691
+
4692
+
4693
+ #endif
4694
+
4695
+ }
4696
+