1# cython: language_level=3 2# 3# Copyright 2015 Knowledge Economy Developments Ltd 4# Copyright 2014 David Wells 5 6# Henry Gomersall 7# heng@kedevelopments.co.uk 8# 9# All rights reserved. 10# 11# Redistribution and use in source and binary forms, with or without 12# modification, are permitted provided that the following conditions are met: 13# 14# * Redistributions of source code must retain the above copyright notice, this 15# list of conditions and the following disclaimer. 16# 17# * Redistributions in binary form must reproduce the above copyright notice, 18# this list of conditions and the following disclaimer in the documentation 19# and/or other materials provided with the distribution. 20# 21# * Neither the name of the copyright holder nor the names of its contributors 22# may be used to endorse or promote products derived from this software without 23# specific prior written permission. 24# 25# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35# POSSIBILITY OF SUCH DAMAGE. 36# 37 38import numpy as np 39cimport numpy as np 40from libc.stdlib cimport calloc, malloc, free 41from libc.stdint cimport intptr_t, int64_t 42from libc cimport limits 43 44import warnings 45import threading 46 47include 'utils.pxi' 48 49cdef extern from *: 50 int Py_AtExit(void (*callback)()) 51 52# the total number of types pyfftw can support 53cdef int _n_types = 3 54cdef object _all_types = ['32', '64', 'ld'] 55_all_types_human_readable = { 56 '32': 'single', 57 '64': 'double', 58 'ld': 'long double', 59} 60 61_all_types_np = { 62 np.dtype(np.float32): '32', 63 np.dtype(np.float64): '64', 64} 65if np.dtype(np.longdouble) != np.dtype(np.float64): 66 _all_types_np[np.dtype(np.longdouble)] = 'ld' 67 68# the types supported in this build 69_supported_types = [] 70_supported_nptypes_complex = [] 71_supported_nptypes_real = [] 72 73IF HAVE_SINGLE: 74 _supported_types.append('32') 75 _supported_nptypes_complex.append(np.complex64) 76 _supported_nptypes_real.append(np.float32) 77IF HAVE_DOUBLE: 78 _supported_types.append('64') 79 _supported_nptypes_complex.append(np.complex128) 80 _supported_nptypes_real.append(np.float64) 81IF HAVE_LONG: 82 _supported_types.append('ld') 83 _supported_nptypes_complex.append(np.clongdouble) 84 _supported_nptypes_real.append(np.longdouble) 85 86IF (HAVE_SINGLE_OMP or HAVE_DOUBLE_OMP or HAVE_LONG_OMP): 87 _threading_type = 'OMP' 88ELIF (HAVE_SINGLE_THREADS or HAVE_DOUBLE_THREADS or HAVE_LONG_THREADS): 89 _threading_type = 'PTHREADS' 90ELSE: 91 _threading_type = None 92 93cdef object directions 94directions = {'FFTW_FORWARD': FFTW_FORWARD, 95 'FFTW_BACKWARD': FFTW_BACKWARD, 96 'FFTW_REDFT00': FFTW_REDFT00, 97 'FFTW_REDFT10': FFTW_REDFT10, 98 'FFTW_REDFT01': FFTW_REDFT01, 99 'FFTW_REDFT11': FFTW_REDFT11, 100 'FFTW_RODFT00': FFTW_RODFT00, 101 'FFTW_RODFT10': FFTW_RODFT10, 102 'FFTW_RODFT01': FFTW_RODFT01, 103 'FFTW_RODFT11': FFTW_RODFT11} 104 105cdef object directions_lookup 106directions_lookup = {FFTW_FORWARD: 'FFTW_FORWARD', 107 FFTW_BACKWARD: 'FFTW_BACKWARD', 108 FFTW_REDFT00: 'FFTW_REDFT00', 109 FFTW_REDFT10: 'FFTW_REDFT10', 110 FFTW_REDFT01: 'FFTW_REDFT01', 111 FFTW_REDFT11: 'FFTW_REDFT11', 112 FFTW_RODFT00: 'FFTW_RODFT00', 113 FFTW_RODFT10: 'FFTW_RODFT10', 114 FFTW_RODFT01: 'FFTW_RODFT01', 115 FFTW_RODFT11: 'FFTW_RODFT11'} 116 117cdef object flag_dict 118flag_dict = {'FFTW_MEASURE': FFTW_MEASURE, 119 'FFTW_EXHAUSTIVE': FFTW_EXHAUSTIVE, 120 'FFTW_PATIENT': FFTW_PATIENT, 121 'FFTW_ESTIMATE': FFTW_ESTIMATE, 122 'FFTW_UNALIGNED': FFTW_UNALIGNED, 123 'FFTW_DESTROY_INPUT': FFTW_DESTROY_INPUT, 124 'FFTW_WISDOM_ONLY': FFTW_WISDOM_ONLY} 125 126_flag_dict = flag_dict.copy() 127 128# Need a global lock to protect FFTW planning so that multiple Python threads 129# do not attempt to plan simultaneously. 130cdef object plan_lock = threading.Lock() 131 132# Function wrappers 133# ================= 134# All of these have the same signature as the fftw_generic functions 135# defined in the .pxd file. The arguments and return values are 136# cast as required in order to call the actual fftw functions. 137# 138# The wrapper function names are simply the fftw names prefixed 139# with a single underscore. 140 141# Planners 142# ======== 143# 144 145cdef void* _fftw_plan_null( 146 int rank, fftw_iodim *dims, 147 int howmany_rank, fftw_iodim *howmany_dims, 148 void *_in, void *_out, 149 int *direction, unsigned flags): 150 151 raise RuntimeError("Undefined planner. This is a bug") 152 153# Complex double precision 154IF HAVE_DOUBLE: 155 cdef void* _fftw_plan_guru_dft( 156 int rank, fftw_iodim *dims, 157 int howmany_rank, fftw_iodim *howmany_dims, 158 void *_in, void *_out, 159 int *direction, unsigned flags) nogil: 160 161 return <void *>fftw_plan_guru_dft(rank, dims, 162 howmany_rank, howmany_dims, 163 <cdouble *>_in, <cdouble *>_out, 164 direction[0], flags) 165 166 # real to complex double precision 167 cdef void* _fftw_plan_guru_dft_r2c( 168 int rank, fftw_iodim *dims, 169 int howmany_rank, fftw_iodim *howmany_dims, 170 void *_in, void *_out, 171 int *direction, unsigned flags) nogil: 172 173 return <void *>fftw_plan_guru_dft_r2c(rank, dims, 174 howmany_rank, howmany_dims, 175 <double *>_in, <cdouble *>_out, 176 flags) 177 178 # complex to real double precision 179 cdef void* _fftw_plan_guru_dft_c2r( 180 int rank, fftw_iodim *dims, 181 int howmany_rank, fftw_iodim *howmany_dims, 182 void *_in, void *_out, 183 int *direction, unsigned flags) nogil: 184 185 return <void *>fftw_plan_guru_dft_c2r(rank, dims, 186 howmany_rank, howmany_dims, 187 <cdouble *>_in, <double *>_out, 188 flags) 189 190 # real to real double precision 191 cdef void* _fftw_plan_guru_r2r( 192 int rank, fftw_iodim *dims, 193 int howmany_rank, fftw_iodim *howmany_dims, 194 void *_in, void *_out, 195 int *direction, int flags): 196 197 return <void *>fftw_plan_guru_r2r(rank, dims, 198 howmany_rank, howmany_dims, 199 <double *>_in, <double *>_out, 200 direction, flags) 201 202IF HAVE_SINGLE: 203 # Complex single precision 204 cdef void* _fftwf_plan_guru_dft( 205 int rank, fftw_iodim *dims, 206 int howmany_rank, fftw_iodim *howmany_dims, 207 void *_in, void *_out, 208 int *direction, unsigned flags) nogil: 209 210 return <void *>fftwf_plan_guru_dft(rank, dims, 211 howmany_rank, howmany_dims, 212 <cfloat *>_in, <cfloat *>_out, 213 direction[0], flags) 214 215 # real to complex single precision 216 cdef void* _fftwf_plan_guru_dft_r2c( 217 int rank, fftw_iodim *dims, 218 int howmany_rank, fftw_iodim *howmany_dims, 219 void *_in, void *_out, 220 int *direction, unsigned flags) nogil: 221 222 return <void *>fftwf_plan_guru_dft_r2c(rank, dims, 223 howmany_rank, howmany_dims, 224 <float *>_in, <cfloat *>_out, 225 flags) 226 227 # complex to real single precision 228 cdef void* _fftwf_plan_guru_dft_c2r( 229 int rank, fftw_iodim *dims, 230 int howmany_rank, fftw_iodim *howmany_dims, 231 void *_in, void *_out, 232 int *direction, unsigned flags) nogil: 233 234 return <void *>fftwf_plan_guru_dft_c2r(rank, dims, 235 howmany_rank, howmany_dims, 236 <cfloat *>_in, <float *>_out, 237 flags) 238 239 # real to real single precision 240 cdef void* _fftwf_plan_guru_r2r( 241 int rank, fftw_iodim *dims, 242 int howmany_rank, fftw_iodim *howmany_dims, 243 void *_in, void *_out, 244 int *direction, int flags): 245 246 return <void *>fftwf_plan_guru_r2r(rank, dims, 247 howmany_rank, howmany_dims, 248 <float *>_in, <float *>_out, 249 direction, flags) 250 251IF HAVE_LONG: 252 # Complex long double precision 253 cdef void* _fftwl_plan_guru_dft( 254 int rank, fftw_iodim *dims, 255 int howmany_rank, fftw_iodim *howmany_dims, 256 void *_in, void *_out, 257 int *direction, unsigned flags) nogil: 258 259 return <void *>fftwl_plan_guru_dft(rank, dims, 260 howmany_rank, howmany_dims, 261 <clongdouble *>_in, <clongdouble *>_out, 262 direction[0], flags) 263 264 # real to complex long double precision 265 cdef void* _fftwl_plan_guru_dft_r2c( 266 int rank, fftw_iodim *dims, 267 int howmany_rank, fftw_iodim *howmany_dims, 268 void *_in, void *_out, 269 int *direction, unsigned flags) nogil: 270 271 return <void *>fftwl_plan_guru_dft_r2c(rank, dims, 272 howmany_rank, howmany_dims, 273 <long double *>_in, <clongdouble *>_out, 274 flags) 275 276 # complex to real long double precision 277 cdef void* _fftwl_plan_guru_dft_c2r( 278 int rank, fftw_iodim *dims, 279 int howmany_rank, fftw_iodim *howmany_dims, 280 void *_in, void *_out, 281 int *direction, unsigned flags) nogil: 282 283 return <void *>fftwl_plan_guru_dft_c2r(rank, dims, 284 howmany_rank, howmany_dims, 285 <clongdouble *>_in, <long double *>_out, 286 flags) 287 288 # real to real long double precision 289 cdef void* _fftwl_plan_guru_r2r( 290 int rank, fftw_iodim *dims, 291 int howmany_rank, fftw_iodim *howmany_dims, 292 void *_in, void *_out, 293 int *direction, int flags): 294 295 return <void *>fftwl_plan_guru_r2r(rank, dims, 296 howmany_rank, howmany_dims, 297 <long double *>_in, <long double *>_out, 298 direction, flags) 299 300# Executors 301# ========= 302# 303 304cdef void _fftw_execute_null(void *_plan, void *_in, void *_out): 305 306 raise RuntimeError("Undefined executor. This is a bug") 307 308IF HAVE_DOUBLE: 309 # Complex double precision 310 cdef void _fftw_execute_dft(void *_plan, void *_in, void *_out) nogil: 311 312 fftw_execute_dft(<fftw_plan>_plan, 313 <cdouble *>_in, <cdouble *>_out) 314 315 # real to complex double precision 316 cdef void _fftw_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: 317 318 fftw_execute_dft_r2c(<fftw_plan>_plan, 319 <double *>_in, <cdouble *>_out) 320 321 # complex to real double precision 322 cdef void _fftw_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: 323 324 fftw_execute_dft_c2r(<fftw_plan>_plan, 325 <cdouble *>_in, <double *>_out) 326 327IF HAVE_SINGLE: 328 # Complex single precision 329 cdef void _fftwf_execute_dft(void *_plan, void *_in, void *_out) nogil: 330 331 fftwf_execute_dft(<fftwf_plan>_plan, 332 <cfloat *>_in, <cfloat *>_out) 333 334 # real to complex single precision 335 cdef void _fftwf_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: 336 337 fftwf_execute_dft_r2c(<fftwf_plan>_plan, 338 <float *>_in, <cfloat *>_out) 339 340 # complex to real single precision 341 cdef void _fftwf_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: 342 343 fftwf_execute_dft_c2r(<fftwf_plan>_plan, 344 <cfloat *>_in, <float *>_out) 345 346IF HAVE_LONG: 347 # Complex long double precision 348 cdef void _fftwl_execute_dft(void *_plan, void *_in, void *_out) nogil: 349 350 fftwl_execute_dft(<fftwl_plan>_plan, 351 <clongdouble *>_in, <clongdouble *>_out) 352 353 # real to complex long double precision 354 cdef void _fftwl_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: 355 356 fftwl_execute_dft_r2c(<fftwl_plan>_plan, 357 <long double *>_in, <clongdouble *>_out) 358 359 # complex to real long double precision 360 cdef void _fftwl_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: 361 362 fftwl_execute_dft_c2r(<fftwl_plan>_plan, 363 <clongdouble *>_in, <long double *>_out) 364 365# real to real double precision 366cdef void _fftw_execute_r2r(void *_plan, void *_in, void *_out) nogil: 367 368 fftw_execute_r2r(<fftw_plan>_plan, <double *>_in, <double *>_out) 369 370# real to real single precision 371cdef void _fftwf_execute_r2r(void *_plan, void *_in, void *_out) nogil: 372 373 fftwf_execute_r2r(<fftwf_plan>_plan, <float *>_in, <float *>_out) 374 375# real to real long double precision 376cdef void _fftwl_execute_r2r(void *_plan, void *_in, void *_out) nogil: 377 378 fftwl_execute_r2r(<fftwl_plan>_plan, <long double *>_in, <long double *>_out) 379 380# Destroyers 381# ========== 382# 383cdef void _fftw_destroy_null(void *plan): 384 385 raise RuntimeError("Undefined destroy. This is a bug") 386 387IF HAVE_DOUBLE: 388 # Double precision 389 cdef void _fftw_destroy_plan(void *_plan): 390 391 fftw_destroy_plan(<fftw_plan>_plan) 392 393IF HAVE_SINGLE: 394 # Single precision 395 cdef void _fftwf_destroy_plan(void *_plan): 396 397 fftwf_destroy_plan(<fftwf_plan>_plan) 398 399IF HAVE_LONG: 400 # Long double precision 401 cdef void _fftwl_destroy_plan(void *_plan): 402 403 fftwl_destroy_plan(<fftwl_plan>_plan) 404 405# Function lookup tables 406# ====================== 407 408 409# Planner table (of size the number of planners). 410cdef fftw_generic_plan_guru planners[12] 411 412cdef fftw_generic_plan_guru * _build_planner_list(): 413 for i in range(12): 414 planners[i] = <fftw_generic_plan_guru>&_fftw_plan_null 415 416 IF HAVE_DOUBLE: 417 planners[0] = <fftw_generic_plan_guru>&_fftw_plan_guru_dft 418 planners[3] = <fftw_generic_plan_guru>&_fftw_plan_guru_dft_r2c 419 planners[6] = <fftw_generic_plan_guru>&_fftw_plan_guru_dft_c2r 420 planners[9] = <fftw_generic_plan_guru>&_fftw_plan_guru_r2r 421 IF HAVE_SINGLE: 422 planners[1] = <fftw_generic_plan_guru>&_fftwf_plan_guru_dft 423 planners[4] = <fftw_generic_plan_guru>&_fftwf_plan_guru_dft_r2c 424 planners[7] = <fftw_generic_plan_guru>&_fftwf_plan_guru_dft_c2r 425 planners[10] = <fftw_generic_plan_guru>&_fftwf_plan_guru_r2r 426 IF HAVE_LONG: 427 planners[2] = <fftw_generic_plan_guru>&_fftwl_plan_guru_dft 428 planners[5] = <fftw_generic_plan_guru>&_fftwl_plan_guru_dft_r2c 429 planners[8] = <fftw_generic_plan_guru>&_fftwl_plan_guru_dft_c2r 430 planners[11] = <fftw_generic_plan_guru>&_fftwl_plan_guru_r2r 431 432# Executor table (of size the number of executors) 433cdef fftw_generic_execute executors[12] 434 435cdef fftw_generic_execute * _build_executor_list(): 436 for i in range(12): 437 executors[i] = <fftw_generic_execute>&_fftw_execute_null 438 439 IF HAVE_DOUBLE: 440 executors[0] = <fftw_generic_execute>&_fftw_execute_dft 441 executors[3] = <fftw_generic_execute>&_fftw_execute_dft_r2c 442 executors[6] = <fftw_generic_execute>&_fftw_execute_dft_c2r 443 executors[9] = <fftw_generic_execute>&_fftw_execute_r2r 444 IF HAVE_SINGLE: 445 executors[1] = <fftw_generic_execute>&_fftwf_execute_dft 446 executors[4] = <fftw_generic_execute>&_fftwf_execute_dft_r2c 447 executors[7] = <fftw_generic_execute>&_fftwf_execute_dft_c2r 448 executors[10] = <fftw_generic_execute>&_fftwf_execute_r2r 449 IF HAVE_LONG: 450 executors[2] = <fftw_generic_execute>&_fftwl_execute_dft 451 executors[5] = <fftw_generic_execute>&_fftwl_execute_dft_r2c 452 executors[8] = <fftw_generic_execute>&_fftwl_execute_dft_c2r 453 executors[11] = <fftw_generic_execute>&_fftwl_execute_r2r 454 455# Destroyer table (of size the number of destroyers) 456cdef fftw_generic_destroy_plan destroyers[3] 457 458cdef fftw_generic_destroy_plan * _build_destroyer_list(): 459 for i in range(3): 460 destroyers[i] = <fftw_generic_destroy_plan>&_fftw_destroy_null 461 462 IF HAVE_DOUBLE: 463 destroyers[0] = <fftw_generic_destroy_plan>&_fftw_destroy_plan 464 IF HAVE_SINGLE: 465 destroyers[1] = <fftw_generic_destroy_plan>&_fftwf_destroy_plan 466 IF HAVE_LONG: 467 destroyers[2] = <fftw_generic_destroy_plan>&_fftwl_destroy_plan 468 469# nthreads plan setters table 470cdef fftw_generic_plan_with_nthreads nthreads_plan_setters[3] 471 472cdef void _fftw_plan_with_nthreads_null(int n): 473 474 raise RuntimeError("Undefined plan with nthreads. This is a bug") 475 476cdef fftw_generic_plan_with_nthreads * _build_nthreads_plan_setters_list(): 477 for i in range(3): 478 nthreads_plan_setters[i] = ( 479 <fftw_generic_plan_with_nthreads>&_fftw_plan_with_nthreads_null) 480 IF HAVE_DOUBLE_MULTITHREADING: 481 nthreads_plan_setters[0] = ( 482 <fftw_generic_plan_with_nthreads>&fftw_plan_with_nthreads) 483 IF HAVE_SINGLE_MULTITHREADING: 484 nthreads_plan_setters[1] = ( 485 <fftw_generic_plan_with_nthreads>&fftwf_plan_with_nthreads) 486 IF HAVE_LONG_MULTITHREADING: 487 nthreads_plan_setters[2] = ( 488 <fftw_generic_plan_with_nthreads>&fftwl_plan_with_nthreads) 489 490# Set planner timelimits 491cdef fftw_generic_set_timelimit set_timelimit_funcs[3] 492 493cdef void _fftw_generic_set_timelimit_null(void *plan): 494 495 raise RuntimeError("Undefined set timelimit. This is a bug") 496 497cdef fftw_generic_set_timelimit * _build_set_timelimit_funcs_list(): 498 for i in range(3): 499 set_timelimit_funcs[i] = ( 500 <fftw_generic_set_timelimit>&_fftw_generic_set_timelimit_null) 501 502 IF HAVE_DOUBLE: 503 set_timelimit_funcs[0] = ( 504 <fftw_generic_set_timelimit>&fftw_set_timelimit) 505 IF HAVE_SINGLE: 506 set_timelimit_funcs[1] = ( 507 <fftw_generic_set_timelimit>&fftwf_set_timelimit) 508 IF HAVE_LONG: 509 set_timelimit_funcs[2] = ( 510 <fftw_generic_set_timelimit>&fftwl_set_timelimit) 511 512# Data validators table 513cdef validator validators[2] 514 515cdef validator * _build_validators_list(): 516 validators[0] = &_validate_r2c_arrays 517 validators[1] = &_validate_c2r_arrays 518 519# Validator functions 520# =================== 521cdef bint _validate_r2c_arrays(np.ndarray input_array, 522 np.ndarray output_array, int64_t *axes, int64_t *not_axes, 523 int64_t axes_length): 524 ''' Validates the input and output array to check for 525 a valid real to complex transform. 526 ''' 527 # We firstly need to confirm that the dimenions of the arrays 528 # are the same 529 if not (input_array.ndim == output_array.ndim): 530 return False 531 532 in_shape = input_array.shape 533 out_shape = output_array.shape 534 535 for n in range(axes_length - 1): 536 if not out_shape[axes[n]] == in_shape[axes[n]]: 537 return False 538 539 # The critical axis is the last of those over which the 540 # FFT is taken. 541 if not (out_shape[axes[axes_length-1]] 542 == in_shape[axes[axes_length-1]]//2 + 1): 543 return False 544 545 for n in range(input_array.ndim - axes_length): 546 if not out_shape[not_axes[n]] == in_shape[not_axes[n]]: 547 return False 548 549 return True 550 551 552cdef bint _validate_c2r_arrays(np.ndarray input_array, 553 np.ndarray output_array, int64_t *axes, int64_t *not_axes, 554 int64_t axes_length): 555 ''' Validates the input and output array to check for 556 a valid complex to real transform. 557 ''' 558 559 # We firstly need to confirm that the dimenions of the arrays 560 # are the same 561 if not (input_array.ndim == output_array.ndim): 562 return False 563 564 in_shape = input_array.shape 565 out_shape = output_array.shape 566 567 for n in range(axes_length - 1): 568 if not in_shape[axes[n]] == out_shape[axes[n]]: 569 return False 570 571 # The critical axis is the last of those over which the 572 # FFT is taken. 573 if not (in_shape[axes[axes_length-1]] 574 == out_shape[axes[axes_length-1]]//2 + 1): 575 return False 576 577 for n in range(input_array.ndim - axes_length): 578 if not in_shape[not_axes[n]] == out_shape[not_axes[n]]: 579 return False 580 581 return True 582 583 584# Shape lookup functions 585# ====================== 586def _lookup_shape_r2c_arrays(input_array, output_array): 587 return input_array.shape 588 589def _lookup_shape_c2r_arrays(input_array, output_array): 590 return output_array.shape 591 592# fftw_schemes is a dictionary with a mapping from a keys, 593# which are a tuple of the string representation of numpy 594# dtypes to a scheme name. 595# 596# scheme_functions is a dictionary of functions, either 597# an index to the array of functions in the case of 598# 'planner', 'executor' and 'generic_precision' or a callable 599# in the case of 'validator' (generic_precision is a catchall for 600# functions that only change based on the precision changing - 601# i.e the prefix fftw, fftwl and fftwf is the only bit that changes). 602# 603# The array indices refer to the relevant functions for each scheme, 604# the tables to which are defined above. 605# 606# The 'validator' function is a callable for validating the arrays 607# that has the following signature: 608# bool callable(ndarray in_array, ndarray out_array, axes, not_axes) 609# and checks that the arrays are a valid pair. If it is set to None, 610# then the default check is applied, which confirms that the arrays 611# have the same shape. 612# 613# The 'fft_shape_lookup' function is a callable for returning the 614# FFT shape - that is, an array that describes the length of the 615# fft along each axis. It has the following signature: 616# fft_shape = fft_shape_lookup(in_array, out_array) 617# (note that this does not correspond to the lengths of the FFT that is 618# actually taken, it's the lengths of the FFT that *could* be taken 619# along each axis. It's necessary because the real FFT has a length 620# that is different to the length of the input array). 621 622cdef object fftw_schemes 623fftw_schemes = { 624 (np.dtype('complex128'), np.dtype('complex128')): ('c2c', '64'), 625 (np.dtype('complex64'), np.dtype('complex64')): ('c2c', '32'), 626 (np.dtype('float64'), np.dtype('complex128')): ('r2c', '64'), 627 (np.dtype('float32'), np.dtype('complex64')): ('r2c', '32'), 628 (np.dtype('complex128'), np.dtype('float64')): ('c2r', '64'), 629 (np.dtype('complex64'), np.dtype('float32')): ('c2r', '32'), 630 (np.dtype('float32'), np.dtype('float32')): ('r2r', '32'), 631 (np.dtype('float64'), np.dtype('float64')): ('r2r', '64')} 632 633cdef object fftw_default_output 634fftw_default_output = { 635 np.dtype('float32'): np.dtype('complex64'), 636 np.dtype('float64'): np.dtype('complex128'), 637 np.dtype('complex64'): np.dtype('complex64'), 638 np.dtype('complex128'): np.dtype('complex128')} 639 640if np.dtype('longdouble') != np.dtype('float64'): 641 fftw_schemes.update({ 642 (np.dtype('clongdouble'), np.dtype('clongdouble')): ('c2c', 'ld'), 643 (np.dtype('longdouble'), np.dtype('clongdouble')): ('r2c', 'ld'), 644 (np.dtype('clongdouble'), np.dtype('longdouble')): ('c2r', 'ld'), 645 (np.dtype('longdouble'), np.dtype('longdouble')): ('r2r', 'ld')}) 646 647 fftw_default_output.update({ 648 np.dtype('longdouble'): np.dtype('clongdouble'), 649 np.dtype('clongdouble'): np.dtype('clongdouble')}) 650 651cdef object scheme_directions 652scheme_directions = { 653 ('c2c', '64'): ['FFTW_FORWARD', 'FFTW_BACKWARD'], 654 ('c2c', '32'): ['FFTW_FORWARD', 'FFTW_BACKWARD'], 655 ('c2c', 'ld'): ['FFTW_FORWARD', 'FFTW_BACKWARD'], 656 ('r2c', '64'): ['FFTW_FORWARD'], 657 ('r2c', '32'): ['FFTW_FORWARD'], 658 ('r2c', 'ld'): ['FFTW_FORWARD'], 659 ('c2r', '64'): ['FFTW_BACKWARD'], 660 ('c2r', '32'): ['FFTW_BACKWARD'], 661 ('c2r', 'ld'): ['FFTW_BACKWARD'], 662 ('r2r', '64'): ['FFTW_REDFT00', 'FFTW_REDFT10', 'FFTW_REDFT01', 663 'FFTW_REDFT11', 'FFTW_RODFT00', 'FFTW_RODFT10', 664 'FFTW_RODFT01', 'FFTW_RODFT11'], 665 ('r2r', '32'): ['FFTW_REDFT00', 'FFTW_REDFT10', 'FFTW_REDFT01', 666 'FFTW_REDFT11', 'FFTW_RODFT00', 'FFTW_RODFT10', 667 'FFTW_RODFT01', 'FFTW_RODFT11'], 668 ('r2r', 'ld'): ['FFTW_REDFT00', 'FFTW_REDFT10', 'FFTW_REDFT01', 669 'FFTW_REDFT11', 'FFTW_RODFT00', 'FFTW_RODFT10', 670 'FFTW_RODFT01', 'FFTW_RODFT11']} 671 672# In the following, -1 denotes using the default. A segfault has been 673# reported on some systems when this is set to None. It seems 674# sufficiently trivial to use -1 in place of None, especially given 675# that scheme_functions is an internal cdef object. 676cdef object _scheme_functions = {} 677IF HAVE_DOUBLE: 678 _scheme_functions.update({ 679 ('c2c', '64'): {'planner': 0, 'executor':0, 'generic_precision':0, 680 'validator': -1, 'fft_shape_lookup': -1}, 681 ('r2c', '64'): {'planner':3, 'executor':3, 'generic_precision':0, 682 'validator': 0, 683 'fft_shape_lookup': _lookup_shape_r2c_arrays}, 684 ('c2r', '64'): {'planner':6, 'executor':6, 'generic_precision':0, 685 'validator': 1, 686 'fft_shape_lookup': _lookup_shape_c2r_arrays}, 687 ('r2r', '64'): {'planner': 9, 'executor':9, 'generic_precision':0, 688 'validator': -1, 'fft_shape_lookup': -1}}) 689IF HAVE_SINGLE: 690 _scheme_functions.update({ 691 ('c2c', '32'): {'planner':1, 'executor':1, 'generic_precision':1, 692 'validator': -1, 'fft_shape_lookup': -1}, 693 ('r2c', '32'): {'planner':4, 'executor':4, 'generic_precision':1, 694 'validator': 0, 695 'fft_shape_lookup': _lookup_shape_r2c_arrays}, 696 ('c2r', '32'): {'planner':7, 'executor':7, 'generic_precision':1, 697 'validator': 1, 698 'fft_shape_lookup': _lookup_shape_c2r_arrays}, 699 ('r2r', '32'): {'planner':10, 'executor':10, 'generic_precision':1, 700 'validator': -1, 'fft_shape_lookup': -1}}) 701IF HAVE_LONG: 702 _scheme_functions.update({ 703 ('c2c', 'ld'): {'planner':2, 'executor':2, 'generic_precision':2, 704 'validator': -1, 'fft_shape_lookup': -1}, 705 ('r2c', 'ld'): {'planner':5, 'executor':5, 'generic_precision':2, 706 'validator': 0, 707 'fft_shape_lookup': _lookup_shape_r2c_arrays}, 708 ('c2r', 'ld'): {'planner':8, 'executor':8, 'generic_precision':2, 709 'validator': 1, 710 'fft_shape_lookup': _lookup_shape_c2r_arrays}, 711 ('r2r', 'ld'): {'planner':11, 'executor':11, 'generic_precision':2, 712 'validator': -1, 'fft_shape_lookup': -1}}) 713 714def scheme_functions(scheme): 715 if scheme in _scheme_functions: 716 return _scheme_functions[scheme] 717 else: 718 msg = "The scheme '%s' is not supported." % str(scheme) 719 if scheme[1] in _all_types: 720 msg += "\nRebuild pyFFTW with support for %s precision!" % \ 721 _all_types_human_readable[scheme[1]] 722 raise NotImplementedError(msg) 723 724# Set the cleanup routine 725cdef void _cleanup(): 726 IF HAVE_DOUBLE: 727 fftw_cleanup() 728 IF HAVE_SINGLE: 729 fftwf_cleanup() 730 IF HAVE_LONG: 731 fftwl_cleanup() 732 IF HAVE_DOUBLE_MULTITHREADING: 733 fftw_cleanup_threads() 734 IF HAVE_SINGLE_MULTITHREADING: 735 fftwf_cleanup_threads() 736 IF HAVE_LONG_MULTITHREADING: 737 fftwl_cleanup_threads() 738 739# Initialize the module 740 741# Define the functions 742_build_planner_list() 743_build_destroyer_list() 744_build_executor_list() 745_build_nthreads_plan_setters_list() 746_build_validators_list() 747_build_set_timelimit_funcs_list() 748 749IF HAVE_DOUBLE_MULTITHREADING: 750 fftw_init_threads() 751IF HAVE_SINGLE_MULTITHREADING: 752 fftwf_init_threads() 753IF HAVE_LONG_MULTITHREADING: 754 fftwl_init_threads() 755 756Py_AtExit(_cleanup) 757 758# Helper functions 759cdef void make_axes_unique(int64_t *axes, int64_t axes_length, 760 int64_t **unique_axes, int64_t **not_axes, int64_t dimensions, 761 int64_t *unique_axes_length): 762 ''' Takes an array of axes and makes that array unique, returning 763 the unique array in unique_axes. It also creates and fills another 764 array, not_axes, with those axes that are not included in unique_axes. 765 766 unique_axes_length is updated with the length of unique_axes. 767 768 dimensions is the number of dimensions to which the axes array 769 might refer. 770 771 It is the responsibility of the caller to free unique_axes and not_axes. 772 ''' 773 774 cdef int64_t unique_axes_count = 0 775 cdef int64_t holding_offset = 0 776 777 cdef int64_t *axes_holding = ( 778 <int64_t *>calloc(dimensions, sizeof(int64_t))) 779 cdef int64_t *axes_holding_offset = ( 780 <int64_t *>calloc(dimensions, sizeof(int64_t))) 781 782 for n in range(dimensions): 783 axes_holding[n] = -1 784 785 # Iterate over all the axes and store each index if it hasn't already 786 # been stored (this keeps one and only one and the first index to axes 787 # i.e. storing the unique set of entries). 788 # 789 # axes_holding_offset holds the shift due to repeated axes 790 for n in range(axes_length): 791 if axes_holding[axes[n]] == -1: 792 axes_holding[axes[n]] = n 793 axes_holding_offset[axes[n]] = holding_offset 794 unique_axes_count += 1 795 else: 796 holding_offset += 1 797 798 unique_axes[0] = <int64_t *>malloc( 799 unique_axes_count * sizeof(int64_t)) 800 801 not_axes[0] = <int64_t *>malloc( 802 (dimensions - unique_axes_count) * sizeof(int64_t)) 803 804 # Now we need to write back the unique axes to a tmp axes 805 cdef int64_t not_axes_count = 0 806 807 for n in range(dimensions): 808 if axes_holding[n] != -1: 809 unique_axes[0][axes_holding[n] - axes_holding_offset[n]] = ( 810 axes[axes_holding[n]]) 811 812 else: 813 not_axes[0][not_axes_count] = n 814 not_axes_count += 1 815 816 free(axes_holding) 817 free(axes_holding_offset) 818 819 unique_axes_length[0] = unique_axes_count 820 821 return 822 823 824# The External Interface 825# ====================== 826# 827cdef class FFTW: 828 ''' 829 FFTW is a class for computing a variety of discrete Fourier 830 transforms of multidimensional, strided arrays using the FFTW 831 library. The interface is designed to be somewhat pythonic, with 832 the correct transform being inferred from the dtypes of the passed 833 arrays. 834 835 The exact scheme may be either directly specified with the 836 ``direction`` parameter or inferred from the dtypes and relative 837 shapes of the input arrays. Information on which shapes and dtypes 838 imply which transformations is available in the :ref:`FFTW schemes 839 <scheme_table>`. If a match is found, the plan corresponding to that 840 scheme is created, operating on the arrays that are passed in. If no 841 scheme can be created then a ``ValueError`` is raised. 842 843 The actual transformation is performed by calling the 844 :meth:`~pyfftw.FFTW.execute` method. 845 846 The arrays can be updated by calling the 847 :meth:`~pyfftw.FFTW.update_arrays` method. 848 849 The created instance of the class is itself callable, and can perform 850 the execution of the FFT, both with or without array updates, returning 851 the result of the FFT. Unlike calling the :meth:`~pyfftw.FFTW.execute` 852 method, calling the class instance will also optionally normalise the 853 output as necessary. Additionally, calling with an input array update 854 will also coerce that array to be the correct dtype. 855 856 See the documentation on the :meth:`~pyfftw.FFTW.__call__` method 857 for more information. 858 ''' 859 # Each of these function pointers simply 860 # points to a chosen fftw wrapper function 861 cdef fftw_generic_plan_guru _fftw_planner 862 cdef fftw_generic_execute _fftw_execute 863 cdef fftw_generic_destroy_plan _fftw_destroy 864 cdef fftw_generic_plan_with_nthreads _nthreads_plan_setter 865 866 # The plan is typecast when it is created or used 867 # within the wrapper functions 868 cdef void *_plan 869 870 cdef np.ndarray _input_array 871 cdef np.ndarray _output_array 872 cdef int *_direction 873 cdef unsigned _flags 874 875 cdef bint _simd_allowed 876 cdef int _input_array_alignment 877 cdef int _output_array_alignment 878 cdef bint _use_threads 879 880 cdef object _input_item_strides 881 cdef object _input_strides 882 cdef object _output_item_strides 883 cdef object _output_strides 884 cdef object _input_shape 885 cdef object _output_shape 886 cdef object _input_dtype 887 cdef object _output_dtype 888 cdef object _flags_used 889 890 cdef double _normalisation_scaling 891 cdef double _sqrt_normalisation_scaling 892 893 cdef int _rank 894 cdef _fftw_iodim *_dims 895 cdef int _howmany_rank 896 cdef _fftw_iodim *_howmany_dims 897 898 cdef int64_t *_axes 899 cdef int64_t *_not_axes 900 901 cdef int64_t _total_size 902 903 cdef bint _normalise_idft 904 cdef bint _ortho 905 906 def _get_N(self): 907 ''' 908 The product of the lengths of the DFT over all DFT axes. 909 1/N is the normalisation constant. For any input array A, 910 and for any set of axes, 1/N * ifft(fft(A)) = A 911 ''' 912 return self._total_size 913 914 N = property(_get_N) 915 916 def _get_simd_aligned(self): 917 ''' 918 Return whether or not this FFTW object requires simd aligned 919 input and output data. 920 ''' 921 return self._simd_allowed 922 923 simd_aligned = property(_get_simd_aligned) 924 925 def _get_input_alignment(self): 926 ''' 927 Returns the byte alignment of the input arrays for which the 928 :class:`~pyfftw.FFTW` object was created. 929 930 Input array updates with arrays that are not aligned on this 931 byte boundary will result in a ValueError being raised, or 932 a copy being made if the :meth:`~pyfftw.FFTW.__call__` 933 interface is used. 934 ''' 935 return self._input_array_alignment 936 937 input_alignment = property(_get_input_alignment) 938 939 def _get_output_alignment(self): 940 ''' 941 Returns the byte alignment of the output arrays for which the 942 :class:`~pyfftw.FFTW` object was created. 943 944 Output array updates with arrays that are not aligned on this 945 byte boundary will result in a ValueError being raised. 946 ''' 947 return self._output_array_alignment 948 949 output_alignment = property(_get_output_alignment) 950 951 def _get_flags_used(self): 952 ''' 953 Return which flags were used to construct the FFTW object. 954 955 This includes flags that were added during initialisation. 956 ''' 957 return tuple(self._flags_used) 958 959 flags = property(_get_flags_used) 960 961 def _get_input_array(self): 962 ''' 963 Return the input array that is associated with the FFTW 964 instance. 965 ''' 966 return self._input_array 967 968 input_array = property(_get_input_array) 969 970 def _get_output_array(self): 971 ''' 972 Return the output array that is associated with the FFTW 973 instance. 974 ''' 975 return self._output_array 976 977 output_array = property(_get_output_array) 978 979 def _get_input_strides(self): 980 ''' 981 Return the strides of the input array for which the FFT is planned. 982 ''' 983 return self._input_strides 984 985 input_strides = property(_get_input_strides) 986 987 def _get_output_strides(self): 988 ''' 989 Return the strides of the output array for which the FFT is planned. 990 ''' 991 return self._output_strides 992 993 output_strides = property(_get_output_strides) 994 995 def _get_input_shape(self): 996 ''' 997 Return the shape of the input array for which the FFT is planned. 998 ''' 999 return self._input_shape 1000 1001 input_shape = property(_get_input_shape) 1002 1003 def _get_output_shape(self): 1004 ''' 1005 Return the shape of the output array for which the FFT is planned. 1006 ''' 1007 return self._output_shape 1008 1009 output_shape = property(_get_output_shape) 1010 1011 def _get_input_dtype(self): 1012 ''' 1013 Return the dtype of the input array for which the FFT is planned. 1014 ''' 1015 return self._input_dtype 1016 1017 input_dtype = property(_get_input_dtype) 1018 1019 def _get_output_dtype(self): 1020 ''' 1021 Return the shape of the output array for which the FFT is planned. 1022 ''' 1023 return self._output_dtype 1024 1025 output_dtype = property(_get_output_dtype) 1026 1027 def _get_direction(self): 1028 ''' 1029 Return the planned FFT direction. Either `'FFTW_FORWARD'`, 1030 `'FFTW_BACKWARD'`, or a list of real transform codes of the form 1031 `['FFTW_R*DFT**']`. 1032 ''' 1033 cdef int i 1034 transform_directions = list() 1035 if self._direction[0] in [FFTW_FORWARD, FFTW_BACKWARD]: 1036 # It would be nice to return a length-one list here (so that the 1037 # return type is always [str]). This is an annoying type difference, 1038 # but is backwards compatible. 1039 return directions_lookup[self._direction[0]] 1040 else: 1041 for i in range(self._rank): 1042 transform_directions.append(directions_lookup[ 1043 self._direction[i]]) 1044 return transform_directions 1045 1046 direction = property(_get_direction) 1047 1048 def _get_axes(self): 1049 ''' 1050 Return the axes for the planned FFT in canonical form. That is, as 1051 a tuple of positive integers. The order in which they were passed 1052 is maintained. 1053 ''' 1054 axes = [] 1055 for i in range(self._rank): 1056 axes.append(self._axes[i]) 1057 1058 return tuple(axes) 1059 1060 axes = property(_get_axes) 1061 1062 def _get_normalise_idft(self): 1063 ''' 1064 If ``normalise_idft=True``, the inverse transform is scaled by 1/N. 1065 ''' 1066 return self._normalise_idft 1067 1068 normalise_idft = property(_get_normalise_idft) 1069 1070 def _get_ortho(self): 1071 ''' 1072 If ``ortho=True`` both the forward and inverse transforms are scaled by 1073 1/sqrt(N). 1074 ''' 1075 return self._ortho 1076 1077 ortho = property(_get_ortho) 1078 1079 def __cinit__(self, input_array, output_array, axes=(-1,), 1080 direction='FFTW_FORWARD', flags=('FFTW_MEASURE',), 1081 unsigned int threads=1, planning_timelimit=None, 1082 bint normalise_idft=True, bint ortho=False, 1083 *args, **kwargs): 1084 1085 if isinstance(direction, str): 1086 given_directions = [direction] 1087 else: 1088 given_directions = list(direction) 1089 1090 # Initialise the pointers that need to be freed 1091 self._plan = NULL 1092 self._dims = NULL 1093 self._howmany_dims = NULL 1094 1095 self._axes = NULL 1096 self._not_axes = NULL 1097 self._direction = NULL 1098 1099 self._normalise_idft = normalise_idft 1100 self._ortho = ortho 1101 if self._ortho and self._normalise_idft: 1102 raise ValueError('Invalid options: ' 1103 'ortho and normalise_idft cannot both be True.') 1104 1105 flags = list(flags) 1106 1107 cdef double _planning_timelimit 1108 if planning_timelimit is None: 1109 _planning_timelimit = FFTW_NO_TIMELIMIT 1110 else: 1111 try: 1112 _planning_timelimit = planning_timelimit 1113 except TypeError: 1114 raise TypeError('Invalid planning timelimit: ' 1115 'The planning timelimit needs to be a float.') 1116 1117 if not isinstance(input_array, np.ndarray): 1118 raise ValueError('Invalid input array: ' 1119 'The input array needs to be an instance ' 1120 'of numpy.ndarray') 1121 1122 if not isinstance(output_array, np.ndarray): 1123 raise ValueError('Invalid output array: ' 1124 'The output array needs to be an instance ' 1125 'of numpy.ndarray') 1126 1127 try: 1128 input_dtype = input_array.dtype 1129 output_dtype = output_array.dtype 1130 scheme = fftw_schemes[(input_dtype, output_dtype)] 1131 except KeyError: 1132 raise ValueError('Invalid scheme: ' 1133 'The output array and input array dtypes ' 1134 'do not correspond to a valid fftw scheme.') 1135 1136 self._input_dtype = input_dtype 1137 self._output_dtype = output_dtype 1138 1139 functions = scheme_functions(scheme) 1140 1141 self._fftw_planner = planners[functions['planner']] 1142 self._fftw_execute = executors[functions['executor']] 1143 self._fftw_destroy = destroyers[functions['generic_precision']] 1144 1145 self._nthreads_plan_setter = ( 1146 nthreads_plan_setters[functions['generic_precision']]) 1147 1148 cdef fftw_generic_set_timelimit set_timelimit_func = ( 1149 set_timelimit_funcs[functions['generic_precision']]) 1150 1151 # We're interested in the natural alignment on the real type, not 1152 # necessarily on the complex type At least one bug was found where 1153 # numpy reported an alignment on a complex dtype that was different 1154 # to that on the real type. 1155 cdef int natural_input_alignment = input_array.real.dtype.alignment 1156 cdef int natural_output_alignment = output_array.real.dtype.alignment 1157 1158 # If either of the arrays is not aligned on a 16-byte boundary, 1159 # we set the FFTW_UNALIGNED flag. This disables SIMD. 1160 # (16 bytes is assumed to be the minimal alignment) 1161 if 'FFTW_UNALIGNED' in flags: 1162 self._simd_allowed = False 1163 self._input_array_alignment = natural_input_alignment 1164 self._output_array_alignment = natural_output_alignment 1165 1166 else: 1167 1168 self._input_array_alignment = -1 1169 self._output_array_alignment = -1 1170 1171 for each_alignment in _valid_simd_alignments: 1172 if (<intptr_t>np.PyArray_DATA(input_array) % 1173 each_alignment == 0 and 1174 <intptr_t>np.PyArray_DATA(output_array) % 1175 each_alignment == 0): 1176 1177 self._simd_allowed = True 1178 1179 self._input_array_alignment = each_alignment 1180 self._output_array_alignment = each_alignment 1181 1182 break 1183 1184 if (self._input_array_alignment == -1 or 1185 self._output_array_alignment == -1): 1186 1187 self._simd_allowed = False 1188 1189 self._input_array_alignment = ( 1190 natural_input_alignment) 1191 self._output_array_alignment = ( 1192 natural_output_alignment) 1193 flags.append('FFTW_UNALIGNED') 1194 1195 if (not (<intptr_t>np.PyArray_DATA(input_array) 1196 % self._input_array_alignment == 0)): 1197 raise ValueError('Invalid input alignment: ' 1198 'The input array is expected to lie on a %d ' 1199 'byte boundary.' % self._input_array_alignment) 1200 1201 if (not (<intptr_t>np.PyArray_DATA(output_array) 1202 % self._output_array_alignment == 0)): 1203 raise ValueError('Invalid output alignment: ' 1204 'The output array is expected to lie on a %d ' 1205 'byte boundary.' % self._output_array_alignment) 1206 1207 for direction in given_directions: 1208 if direction not in scheme_directions[scheme]: 1209 raise ValueError('Invalid direction: ' 1210 'The direction is not valid for the scheme. ' 1211 'Try setting it explicitly if it is not already.') 1212 1213 self._direction = <int *>malloc(len(axes)*sizeof(int)) 1214 1215 real_transforms = True 1216 cdef int i 1217 if given_directions[0] in ['FFTW_FORWARD', 'FFTW_BACKWARD']: 1218 self._direction[0] = directions[given_directions[0]] 1219 real_transforms = False 1220 else: 1221 if len(axes) != len(given_directions): 1222 raise ValueError('For real-to-real transforms, there must ' 1223 'be exactly one specified transform for each ' 1224 'transformed axis.') 1225 for i in range(len(axes)): 1226 if given_directions[0] in ['FFTW_FORWARD', 'FFTW_BACKWARD']: 1227 raise ValueError('Heterogeneous transforms cannot be ' 1228 'assigned with \'FFTW_FORWARD\' or ' 1229 '\'FFTW_BACKWARD\'.') 1230 else: 1231 self._direction[i] = directions[given_directions[i]] 1232 1233 self._input_shape = input_array.shape 1234 self._output_shape = output_array.shape 1235 1236 self._input_array = input_array 1237 self._output_array = output_array 1238 1239 self._axes = <int64_t *>malloc(len(axes)*sizeof(int64_t)) 1240 for n in range(len(axes)): 1241 self._axes[n] = axes[n] 1242 1243 # Set the negative entries to their actual index (use the size 1244 # of the shape array for this) 1245 cdef int64_t array_dimension = len(self._input_shape) 1246 1247 for n in range(len(axes)): 1248 if self._axes[n] < 0: 1249 self._axes[n] = self._axes[n] + array_dimension 1250 1251 if self._axes[n] >= array_dimension or self._axes[n] < 0: 1252 raise IndexError('Invalid axes: ' 1253 'The axes list cannot contain invalid axes.') 1254 1255 cdef int64_t unique_axes_length 1256 cdef int64_t *unique_axes 1257 cdef int64_t *not_axes 1258 1259 make_axes_unique(self._axes, len(axes), &unique_axes, 1260 ¬_axes, array_dimension, &unique_axes_length) 1261 1262 # and assign axes and not_axes to the filled arrays 1263 free(self._axes) 1264 self._axes = unique_axes 1265 self._not_axes = not_axes 1266 1267 total_N = 1 1268 for n in range(unique_axes_length): 1269 if self._input_shape[self._axes[n]] == 0: 1270 raise ValueError('Zero length array: ' 1271 'The input array should have no zero length' 1272 'axes over which the FFT is to be taken') 1273 1274 if real_transforms: 1275 if self._direction[n] == FFTW_RODFT00: 1276 total_N *= 2*(self._input_shape[self._axes[n]] + 1) 1277 elif self._direction[n] == FFTW_REDFT00: 1278 if (self._input_shape[self._axes[n]] < 2): 1279 raise ValueError('FFTW_REDFT00 (also known as DCT-1) is' 1280 ' not defined for inputs of length less than two.') 1281 total_N *= 2*(self._input_shape[self._axes[n]] - 1) 1282 else: 1283 total_N *= 2*self._input_shape[self._axes[n]] 1284 else: 1285 if self._direction[0] == FFTW_FORWARD: 1286 total_N *= self._input_shape[self._axes[n]] 1287 else: 1288 total_N *= self._output_shape[self._axes[n]] 1289 1290 self._total_size = total_N 1291 self._normalisation_scaling = 1/float(self.N) 1292 self._sqrt_normalisation_scaling = np.sqrt(self._normalisation_scaling) 1293 1294 # Now we can validate the array shapes 1295 cdef validator _validator 1296 1297 if functions['validator'] == -1: 1298 if not (output_array.shape == input_array.shape): 1299 raise ValueError('Invalid shapes: ' 1300 'The output array should be the same shape as the ' 1301 'input array for the given array dtypes.') 1302 else: 1303 _validator = validators[functions['validator']] 1304 if not _validator(input_array, output_array, 1305 self._axes, self._not_axes, unique_axes_length): 1306 raise ValueError('Invalid shapes: ' 1307 'The input array and output array are invalid ' 1308 'complementary shapes for their dtypes.') 1309 1310 self._rank = unique_axes_length 1311 self._howmany_rank = self._input_array.ndim - unique_axes_length 1312 1313 self._flags = 0 1314 self._flags_used = [] 1315 for each_flag in flags: 1316 try: 1317 self._flags |= flag_dict[each_flag] 1318 self._flags_used.append(each_flag) 1319 except KeyError: 1320 raise ValueError('Invalid flag: ' + '\'' + 1321 each_flag + '\' is not a valid planner flag.') 1322 1323 1324 if ('FFTW_DESTROY_INPUT' not in flags) and ( 1325 (scheme[0] != 'c2r') or not self._rank > 1): 1326 # The default in all possible cases is to preserve the input 1327 # This is not possible for r2c arrays with rank > 1 1328 self._flags |= FFTW_PRESERVE_INPUT 1329 1330 # Set up the arrays of structs for holding the stride shape 1331 # information 1332 self._dims = <_fftw_iodim *>malloc( 1333 self._rank * sizeof(_fftw_iodim)) 1334 self._howmany_dims = <_fftw_iodim *>malloc( 1335 self._howmany_rank * sizeof(_fftw_iodim)) 1336 1337 if self._dims == NULL or self._howmany_dims == NULL: 1338 # Not much else to do than raise an exception 1339 raise MemoryError 1340 1341 # Find the strides for all the axes of both arrays in terms of the 1342 # number of items (as opposed to the number of bytes). 1343 self._input_strides = input_array.strides 1344 self._input_item_strides = tuple([stride/input_array.itemsize 1345 for stride in input_array.strides]) 1346 self._output_strides = output_array.strides 1347 self._output_item_strides = tuple([stride/output_array.itemsize 1348 for stride in output_array.strides]) 1349 1350 # Make sure that the arrays are not too big for fftw 1351 # This is hard to test, so we cross our fingers and hope for the 1352 # best (any suggestions, please get in touch). 1353 for i in range(0, len(self._input_shape)): 1354 if self._input_shape[i] >= <Py_ssize_t> limits.INT_MAX: 1355 raise ValueError('Dimensions of the input array must be ' + 1356 'less than ', str(limits.INT_MAX)) 1357 1358 if self._input_item_strides[i] >= <Py_ssize_t> limits.INT_MAX: 1359 raise ValueError('Strides of the input array must be ' + 1360 'less than ', str(limits.INT_MAX)) 1361 1362 for i in range(0, len(self._output_shape)): 1363 if self._output_shape[i] >= <Py_ssize_t> limits.INT_MAX: 1364 raise ValueError('Dimensions of the output array must be ' + 1365 'less than ', str(limits.INT_MAX)) 1366 1367 if self._output_item_strides[i] >= <Py_ssize_t> limits.INT_MAX: 1368 raise ValueError('Strides of the output array must be ' + 1369 'less than ', str(limits.INT_MAX)) 1370 1371 fft_shape_lookup = functions['fft_shape_lookup'] 1372 if fft_shape_lookup == -1: 1373 fft_shape = self._input_shape 1374 else: 1375 fft_shape = fft_shape_lookup(input_array, output_array) 1376 1377 # Fill in the stride and shape information 1378 input_strides_array = self._input_item_strides 1379 output_strides_array = self._output_item_strides 1380 for i in range(0, self._rank): 1381 self._dims[i]._n = fft_shape[self._axes[i]] 1382 self._dims[i]._is = input_strides_array[self._axes[i]] 1383 self._dims[i]._os = output_strides_array[self._axes[i]] 1384 1385 for i in range(0, self._howmany_rank): 1386 self._howmany_dims[i]._n = fft_shape[self._not_axes[i]] 1387 self._howmany_dims[i]._is = input_strides_array[self._not_axes[i]] 1388 self._howmany_dims[i]._os = output_strides_array[self._not_axes[i]] 1389 1390 # parallel execution 1391 self._use_threads = (threads > 1) 1392 1393 ## Point at which FFTW calls are made 1394 ## (and none should be made before this) 1395 1396 # noop if threads library not available 1397 self._nthreads_plan_setter(threads) 1398 1399 # Set the timelimit 1400 set_timelimit_func(_planning_timelimit) 1401 1402 # Finally, construct the plan, after acquiring the global planner lock 1403 # (so that only one python thread can plan at a time, as the FFTW 1404 # planning functions are not thread-safe) 1405 1406 # no self-lookups allowed in nogil block, so must grab all these first 1407 cdef void *plan 1408 cdef fftw_generic_plan_guru fftw_planner = self._fftw_planner 1409 cdef int rank = self._rank 1410 cdef fftw_iodim *dims = <fftw_iodim *>self._dims 1411 cdef int howmany_rank = self._howmany_rank 1412 cdef fftw_iodim *howmany_dims = <fftw_iodim *>self._howmany_dims 1413 cdef void *_in = <void *>np.PyArray_DATA(self._input_array) 1414 cdef void *_out = <void *>np.PyArray_DATA(self._output_array) 1415 cdef unsigned c_flags = self._flags 1416 1417 with plan_lock, nogil: 1418 plan = fftw_planner(rank, dims, howmany_rank, howmany_dims, 1419 _in, _out, self._direction, c_flags) 1420 self._plan = plan 1421 1422 if self._plan == NULL: 1423 if 'FFTW_WISDOM_ONLY' in flags: 1424 raise RuntimeError('No FFTW wisdom is known for this plan.') 1425 else: 1426 raise RuntimeError('The data has an uncaught error that led '+ 1427 'to the planner returning NULL. This is a bug.') 1428 1429 def __init__(self, input_array, output_array, axes=(-1,), 1430 direction='FFTW_FORWARD', flags=('FFTW_MEASURE',), 1431 int threads=1, planning_timelimit=None, 1432 normalise_idft=True, ortho=False): 1433 ''' 1434 **Arguments**: 1435 1436 * ``input_array`` and ``output_array`` should be numpy arrays. 1437 The contents of these arrays will be destroyed by the planning 1438 process during initialisation. Information on supported 1439 dtypes for the arrays is :ref:`given below <scheme_table>`. 1440 1441 * ``axes`` describes along which axes the DFT should be taken. 1442 This should be a valid list of axes. Repeated axes are 1443 only transformed once. Invalid axes will raise an ``IndexError`` 1444 exception. This argument is equivalent to the same 1445 argument in :func:`numpy.fft.fftn`, except for the fact that 1446 the behaviour of repeated axes is different (``numpy.fft`` 1447 will happily take the fft of the same axis if it is repeated 1448 in the ``axes`` argument). Rudimentary testing has suggested 1449 this is down to the underlying FFTW library and so unlikely 1450 to be fixed in these wrappers. 1451 1452 * The ``direction`` parameter describes what sort of 1453 transformation the object should compute. This parameter is 1454 poorly named for historical reasons: older versions of pyFFTW 1455 only supported forward and backward transformations, for which 1456 this name made sense. Since then pyFFTW has been expanded to 1457 support real to real transforms as well and the name is not 1458 quite as descriptive. 1459 1460 ``direction`` should either be a string, or, in the case of 1461 multiple real transforms, a list of strings. The two values 1462 corresponding to the DFT are 1463 1464 * ``'FFTW_FORWARD'``, which is the forward discrete Fourier 1465 transform, and 1466 * ``'FFTW_BACKWARD'``, which is the backward discrete Fourier 1467 transform. 1468 1469 Note that, for the two above options, only the Complex schemes 1470 allow a free choice for ``direction``. The direction *must* 1471 agree with the the :ref:`table below <scheme_table>` if a Real 1472 scheme is used, otherwise a ``ValueError`` is raised. 1473 1474 1475 Alternatively, if you are interested in one of the real to real 1476 transforms, then pyFFTW supports four different discrete cosine 1477 transforms: 1478 1479 * ``'FFTW_REDFT00'``, 1480 * ``'FFTW_REDFT01'``, 1481 * ``'FFTW_REDFT10'``, and 1482 * ``'FFTW_REDFT01'``, 1483 1484 and four discrete sine transforms: 1485 1486 * ``'FFTW_RODFT00'``, 1487 * ``'FFTW_RODFT01'``, 1488 * ``'FFTW_RODFT10'``, and 1489 * ``'FFTW_RODFT01'``. 1490 1491 pyFFTW uses the same naming convention for these flags as FFTW: 1492 the ``'REDFT'`` part of the name is an acronym for 'real even 1493 discrete Fourier transform, and, similarly, ``'RODFT'`` stands 1494 for 'real odd discrete Fourier transform'. The trailing ``'0'`` 1495 is notation for even data (in terms of symmetry) and the 1496 trailing ``'1'`` is for odd data. 1497 1498 Unlike the plain discrete Fourier transform, one may specify a 1499 different real to real transformation over each axis: for example, 1500 1501 .. code-block:: none 1502 a = pyfftw.empty_aligned((128,128,128)) 1503 b = pyfftw.empty_aligned((128,128,128)) 1504 directions = ['FFTW_REDFT00', 'FFTW_RODFT11'] 1505 transform = pyfftw.FFTW(a, b, axes=(0, 2), direction=directions) 1506 1507 will create a transformation across the first and last axes 1508 with a discrete cosine transform over the first and a discrete 1509 sine transform over the last. 1510 1511 Unfortunately, since this class is ultimately just a wrapper 1512 for various transforms implemented in FFTW, one cannot combine 1513 real transformations with real to complex transformations in a 1514 single object. 1515 1516 .. _FFTW_flags: 1517 1518 * ``flags`` is a list of strings and is a subset of the 1519 flags that FFTW allows for the planners: 1520 1521 * ``'FFTW_ESTIMATE'``, ``'FFTW_MEASURE'``, ``'FFTW_PATIENT'`` and 1522 ``'FFTW_EXHAUSTIVE'`` are supported. These describe the 1523 increasing amount of effort spent during the planning 1524 stage to create the fastest possible transform. 1525 Usually ``'FFTW_MEASURE'`` is a good compromise. If no flag 1526 is passed, the default ``'FFTW_MEASURE'`` is used. 1527 * ``'FFTW_UNALIGNED'`` is supported. 1528 This tells FFTW not to assume anything about the 1529 alignment of the data and disabling any SIMD capability 1530 (see below). 1531 * ``'FFTW_DESTROY_INPUT'`` is supported. 1532 This tells FFTW that the input array can be destroyed during 1533 the transform, sometimes allowing a faster algorithm to be 1534 used. The default behaviour is, if possible, to preserve the 1535 input. In the case of the 1D Backwards Real transform, this 1536 may result in a performance hit. In the case of a backwards 1537 real transform for greater than one dimension, it is not 1538 possible to preserve the input, making this flag implicit 1539 in that case. A little more on this is given 1540 :ref:`below<scheme_table>`. 1541 * ``'FFTW_WISDOM_ONLY'`` is supported. 1542 This tells FFTW to raise an error if no plan for this transform 1543 and data type is already in the wisdom. It thus provides a method 1544 to determine whether planning would require additional effort or the 1545 cached wisdom can be used. This flag should be combined with the 1546 various planning-effort flags (``'FFTW_ESTIMATE'``, 1547 ``'FFTW_MEASURE'``, etc.); if so, then an error will be raised if 1548 wisdom derived from that level of planning effort (or higher) is 1549 not present. If no planning-effort flag is used, the default of 1550 ``'FFTW_ESTIMATE'`` is assumed. 1551 Note that wisdom is specific to all the parameters, including the 1552 data alignment. That is, if wisdom was generated with input/output 1553 arrays with one specific alignment, using ``'FFTW_WISDOM_ONLY'`` 1554 to create a plan for arrays with any different alignment will 1555 cause the ``'FFTW_WISDOM_ONLY'`` planning to fail. Thus it is 1556 important to specifically control the data alignment to make the 1557 best use of ``'FFTW_WISDOM_ONLY'``. 1558 1559 The `FFTW planner flags documentation 1560 <http://www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags>`_ 1561 has more information about the various flags and their impact. 1562 Note that only the flags documented here are supported. 1563 1564 * ``threads`` tells the wrapper how many threads to use 1565 when invoking FFTW, with a default of 1. If the number 1566 of threads is greater than 1, then the GIL is released 1567 by necessity. 1568 1569 * ``planning_timelimit`` is a floating point number that 1570 indicates to the underlying FFTW planner the maximum number of 1571 seconds it should spend planning the FFT. This is a rough 1572 estimate and corresponds to calling of ``fftw_set_timelimit()`` 1573 (or an equivalent dependent on type) in the underlying FFTW 1574 library. If ``None`` is set, the planner will run indefinitely 1575 until all the planning modes allowed by the flags have been 1576 tried. See the `FFTW planner flags page 1577 <http://www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags>`_ 1578 for more information on this. 1579 1580 .. _fftw_schemes: 1581 1582 **Schemes** 1583 1584 The currently supported full (so not discrete sine or discrete 1585 cosine) DFT schemes are as follows: 1586 1587 .. _scheme_table: 1588 1589 +----------------+-----------------------+------------------------+-----------+ 1590 | Type | ``input_array.dtype`` | ``output_array.dtype`` | Direction | 1591 +================+=======================+========================+===========+ 1592 | Complex | ``complex64`` | ``complex64`` | Both | 1593 +----------------+-----------------------+------------------------+-----------+ 1594 | Complex | ``complex128`` | ``complex128`` | Both | 1595 +----------------+-----------------------+------------------------+-----------+ 1596 | Complex | ``clongdouble`` | ``clongdouble`` | Both | 1597 +----------------+-----------------------+------------------------+-----------+ 1598 | Real | ``float32`` | ``complex64`` | Forwards | 1599 +----------------+-----------------------+------------------------+-----------+ 1600 | Real | ``float64`` | ``complex128`` | Forwards | 1601 +----------------+-----------------------+------------------------+-----------+ 1602 | Real | ``longdouble`` | ``clongdouble`` | Forwards | 1603 +----------------+-----------------------+------------------------+-----------+ 1604 | Real\ :sup:`1` | ``complex64`` | ``float32`` | Backwards | 1605 +----------------+-----------------------+------------------------+-----------+ 1606 | Real\ :sup:`1` | ``complex128`` | ``float64`` | Backwards | 1607 +----------------+-----------------------+------------------------+-----------+ 1608 | Real\ :sup:`1` | ``clongdouble`` | ``longdouble`` | Backwards | 1609 +----------------+-----------------------+------------------------+-----------+ 1610 1611 \ :sup:`1` Note that the Backwards Real transform for the case 1612 in which the dimensionality of the transform is greater than 1 1613 will destroy the input array. This is inherent to FFTW and the only 1614 general work-around for this is to copy the array prior to 1615 performing the transform. In the case where the dimensionality 1616 of the transform is 1, the default is to preserve the input array. 1617 This is different from the default in the underlying library, and 1618 some speed gain may be achieved by allowing the input array to 1619 be destroyed by passing the ``'FFTW_DESTROY_INPUT'`` 1620 :ref:`flag <FFTW_flags>`. 1621 1622 The discrete sine and discrete cosine transforms are supported 1623 for all three real types. 1624 1625 ``clongdouble`` typically maps directly to ``complex256`` 1626 or ``complex192``, and ``longdouble`` to ``float128`` or 1627 ``float96``, dependent on platform. 1628 1629 The relative shapes of the arrays should be as follows: 1630 1631 * For a Complex transform, ``output_array.shape == input_array.shape`` 1632 * For a Real transform in the Forwards direction, both the following 1633 should be true: 1634 1635 * ``output_array.shape[axes][-1] == input_array.shape[axes][-1]//2 + 1`` 1636 * All the other axes should be equal in length. 1637 1638 * For a Real transform in the Backwards direction, both the following 1639 should be true: 1640 1641 * ``input_array.shape[axes][-1] == output_array.shape[axes][-1]//2 + 1`` 1642 * All the other axes should be equal in length. 1643 1644 In the above expressions for the Real transform, the ``axes`` 1645 arguments denotes the unique set of axes on which we are taking 1646 the FFT, in the order passed. It is the last of these axes that 1647 is subject to the special case shown. 1648 1649 The shapes for the real transforms corresponds to those 1650 stipulated by the FFTW library. Further information can be 1651 found in the FFTW documentation on the `real DFT 1652 <http://www.fftw.org/fftw3_doc/Guru-Real_002ddata-DFTs.html>`_. 1653 1654 The actual arrangement in memory is arbitrary and the scheme 1655 can be planned for any set of strides on either the input 1656 or the output. The user should not have to worry about this 1657 and any valid numpy array should work just fine. 1658 1659 What is calculated is exactly what FFTW calculates. 1660 Notably, this is an unnormalized transform so should 1661 be scaled as necessary (fft followed by ifft will scale 1662 the input by N, the product of the dimensions along which 1663 the DFT is taken). For further information, see the 1664 `FFTW documentation 1665 <http://www.fftw.org/fftw3_doc/What-FFTW-Really-Computes.html>`_. 1666 1667 The FFTW library benefits greatly from the beginning of each 1668 DFT axes being aligned on the correct byte boundary, enabling 1669 SIMD instructions. By default, if the data begins on such a 1670 boundary, then FFTW will be allowed to try and enable 1671 SIMD instructions. This means that all future changes to 1672 the data arrays will be checked for similar alignment. SIMD 1673 instructions can be explicitly disabled by setting the 1674 FFTW_UNALIGNED flags, to allow for updates with unaligned 1675 data. 1676 1677 :func:`~pyfftw.byte_align` and 1678 :func:`~pyfftw.empty_aligned` are two methods 1679 included with this module for producing aligned arrays. 1680 1681 The optimum alignment for the running platform is provided 1682 by :data:`pyfftw.simd_alignment`, though a different alignment 1683 may still result in some performance improvement. For example, 1684 if the processor supports AVX (requiring 32-byte alignment) as 1685 well as SSE (requiring 16-byte alignment), then if the array 1686 is 16-byte aligned, SSE will still be used. 1687 1688 It's worth noting that just being aligned may not be sufficient 1689 to create the fastest possible transform. For example, if the 1690 array is not contiguous (i.e. certain axes are displaced in 1691 memory), it may be faster to plan a transform for a contiguous 1692 array, and then rely on the array being copied in before the 1693 transform (which :class:`pyfftw.FFTW` will handle for you when 1694 accessed through :meth:`~pyfftw.FFTW.__call__`). 1695 ''' 1696 1697 def __dealloc__(self): 1698 1699 if not self._axes == NULL: 1700 free(self._axes) 1701 1702 if not self._not_axes == NULL: 1703 free(self._not_axes) 1704 1705 if not self._plan == NULL: 1706 self._fftw_destroy(self._plan) 1707 1708 if not self._dims == NULL: 1709 free(self._dims) 1710 1711 if not self._howmany_dims == NULL: 1712 free(self._howmany_dims) 1713 1714 if not self._direction == NULL: 1715 free(self._direction) 1716 1717 def __call__(self, input_array=None, output_array=None, 1718 normalise_idft=None, ortho=None): 1719 '''__call__(input_array=None, output_array=None, normalise_idft=True, 1720 ortho=False) 1721 1722 Calling the class instance (optionally) updates the arrays, then 1723 calls :meth:`~pyfftw.FFTW.execute`, before optionally normalising 1724 the output and returning the output array. 1725 1726 It has some built-in helpers to make life simpler for the calling 1727 functions (as distinct from manually updating the arrays and 1728 calling :meth:`~pyfftw.FFTW.execute`). 1729 1730 If ``normalise_idft`` is ``True`` (the default), then the output from 1731 an inverse DFT (i.e. when the direction flag is ``'FFTW_BACKWARD'``) is 1732 scaled by 1/N, where N is the product of the lengths of input array on 1733 which the FFT is taken. If the direction is ``'FFTW_FORWARD'``, this 1734 flag makes no difference to the output array. 1735 1736 If ``ortho`` is ``True``, then the output of both forward 1737 and inverse DFT operations is scaled by 1/sqrt(N), where N is the 1738 product of the lengths of input array on which the FFT is taken. This 1739 ensures that the DFT is a unitary operation, meaning that it satisfies 1740 Parseval's theorem (the sum of the squared values of the transform 1741 output is equal to the sum of the squared values of the input). In 1742 other words, the energy of the signal is preserved. 1743 1744 If either ``normalise_idft`` or ``ortho`` are ``True``, then 1745 ifft(fft(A)) = A. 1746 1747 When ``input_array`` is something other than None, then the passed in 1748 array is coerced to be the same dtype as the input array used when the 1749 class was instantiated, the byte-alignment of the passed in array is 1750 made consistent with the expected byte-alignment and the striding is 1751 made consistent with the expected striding. All this may, but not 1752 necessarily, require a copy to be made. 1753 1754 As noted in the :ref:`scheme table<scheme_table>`, if the FFTW 1755 instance describes a backwards real transform of more than one 1756 dimension, the contents of the input array will be destroyed. It is 1757 up to the calling function to make a copy if it is necessary to 1758 maintain the input array. 1759 1760 ``output_array`` is always used as-is if possible. If the dtype, the 1761 alignment or the striding is incorrect for the FFTW object, then a 1762 ``ValueError`` is raised. 1763 1764 The coerced input array and the output array (as appropriate) are 1765 then passed as arguments to 1766 :meth:`~pyfftw.FFTW.update_arrays`, after which 1767 :meth:`~pyfftw.FFTW.execute` is called, and then normalisation 1768 is applied to the output array if that is desired. 1769 1770 Note that it is possible to pass some data structure that can be 1771 converted to an array, such as a list, so long as it fits the data 1772 requirements of the class instance, such as array shape. 1773 1774 Other than the dtype and the alignment of the passed in arrays, the 1775 rest of the requirements on the arrays mandated by 1776 :meth:`~pyfftw.FFTW.update_arrays` are enforced. 1777 1778 A ``None`` argument to either keyword means that that array is not 1779 updated. 1780 1781 The result of the FFT is returned. This is the same array that is used 1782 internally and will be overwritten again on subsequent calls. If you 1783 need the data to persist longer than a subsequent call, you should 1784 copy the returned array. 1785 ''' 1786 1787 if ortho is None: 1788 ortho = self._ortho 1789 if normalise_idft is None: 1790 normalise_idft = self._normalise_idft 1791 1792 if ortho and normalise_idft: 1793 raise ValueError('Invalid options: ortho and normalise_idft cannot' 1794 ' both be True.') 1795 1796 if input_array is not None or output_array is not None: 1797 1798 if input_array is None: 1799 input_array = self._input_array 1800 1801 if output_array is None: 1802 output_array = self._output_array 1803 1804 if not isinstance(input_array, np.ndarray): 1805 copy_needed = True 1806 elif (not input_array.dtype == self._input_dtype): 1807 copy_needed = True 1808 elif (not input_array.strides == self._input_strides): 1809 copy_needed = True 1810 elif not (<intptr_t>np.PyArray_DATA(input_array) 1811 % self.input_alignment == 0): 1812 copy_needed = True 1813 else: 1814 copy_needed = False 1815 1816 if copy_needed: 1817 1818 if not isinstance(input_array, np.ndarray): 1819 input_array = np.asanyarray(input_array) 1820 1821 if not input_array.shape == self._input_shape: 1822 raise ValueError('Invalid input shape: ' 1823 'The new input array should be the same shape ' 1824 'as the input array used to instantiate the ' 1825 'object.') 1826 1827 self._input_array[:] = input_array 1828 1829 if output_array is not None: 1830 # No point wasting time if no update is necessary 1831 # (which the copy above may have avoided) 1832 input_array = self._input_array 1833 self.update_arrays(input_array, output_array) 1834 1835 else: 1836 self.update_arrays(input_array, output_array) 1837 1838 self.execute() 1839 1840 # after executing, optionally normalize output array 1841 if ortho: 1842 self._output_array *= self._sqrt_normalisation_scaling 1843 elif normalise_idft and self._direction[0] == FFTW_BACKWARD: 1844 self._output_array *= self._normalisation_scaling 1845 elif not normalise_idft and self._direction[0] == FFTW_FORWARD: 1846 self._output_array *= self._normalisation_scaling 1847 1848 return self._output_array 1849 1850 cpdef update_arrays(self, 1851 new_input_array, new_output_array): 1852 '''update_arrays(new_input_array, new_output_array) 1853 1854 Update the arrays upon which the DFT is taken. 1855 1856 The new arrays should be of the same dtypes as the originals, the same 1857 shapes as the originals and should have the same strides between axes. 1858 If the original data was aligned so as to allow SIMD instructions 1859 (e.g. by being aligned on a 16-byte boundary), then the new array must 1860 also be aligned so as to allow SIMD instructions (assuming, of 1861 course, that the ``FFTW_UNALIGNED`` flag was not enabled). 1862 1863 The byte alignment requirement extends to requiring natural 1864 alignment in the non-SIMD cases as well, but this is much less 1865 stringent as it simply means avoiding arrays shifted by, say, 1866 a single byte (which invariably takes some effort to 1867 achieve!). 1868 1869 If all these conditions are not met, a ``ValueError`` will 1870 be raised and the data will *not* be updated (though the 1871 object will still be in a sane state). 1872 ''' 1873 if not isinstance(new_input_array, np.ndarray): 1874 raise ValueError('Invalid input array: ' 1875 'The new input array needs to be an instance ' 1876 'of numpy.ndarray') 1877 1878 if not isinstance(new_output_array, np.ndarray): 1879 raise ValueError('Invalid output array ' 1880 'The new output array needs to be an instance ' 1881 'of numpy.ndarray') 1882 1883 if not (<intptr_t>np.PyArray_DATA(new_input_array) % 1884 self.input_alignment == 0): 1885 raise ValueError('Invalid input alignment: ' 1886 'The original arrays were %d-byte aligned. It is ' 1887 'necessary that the update input array is similarly ' 1888 'aligned.' % self.input_alignment) 1889 1890 if not (<intptr_t>np.PyArray_DATA(new_output_array) % 1891 self.output_alignment == 0): 1892 raise ValueError('Invalid output alignment: ' 1893 'The original arrays were %d-byte aligned. It is ' 1894 'necessary that the update output array is similarly ' 1895 'aligned.' % self.output_alignment) 1896 1897 if not new_input_array.dtype == self._input_dtype: 1898 raise ValueError('Invalid input dtype: ' 1899 'The new input array is not of the same ' 1900 'dtype as was originally planned for.') 1901 1902 if not new_output_array.dtype == self._output_dtype: 1903 raise ValueError('Invalid output dtype: ' 1904 'The new output array is not of the same ' 1905 'dtype as was originally planned for.') 1906 1907 new_input_shape = new_input_array.shape 1908 new_output_shape = new_output_array.shape 1909 1910 new_input_strides = new_input_array.strides 1911 new_output_strides = new_output_array.strides 1912 1913 if not new_input_shape == self._input_shape: 1914 raise ValueError('Invalid input shape: ' 1915 'The new input array should be the same shape as ' 1916 'the input array used to instantiate the object.') 1917 1918 if not new_output_shape == self._output_shape: 1919 raise ValueError('Invalid output shape: ' 1920 'The new output array should be the same shape as ' 1921 'the output array used to instantiate the object.') 1922 1923 if not new_input_strides == self._input_strides: 1924 raise ValueError('Invalid input striding: ' 1925 'The strides should be identical for the new ' 1926 'input array as for the old.') 1927 1928 if not new_output_strides == self._output_strides: 1929 raise ValueError('Invalid output striding: ' 1930 'The strides should be identical for the new ' 1931 'output array as for the old.') 1932 1933 self._update_arrays(new_input_array, new_output_array) 1934 1935 cdef _update_arrays(self, 1936 np.ndarray new_input_array, np.ndarray new_output_array): 1937 ''' A C interface to the update_arrays method that does not 1938 perform any checks on strides being correct and so on. 1939 ''' 1940 self._input_array = new_input_array 1941 self._output_array = new_output_array 1942 1943 def get_input_array(self): 1944 '''get_input_array() 1945 1946 Return the input array that is associated with the FFTW 1947 instance. 1948 1949 *Deprecated since 0.10. Consider using the* :attr:`FFTW.input_array` 1950 *property instead.* 1951 ''' 1952 warnings.warn('get_input_array is deprecated. ' 1953 'Consider using the input_array property instead.', 1954 DeprecationWarning) 1955 1956 return self._input_array 1957 1958 def get_output_array(self): 1959 '''get_output_array() 1960 1961 Return the output array that is associated with the FFTW 1962 instance. 1963 1964 *Deprecated since 0.10. Consider using the* :attr:`FFTW.output_array` 1965 *property instead.* 1966 ''' 1967 warnings.warn('get_output_array is deprecated. ' 1968 'Consider using the output_array property instead.', 1969 DeprecationWarning) 1970 1971 return self._output_array 1972 1973 cpdef execute(self): 1974 '''execute() 1975 1976 Execute the planned operation, taking the correct kind of FFT of 1977 the input array (i.e. :attr:`FFTW.input_array`), 1978 and putting the result in the output array (i.e. 1979 :attr:`FFTW.output_array`). 1980 ''' 1981 cdef void *input_pointer = ( 1982 <void *>np.PyArray_DATA(self._input_array)) 1983 cdef void *output_pointer = ( 1984 <void *>np.PyArray_DATA(self._output_array)) 1985 1986 cdef void *plan = self._plan 1987 cdef fftw_generic_execute fftw_execute = self._fftw_execute 1988 with nogil: 1989 fftw_execute(plan, input_pointer, output_pointer) 1990 1991cdef void count_char(char c, void *counter_ptr): 1992 ''' 1993 On every call, increment the derefenced counter_ptr. 1994 ''' 1995 (<int *>counter_ptr)[0] += 1 1996 1997 1998cdef void write_char_to_string(char c, void *string_location_ptr): 1999 ''' 2000 Write the passed character c to the memory location 2001 pointed to by the contents of string_location_ptr (i.e. a pointer 2002 to a pointer), then increment the contents of string_location_ptr 2003 (i.e. move to the next byte in memory). 2004 2005 In other words, for every character that is passed, we write that 2006 to a string that is referenced by the dereferenced value of 2007 string_location_ptr. 2008 2009 If the derefenced value of string_location points to an 2010 unallocated piece of memory, a segfault will likely occur. 2011 ''' 2012 cdef char *write_location = <char *>((<intptr_t *>string_location_ptr)[0]) 2013 write_location[0] = c 2014 2015 (<intptr_t *>string_location_ptr)[0] += 1 2016 2017 2018def export_wisdom(): 2019 '''export_wisdom() 2020 2021 Return the FFTW wisdom as a tuple of strings. 2022 2023 The first string in the tuple is the string for the double precision 2024 wisdom, the second is for single precision, and the third for long double 2025 precision. If any of the precisions is not supported in the build, the 2026 string is empty. 2027 2028 The tuple that is returned from this function can be used as the argument 2029 to :func:`~pyfftw.import_wisdom`. 2030 2031 ''' 2032 2033 cdef: 2034 # can't directly initialize `bytes` with '' 2035 const char* empty = '' 2036 bytes py_wisdom = empty 2037 bytes py_wisdomf = empty 2038 bytes py_wisdoml = empty 2039 2040 # default init to zero 2041 cdef int counter = 0 2042 cdef int counterf = 0 2043 cdef int counterl = 0 2044 2045 char* c_wisdom = NULL 2046 char* c_wisdomf = NULL 2047 char* c_wisdoml = NULL 2048 2049 # count the length of the string and extract it manually rather than using 2050 # `fftw_export_wisdom_to_string` to avoid calling `free` on the string 2051 # potentially allocated by a different C library; see #3 2052 IF HAVE_DOUBLE: 2053 fftw_export_wisdom(&count_char, <void *>&counter) 2054 c_wisdom = <char *>malloc(sizeof(char)*(counter + 1)) 2055 if c_wisdom == NULL: 2056 raise MemoryError 2057 # Set the pointers to the string pointers 2058 cdef intptr_t c_wisdom_ptr = <intptr_t>c_wisdom 2059 fftw_export_wisdom(&write_char_to_string, <void *>&c_wisdom_ptr) 2060 # Write the last byte as the null byte 2061 c_wisdom[counter] = 0 2062 try: 2063 py_wisdom = c_wisdom 2064 finally: 2065 free(c_wisdom) 2066 IF HAVE_SINGLE: 2067 fftwf_export_wisdom(&count_char, <void *>&counterf) 2068 c_wisdomf = <char *>malloc(sizeof(char)*(counterf + 1)) 2069 if c_wisdomf == NULL: 2070 raise MemoryError 2071 cdef intptr_t c_wisdomf_ptr = <intptr_t>c_wisdomf 2072 fftwf_export_wisdom(&write_char_to_string, <void *>&c_wisdomf_ptr) 2073 c_wisdomf[counterf] = 0 2074 try: 2075 py_wisdomf = c_wisdomf 2076 finally: 2077 free(c_wisdomf) 2078 IF HAVE_LONG: 2079 fftwl_export_wisdom(&count_char, <void *>&counterl) 2080 c_wisdoml = <char *>malloc(sizeof(char)*(counterl + 1)) 2081 if c_wisdoml == NULL: 2082 raise MemoryError 2083 cdef intptr_t c_wisdoml_ptr = <intptr_t>c_wisdoml 2084 fftwl_export_wisdom(&write_char_to_string, <void *>&c_wisdoml_ptr) 2085 c_wisdoml[counterl] = 0 2086 try: 2087 py_wisdoml = c_wisdoml 2088 finally: 2089 free(c_wisdoml) 2090 2091 return (py_wisdom, py_wisdomf, py_wisdoml) 2092 2093def import_wisdom(wisdom): 2094 '''import_wisdom(wisdom) 2095 2096 Function that imports wisdom from the passed tuple 2097 of strings. 2098 2099 The first string in the tuple is the string for the double 2100 precision wisdom. The second string in the tuple is the string 2101 for the single precision wisdom. The third string in the tuple 2102 is the string for the long double precision wisdom. 2103 2104 The tuple that is returned from :func:`~pyfftw.export_wisdom` 2105 can be used as the argument to this function. 2106 2107 This function returns a tuple of boolean values indicating 2108 the success of loading each of the wisdom types (double, float 2109 and long double, in that order). 2110 ''' 2111 2112 cdef: 2113 char* c_wisdom = wisdom[0] 2114 char* c_wisdomf = wisdom[1] 2115 char* c_wisdoml = wisdom[2] 2116 2117 bint success = False 2118 bint successf = False 2119 bint successl = False 2120 2121 IF HAVE_DOUBLE: 2122 success = fftw_import_wisdom_from_string(c_wisdom) 2123 IF HAVE_SINGLE: 2124 successf = fftwf_import_wisdom_from_string(c_wisdomf) 2125 IF HAVE_LONG: 2126 successl = fftwl_import_wisdom_from_string(c_wisdoml) 2127 return (success, successf, successl) 2128 2129#def export_wisdom_to_files( 2130# double_wisdom_file=None, 2131# single_wisdom_file=None, 2132# long_double_wisdom_file=None): 2133# '''export_wisdom_to_file(double_wisdom_file=None, single_wisdom_file=None, long_double_wisdom_file=None) 2134# 2135# Export the wisdom to the passed files. 2136# 2137# The double precision wisdom is written to double_wisdom_file. 2138# The single precision wisdom is written to single_wisdom_file. 2139# The long double precision wisdom is written to 2140# long_double_wisdom_file. 2141# 2142# If any of the arguments are None, then nothing is done for that 2143# file. 2144# 2145# This function returns a tuple of boolean values indicating 2146# the success of storing each of the wisdom types (double, float 2147# and long double, in that order). 2148# ''' 2149# cdef bint success = True 2150# cdef bint successf = True 2151# cdef bint successl = True 2152# 2153# cdef char *_double_wisdom_file 2154# cdef char *_single_wisdom_file 2155# cdef char *_long_double_wisdom_file 2156# 2157# 2158# if double_wisdom_file is not None: 2159# _double_wisdom_file = double_wisdom_file 2160# success = fftw_export_wisdom_to_filename(_double_wisdom_file) 2161# 2162# if single_wisdom_file is not None: 2163# _single_wisdom_file = single_wisdom_file 2164# successf = fftwf_export_wisdom_to_filename(_single_wisdom_file) 2165# 2166# if long_double_wisdom_file is not None: 2167# _long_double_wisdom_file = long_double_wisdom_file 2168# successl = fftwl_export_wisdom_to_filename( 2169# _long_double_wisdom_file) 2170# 2171# return (success, successf, successl) 2172# 2173#def import_wisdom_to_files( 2174# double_wisdom_file=None, 2175# single_wisdom_file=None, 2176# long_double_wisdom_file=None): 2177# '''import_wisdom_to_file(double_wisdom_file=None, single_wisdom_file=None, long_double_wisdom_file=None) 2178# 2179# import the wisdom to the passed files. 2180# 2181# The double precision wisdom is imported from double_wisdom_file. 2182# The single precision wisdom is imported from single_wisdom_file. 2183# The long double precision wisdom is imported from 2184# long_double_wisdom_file. 2185# 2186# If any of the arguments are None, then nothing is done for that 2187# file. 2188# 2189# This function returns a tuple of boolean values indicating 2190# the success of loading each of the wisdom types (double, float 2191# and long double, in that order). 2192# ''' 2193# cdef bint success = True 2194# cdef bint successf = True 2195# cdef bint successl = True 2196# 2197# cdef char *_double_wisdom_file 2198# cdef char *_single_wisdom_file 2199# cdef char *_long_double_wisdom_file 2200# 2201# if double_wisdom_file is not None: 2202# _double_wisdom_file = double_wisdom_file 2203# success = fftw_import_wisdom_from_filename(_double_wisdom_file) 2204# 2205# if single_wisdom_file is not None: 2206# _single_wisdom_file = single_wisdom_file 2207# successf = fftwf_import_wisdom_from_filename(_single_wisdom_file) 2208# 2209# if long_double_wisdom_file is not None: 2210# _long_double_wisdom_file = long_double_wisdom_file 2211# successl = fftwl_import_wisdom_from_filename( 2212# _long_double_wisdom_file) 2213# 2214# return (success, successf, successl) 2215 2216def forget_wisdom(): 2217 '''forget_wisdom() 2218 2219 Forget all the accumulated wisdom. 2220 ''' 2221 IF HAVE_DOUBLE: 2222 fftw_forget_wisdom() 2223 IF HAVE_SINGLE: 2224 fftwf_forget_wisdom() 2225 IF HAVE_LONG: 2226 fftwl_forget_wisdom() 2227