alglib4 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+