diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..5144dc0 --- /dev/null +++ b/.flake8 @@ -0,0 +1,53 @@ +[flake8] +extend-ignore = + # whitespace before ':' (currently conflicts with black formatting): + E203, + # line too long (in docstrings): + E501, + # ‘from module import *’ used; unable to detect undefined names: + F403, + # doc line too long (105 > 80 characters): + W505, + # missing docstring in public module: + D100, + # missing docstring in public class: + D101, + # missing docstring in public method: + D102, + # missing docstring in public function: + D103, + # missing docstring in public package: + D104, + # missing docstring in magic method: + D105, + # missing docstring in __init__: + D107, + # no blank lines allowed after function docstring: + D202, + # 1 blank line required between summary line and description: + D205, + # first line should end with a period: + D400, + # first line should be in imperative mood: + D401, + # first line should not be the function's "signature": + D402, + # first word of the first line should be properly capitalized + D403, + +per-file-ignores = + mkl_fft/__init__.py: E402, F401 + mkl_fft/interfaces/__init__.py: F401 + mkl_fft/interfaces/scipy_fft.py: F401 + mkl_fft/interfaces/numpy_fft.py: F401 + +exclude = _vendored/conv_template.py + +filename = *.py, *.pyx, *.pxi, *.pxd +max_line_length = 80 +max-doc-length = 80 +show-source = True + +# Print detailed statistic if any issue detected +count = True +statistics = True diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..bb237c2 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# $ git config blame.ignoreRevsFile .git-blame-ignore-revs + +# Add pre-commit hooks +2e1b33fcf6b7f0c7c9d7d5d7f55d2d0ba35f393a diff --git a/.github/workflows/conda-package-cf.yml b/.github/workflows/conda-package-cf.yml index a117b12..e87c62f 100644 --- a/.github/workflows/conda-package-cf.yml +++ b/.github/workflows/conda-package-cf.yml @@ -13,8 +13,8 @@ env: MODULE_NAME: mkl_fft TEST_ENV_NAME: test_mkl_fft VER_SCRIPT1: "import json; f = open('ver.json', 'r'); j = json.load(f); f.close(); d = j['mkl_fft'][0];" - VER_SCRIPT2: "print('='.join((d[s] for s in ('version', 'build'))))" - + VER_SCRIPT2: "print('='.join((d[s] for s in ('version', 'build'))))" + jobs: build: runs-on: ubuntu-latest @@ -280,4 +280,3 @@ jobs: shell: cmd /C CALL {0} run: >- conda activate ${{ env.TEST_ENV_NAME }} && python -m pytest -v -s --pyargs ${{ env.MODULE_NAME }} - diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 76445ee..d01f2de 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -13,7 +13,7 @@ env: MODULE_NAME: mkl_fft TEST_ENV_NAME: test_mkl_fft VER_SCRIPT1: "import json; f = open('ver.json', 'r'); j = json.load(f); f.close(); d = j['mkl_fft'][0];" - VER_SCRIPT2: "print('='.join((d[s] for s in ('version', 'build'))))" + VER_SCRIPT2: "print('='.join((d[s] for s in ('version', 'build'))))" jobs: build: @@ -278,4 +278,3 @@ jobs: shell: cmd /C CALL {0} run: >- conda activate ${{ env.TEST_ENV_NAME }} && python -m pytest -v -s --pyargs ${{ env.MODULE_NAME }} - diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..00da4d6 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,33 @@ +name: pre-commit + +on: + pull_request: + push: + branches: [master] + +permissions: read-all + +jobs: + pre-commit: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo + uses: actions/checkout@v4.2.2 + + - name: Set up python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - uses: BSFishy/pip-action@v1 + with: + packages: | + pylint + + - name: Version of clang-format + run: | + clang-format --version + + - name: Run pre-commit checks + uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..f2b742f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,76 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-ast + - id: check-builtin-literals + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-toml + - id: debug-statements + - id: destroyed-symlinks + - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: mixed-line-ending + - id: trailing-whitespace + +- repo: https://github.com/psf/black + rev: 25.1.0 + hooks: + - id: black + exclude: "_vendored/conv_template.py" + +- repo: https://github.com/pocc/pre-commit-hooks + rev: v1.3.5 + hooks: + - id: clang-format + args: ["-i"] + +- repo: https://github.com/pycqa/flake8 + rev: 7.1.2 + hooks: + - id: flake8 + args: ["--config=.flake8"] + additional_dependencies: + - flake8-docstrings==1.7.0 + - flake8-bugbear==24.4.26 + +- repo: https://github.com/pycqa/isort + rev: 6.0.1 + hooks: + - id: isort + name: isort (python) + - id: isort + name: isort (cython) + types: [cython] + - id: isort + name: isort (pyi) + types: [pyi] + +- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks + rev: v2.14.0 + hooks: + - id: pretty-format-toml + args: [--autofix] + +- repo: local + hooks: + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] + require_serial: true + args: + [ + "-rn", # Only display messages + "-sn", # Don't display the score + "--errors-only", + "--disable=import-error", + ] + +- repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shellcheck diff --git a/CHANGES.rst b/CHANGES.rst index 787d3b6..e2f379b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -125,7 +125,7 @@ Fix for issue #29. 1.0.7 ===== Improved exception message raised if MKL is signalling an error. The message now includes MKL's own description of the exception. -This partially improves #24. +This partially improves #24. Improved argument validation for ND transforms aligning with scipy 1.2.0 diff --git a/SECURITY.md b/SECURITY.md index 38d9c83..373608b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,5 @@ # Security Policy -Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. +Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. ## Reporting a Vulnerability -Please report any security vulnerabilities in this project utilizing the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). \ No newline at end of file +Please report any security vulnerabilities in this project utilizing the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). diff --git a/_vendored/README.md b/_vendored/README.md index 0ebafcb..b3f3a91 100644 --- a/_vendored/README.md +++ b/_vendored/README.md @@ -2,4 +2,4 @@ File `conv_template.py` is copied from NumPy's numpy/distutils folder, since `numpy.distutils` is absent from the installation layout starting with -Python 3.12 \ No newline at end of file +Python 3.12 diff --git a/conda-recipe-cf/build.sh b/conda-recipe-cf/build.sh index de18657..6f3bbdd 100644 --- a/conda-recipe-cf/build.sh +++ b/conda-recipe-cf/build.sh @@ -1,10 +1,9 @@ #!/bin/bash -x -if [ `uname` == Darwin ]; then +if [ "$(uname)" == Darwin ]; then export MACOSX_DEPLOYMENT_TARGET=10.9 fi export MKLROOT=$PREFIX export CFLAGS="-I$PREFIX/include $CFLAGS" $PYTHON -m pip install --no-build-isolation --no-deps . - diff --git a/conda-recipe/build.sh b/conda-recipe/build.sh index de18657..6f3bbdd 100644 --- a/conda-recipe/build.sh +++ b/conda-recipe/build.sh @@ -1,10 +1,9 @@ #!/bin/bash -x -if [ `uname` == Darwin ]; then +if [ "$(uname)" == Darwin ]; then export MACOSX_DEPLOYMENT_TARGET=10.9 fi export MKLROOT=$PREFIX export CFLAGS="-I$PREFIX/include $CFLAGS" $PYTHON -m pip install --no-build-isolation --no-deps . - diff --git a/mkl_fft/__init__.py b/mkl_fft/__init__.py index a836abc..d2c4155 100644 --- a/mkl_fft/__init__.py +++ b/mkl_fft/__init__.py @@ -24,14 +24,45 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import mkl_fft.interfaces + from . import _init_helper -from ._pydfti import (fft, ifft, fft2, ifft2, fftn, ifftn, rfftpack, irfftpack, - rfft, irfft, rfft2, irfft2, rfftn, irfftn) +# pylint: disable=no-name-in-module +from ._pydfti import ( + fft, + fft2, + fftn, + ifft, + ifft2, + ifftn, + irfft, + irfft2, + irfftn, + irfftpack, + rfft, + rfft2, + rfftn, + rfftpack, +) from ._version import __version__ -import mkl_fft.interfaces -__all__ = ['fft', 'ifft', 'fft2', 'ifft2', 'fftn', 'ifftn', 'rfftpack', 'irfftpack' - 'rfft', 'irfft', 'rfft2', 'irfft2', 'rfftn', 'irfftn','interfaces'] +__all__ = [ + "fft", + "ifft", + "fft2", + "ifft2", + "fftn", + "ifftn", + "rfftpack", + "irfftpack", + "rfft", + "irfft", + "rfft2", + "irfft2", + "rfftn", + "irfftn", + "interfaces", +] del _init_helper diff --git a/mkl_fft/_float_utils.py b/mkl_fft/_float_utils.py index 77e1322..b904476 100644 --- a/mkl_fft/_float_utils.py +++ b/mkl_fft/_float_utils.py @@ -26,12 +26,18 @@ import numpy as np -__all__ = ['__upcast_float16_array', '__downcast_float128_array', '__supported_array_or_not_implemented'] +__all__ = [ + "__upcast_float16_array", + "__downcast_float128_array", + "__supported_array_or_not_implemented", +] + def __upcast_float16_array(x): """ - Used in _scipy_fft to upcast float16 to float32, - instead of float64, as mkl_fft would do""" + Used in _scipy_fft to upcast float16 to float32, + instead of float64, as mkl_fft would do + """ if hasattr(x, "dtype"): xdt = x.dtype if xdt == np.half: @@ -53,8 +59,9 @@ def __upcast_float16_array(x): def __downcast_float128_array(x): """ - Used in _numpy_fft to unsafely downcast float128/complex256 to - complex128, instead of raising an error""" + Used in _numpy_fft to unsafely downcast float128/complex256 to + complex128, instead of raising an error + """ if hasattr(x, "dtype"): xdt = x.dtype if xdt == np.longdouble and not xdt == np.float64: @@ -79,9 +86,9 @@ def __supported_array_or_not_implemented(x): """ __x = np.asarray(x) black_list = [np.half] - if hasattr(np, 'float128'): + if hasattr(np, "float128"): black_list.append(np.float128) - if hasattr(np, 'complex256'): + if hasattr(np, "complex256"): black_list.append(np.complex256) if __x.dtype in black_list: return NotImplemented diff --git a/mkl_fft/_numpy_fft.py b/mkl_fft/_numpy_fft.py index 0a0a07d..6a660d7 100644 --- a/mkl_fft/_numpy_fft.py +++ b/mkl_fft/_numpy_fft.py @@ -53,32 +53,50 @@ """ -__all__ = ['fft', 'ifft', 'rfft', 'irfft', 'hfft', 'ihfft', 'rfftn', - 'irfftn', 'rfft2', 'irfft2', 'fft2', 'ifft2', 'fftn', 'ifftn'] +__all__ = [ + "fft", + "ifft", + "rfft", + "irfft", + "hfft", + "ihfft", + "rfftn", + "irfftn", + "rfft2", + "irfft2", + "fft2", + "ifft2", + "fftn", + "ifftn", +] -from numpy import (array, asarray, asanyarray, shape, conjugate, take, sqrt, prod) +import re + +from numpy import array, asanyarray, conjugate, prod, sqrt, take -import numpy -from . import _pydfti as mkl_fft from . import _float_utils -import re +from . import _pydfti as mkl_fft # pylint: disable=no-name-in-module + def _check_norm(norm): if norm not in (None, "ortho", "forward", "backward"): raise ValueError( - ("Invalid norm value {} should be None, " - "\"ortho\", \"forward\", or \"backward\".").format(norm)) + ( + "Invalid norm value {} should be None, " + '"ortho", "forward", or "backward".' + ).format(norm) + ) def frwd_sc_1d(n, s): nn = n if n is not None else s - return 1/nn if nn != 0 else 1 + return 1 / nn if nn != 0 else 1 def frwd_sc_nd(s, x_shape): ss = s if s is not None else x_shape nn = prod(ss) - return 1/nn if nn != 0 else 1 + return 1 / nn if nn != 0 else 1 def ortho_sc_1d(n, s): @@ -89,7 +107,7 @@ def trycall(func, args, kwrds): try: res = func(*args, **kwrds) except ValueError as ve: - if len(ve.args)==1: + if len(ve.args) == 1: if re.match("^Dimension n", ve.args[0]): raise ValueError("Invalid number of FFT data points") raise ve @@ -198,11 +216,7 @@ def fft(a, n=None, axis=-1, norm=None): else: fsc = ortho_sc_1d(n, x.shape[axis]) - return trycall( - mkl_fft.fft, - (x,), - {'n': n, 'axis': axis, - 'fwd_scale': fsc}) + return trycall(mkl_fft.fft, (x,), {"n": n, "axis": axis, "fwd_scale": fsc}) def ifft(a, n=None, axis=-1, norm=None): @@ -301,11 +315,7 @@ def ifft(a, n=None, axis=-1, norm=None): else: fsc = ortho_sc_1d(n, x.shape[axis]) - return trycall( - mkl_fft.ifft, - (x,), - {'n': n, 'axis': axis, - 'fwd_scale': fsc}) + return trycall(mkl_fft.ifft, (x,), {"n": n, "axis": axis, "fwd_scale": fsc}) def rfft(a, n=None, axis=-1, norm=None): @@ -402,11 +412,7 @@ def rfft(a, n=None, axis=-1, norm=None): else: fsc = ortho_sc_1d(n, x.shape[axis]) - return trycall( - mkl_fft.rfft, - (x,), - {'n': n, 'axis': axis, - 'fwd_scale': fsc}) + return trycall(mkl_fft.rfft, (x,), {"n": n, "axis": axis, "fwd_scale": fsc}) def irfft(a, n=None, axis=-1, norm=None): @@ -498,7 +504,7 @@ def irfft(a, n=None, axis=-1, norm=None): _check_norm(norm) x = _float_utils.__downcast_float128_array(a) - nn = n if n else 2*(x.shape[axis]-1) + nn = n if n else 2 * (x.shape[axis] - 1) if norm in (None, "backward"): fsc = 1.0 elif norm == "forward": @@ -507,10 +513,8 @@ def irfft(a, n=None, axis=-1, norm=None): fsc = ortho_sc_1d(nn, nn) return trycall( - mkl_fft.irfft, - (x,), - {'n': n, 'axis': axis, - 'fwd_scale': fsc}) + mkl_fft.irfft, (x,), {"n": n, "axis": axis, "fwd_scale": fsc} + ) def hfft(a, n=None, axis=-1, norm=None): @@ -593,9 +597,9 @@ def hfft(a, n=None, axis=-1, norm=None): x = _float_utils.__downcast_float128_array(a) x = array(x, copy=True, dtype=complex) conjugate(x, out=x) - - nn = n if n else 2*(x.shape[axis]-1) - if (norm in (None, "backward")): + + nn = n if n else 2 * (x.shape[axis] - 1) + if norm in (None, "backward"): fsc = frwd_sc_1d(nn, nn) elif norm == "forward": fsc = 1.0 @@ -603,10 +607,8 @@ def hfft(a, n=None, axis=-1, norm=None): fsc = ortho_sc_1d(nn, nn) return trycall( - mkl_fft.irfft, - (x,), - {'n': n, 'axis': axis, - 'fwd_scale': fsc}) + mkl_fft.irfft, (x,), {"n": n, "axis": axis, "fwd_scale": fsc} + ) def ihfft(a, n=None, axis=-1, norm=None): @@ -671,18 +673,16 @@ def ihfft(a, n=None, axis=-1, norm=None): x = _float_utils.__downcast_float128_array(a) x = array(x, copy=True, dtype=float) - if (norm in (None, 'backward')): + if norm in (None, "backward"): fsc = frwd_sc_1d(n, x.shape[axis]) - elif norm == 'forward': + elif norm == "forward": fsc = 1.0 else: fsc = ortho_sc_1d(n, x.shape[axis]) output = trycall( - mkl_fft.rfft, - (x,), - {'n': n, 'axis': axis, - 'fwd_scale': fsc}) + mkl_fft.rfft, (x,), {"n": n, "axis": axis, "fwd_scale": fsc} + ) conjugate(output, out=output) return output @@ -816,11 +816,7 @@ def fftn(a, s=None, axes=None, norm=None): else: fsc = sqrt(frwd_sc_nd(s, x.shape)) - return trycall( - mkl_fft.fftn, - (x,), - {'s': s, 'axes': axes, - 'fwd_scale': fsc}) + return trycall(mkl_fft.fftn, (x,), {"s": s, "axes": axes, "fwd_scale": fsc}) def ifftn(a, s=None, axes=None, norm=None): @@ -933,10 +929,8 @@ def ifftn(a, s=None, axes=None, norm=None): fsc = sqrt(frwd_sc_nd(s, x.shape)) return trycall( - mkl_fft.ifftn, - (x,), - {'s': s, 'axes': axes, - 'fwd_scale': fsc}) + mkl_fft.ifftn, (x,), {"s": s, "axes": axes, "fwd_scale": fsc} + ) def fft2(a, s=None, axes=(-2, -1), norm=None): @@ -1222,7 +1216,7 @@ def rfftn(a, s=None, axes=None, norm=None): _check_norm(norm) x = _float_utils.__downcast_float128_array(a) - if (norm in (None, "backward")): + if norm in (None, "backward"): fsc = 1.0 elif norm == "forward": x = asanyarray(x) @@ -1234,10 +1228,8 @@ def rfftn(a, s=None, axes=None, norm=None): fsc = sqrt(frwd_sc_nd(s, x.shape)) return trycall( - mkl_fft.rfftn, - (x,), - {'s': s, 'axes': axes, - 'fwd_scale': fsc}) + mkl_fft.rfftn, (x,), {"s": s, "axes": axes, "fwd_scale": fsc} + ) def rfft2(a, s=None, axes=(-2, -1), norm=None): @@ -1378,8 +1370,7 @@ def irfftn(a, s=None, axes=None, norm=None): _check_norm(norm) x = _float_utils.__downcast_float128_array(a) - - if (norm in (None, "backward")): + if norm in (None, "backward"): fsc = 1.0 elif norm == "forward": x = asanyarray(x) @@ -1391,10 +1382,8 @@ def irfftn(a, s=None, axes=None, norm=None): fsc = sqrt(frwd_sc_nd(s, x.shape)) return trycall( - mkl_fft.irfftn, - (x,), - {'s': s, 'axes': axes, - 'fwd_scale': fsc}) + mkl_fft.irfftn, (x,), {"s": s, "axes": axes, "fwd_scale": fsc} + ) def irfft2(a, s=None, axes=(-2, -1), norm=None): diff --git a/mkl_fft/_pydfti.pyx b/mkl_fft/_pydfti.pyx index ded8ce1..93794d4 100644 --- a/mkl_fft/_pydfti.pyx +++ b/mkl_fft/_pydfti.pyx @@ -28,20 +28,23 @@ # imports import sys + import numpy as np + if np.lib.NumpyVersion(np.__version__) >= "2.0.0a0": from numpy._core._multiarray_tests import internal_overlap else: from numpy.core._multiarray_tests import internal_overlap + from threading import local as threading_local # cimports + +cimport cpython.pycapsule cimport numpy as cnp +from cpython.exc cimport PyErr_Clear, PyErr_Occurred +from cpython.mem cimport PyMem_Free, PyMem_Malloc from libc.string cimport memcpy -cimport cpython.pycapsule -from cpython.exc cimport (PyErr_Occurred, PyErr_Clear) -from cpython.mem cimport (PyMem_Malloc, PyMem_Free) - # thread-local storage _tls = threading_local() diff --git a/mkl_fft/_scipy_fft.py b/mkl_fft/_scipy_fft.py index a9dd98b..3d9504a 100644 --- a/mkl_fft/_scipy_fft.py +++ b/mkl_fft/_scipy_fft.py @@ -24,16 +24,16 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from . import _pydfti as mkl_fft -from . import _float_utils -import mkl - -from numpy import (take, sqrt, prod) -import contextvars import contextlib +import contextvars import operator import os +import mkl +from numpy import prod, sqrt, take + +from . import _float_utils +from . import _pydfti as mkl_fft # pylint: disable=no-name-in-module __doc__ = """ This module implements interfaces mimicing `scipy.fft` module. @@ -48,6 +48,7 @@ scipy.fft.set_global_backend(be) """ + class _cpu_max_threads_count: def __init__(self): self.cpu_count = None @@ -61,6 +62,7 @@ def get_cpu_count(self): def get_max_threads_count(self): if self.max_threads_count is None: + # pylint: disable=no-member self.max_threads_count = mkl.get_max_threads() return self.max_threads_count @@ -83,17 +85,19 @@ def workers(self, workers_val): self.workerks_ = operator.index(workers_val) -_workers_global_settings = contextvars.ContextVar('scipy_backend_workers', default=_workers_data()) +_workers_global_settings = contextvars.ContextVar( + "scipy_backend_workers", default=_workers_data() +) def get_workers(): - "Gets the number of workers used by mkl_fft by default" + """Gets the number of workers used by mkl_fft by default""" return _workers_global_settings.get().workers @contextlib.contextmanager def set_workers(n_workers): - "Set the value of workers used by default, returns the previous value" + """Set the value of workers used by default, returns the previous value""" nw = operator.index(n_workers) token = None try: @@ -107,12 +111,27 @@ def set_workers(n_workers): raise ValueError -__all__ = ['fft', 'ifft', 'fft2', 'ifft2', 'fftn', 'ifftn', - 'rfft', 'irfft', 'rfft2', 'irfft2', 'rfftn', 'irfftn', - 'get_workers', 'set_workers', 'DftiBackend'] +__all__ = [ + "fft", + "ifft", + "fft2", + "ifft2", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfft2", + "irfft2", + "rfftn", + "irfftn", + "get_workers", + "set_workers", + "DftiBackend", +] __ua_domain__ = "numpy.scipy.fft" + def __ua_function__(method, args, kwargs): """Fetch registered UA function.""" fn = globals().get(method.__name__, None) @@ -123,6 +142,7 @@ def __ua_function__(method, args, kwargs): class DftiBackend: __ua_domain__ = "numpy.scipy.fft" + @staticmethod def __ua_function__(method, args, kwargs): """Fetch registered UA function.""" @@ -158,14 +178,16 @@ def _workers_to_num_threads(w): if w is None: return _workers_global_settings.get().workers _w = operator.index(w) - if (_w == 0): + if _w == 0: raise ValueError("Number of workers must not be zero") - if (_w < 0): + if _w < 0: ub = os.cpu_count() _w += ub + 1 if _w <= 0: - raise ValueError("workers value out of range; got {}, must not be" - " less than {}".format(w, -ub)) + raise ValueError( + "workers value out of range; got {}, must not be" + " less than {}".format(w, -ub) + ) return _w @@ -176,20 +198,30 @@ def __init__(self, workers): def __enter__(self): try: + # pylint: disable=no-member self.prev_num_threads = mkl.set_num_threads_local(self.n_threads) - except: - raise ValueError("Class argument {} result in invalid number of threads {}".format(self.workers, self.n_threads)) + except Exception as e: + raise ValueError( + "Class argument {} result in invalid number of threads {}".format( + self.workers, self.n_threads + ) + ) from e def __exit__(self, *args): # restore old value + # pylint: disable=no-member mkl.set_num_threads_local(self.prev_num_threads) def _check_norm(norm): if norm not in (None, "ortho", "forward", "backward"): raise ValueError( - ("Invalid norm value {} should be None, " - "\"ortho\", \"forward\", or \"backward\".").format(norm)) + ( + "Invalid norm value {} should be None, " + '"ortho", "forward", or "backward".' + ).format(norm) + ) + def _check_plan(plan): if plan is None: @@ -201,13 +233,13 @@ def _check_plan(plan): def _frwd_sc_1d(n, s): nn = n if n is not None else s - return 1/nn if nn != 0 else 1 + return 1 / nn if nn != 0 else 1 def _frwd_sc_nd(s, x_shape): ss = s if s is not None else x_shape nn = prod(ss) - return 1/nn if nn != 0 else 1 + return 1 / nn if nn != 0 else 1 def _ortho_sc_1d(n, s): @@ -216,29 +248,29 @@ def _ortho_sc_1d(n, s): def _compute_1d_fwd_scale(norm, n, s): if norm in (None, "backward"): - fsc = 1.0 + return 1.0 elif norm == "forward": - fsc = _frwd_sc_1d(n, s) + return _frwd_sc_1d(n, s) elif norm == "ortho": - fsc = _ortho_sc_1d(n, s) + return _ortho_sc_1d(n, s) else: _check_norm(norm) - return fsc def _compute_nd_fwd_scale(norm, s, axes, x_shape): if norm in (None, "backward"): - fsc = 1.0 + return 1.0 elif norm == "forward": - fsc = _frwd_sc_nd(s, x_shape) + return _frwd_sc_nd(s, x_shape) elif norm == "ortho": - fsc = sqrt(_frwd_sc_nd(s, x_shape)) + return sqrt(_frwd_sc_nd(s, x_shape)) else: _check_norm(norm) - return fsc -def fft(a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None): +def fft( + a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None +): try: x = _float_utils.__supported_array_or_not_implemented(a) except ValueError: @@ -248,11 +280,15 @@ def fft(a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=Non fsc = _compute_1d_fwd_scale(norm, n, x.shape[axis]) _check_plan(plan) with Workers(workers): - output = mkl_fft.fft(x, n=n, axis=axis, overwrite_x=overwrite_x, fwd_scale=fsc) + output = mkl_fft.fft( + x, n=n, axis=axis, overwrite_x=overwrite_x, fwd_scale=fsc + ) return output -def ifft(a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None): +def ifft( + a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None +): try: x = _float_utils.__supported_array_or_not_implemented(a) except ValueError: @@ -262,11 +298,21 @@ def ifft(a, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=No fsc = _compute_1d_fwd_scale(norm, n, x.shape[axis]) _check_plan(plan) with Workers(workers): - output = mkl_fft.ifft(x, n=n, axis=axis, overwrite_x=overwrite_x, fwd_scale=fsc) + output = mkl_fft.ifft( + x, n=n, axis=axis, overwrite_x=overwrite_x, fwd_scale=fsc + ) return output -def fft2(a, s=None, axes=(-2,-1), norm=None, overwrite_x=False, workers=None, plan=None): +def fft2( + a, + s=None, + axes=(-2, -1), + norm=None, + overwrite_x=False, + workers=None, + plan=None, +): try: x = _float_utils.__supported_array_or_not_implemented(a) except ValueError: @@ -276,11 +322,21 @@ def fft2(a, s=None, axes=(-2,-1), norm=None, overwrite_x=False, workers=None, pl fsc = _compute_nd_fwd_scale(norm, s, axes, x.shape) _check_plan(plan) with Workers(workers): - output = mkl_fft.fftn(x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc) + output = mkl_fft.fftn( + x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc + ) return output -def ifft2(a, s=None, axes=(-2,-1), norm=None, overwrite_x=False, workers=None, plan=None): +def ifft2( + a, + s=None, + axes=(-2, -1), + norm=None, + overwrite_x=False, + workers=None, + plan=None, +): try: x = _float_utils.__supported_array_or_not_implemented(a) except ValueError: @@ -290,11 +346,15 @@ def ifft2(a, s=None, axes=(-2,-1), norm=None, overwrite_x=False, workers=None, p fsc = _compute_nd_fwd_scale(norm, s, axes, x.shape) _check_plan(plan) with Workers(workers): - output = mkl_fft.ifftn(x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc) + output = mkl_fft.ifftn( + x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc + ) return output -def fftn(a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None): +def fftn( + a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None +): try: x = _float_utils.__supported_array_or_not_implemented(a) except ValueError: @@ -304,11 +364,15 @@ def fftn(a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan= fsc = _compute_nd_fwd_scale(norm, s, axes, x.shape) _check_plan(plan) with Workers(workers): - output = mkl_fft.fftn(x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc) + output = mkl_fft.fftn( + x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc + ) return output -def ifftn(a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None): +def ifftn( + a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None +): try: x = _float_utils.__supported_array_or_not_implemented(a) except ValueError: @@ -318,7 +382,9 @@ def ifftn(a, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan fsc = _compute_nd_fwd_scale(norm, s, axes, x.shape) _check_plan(plan) with Workers(workers): - output = mkl_fft.ifftn(x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc) + output = mkl_fft.ifftn( + x, s=s, axes=axes, overwrite_x=overwrite_x, fwd_scale=fsc + ) return output @@ -343,7 +409,7 @@ def irfft(a, n=None, axis=-1, norm=None, workers=None, plan=None): return NotImplemented if x is NotImplemented: return x - nn = n if n else 2*(x.shape[axis]-1) + nn = n if n else 2 * (x.shape[axis] - 1) fsc = _compute_1d_fwd_scale(norm, nn, x.shape[axis]) _check_plan(plan) with Workers(workers): @@ -353,16 +419,15 @@ def irfft(a, n=None, axis=-1, norm=None, workers=None, plan=None): def _compute_nd_fwd_scale_for_rfft(norm, s, axes, x, invreal=False): if norm in (None, "backward"): - fsc = 1.0 + return s, axes, 1.0 elif norm == "forward": s, axes = _cook_nd_args(x, s, axes, invreal=invreal) - fsc = _frwd_sc_nd(s, x.shape) + return s, axes, _frwd_sc_nd(s, x.shape) elif norm == "ortho": s, axes = _cook_nd_args(x, s, axes, invreal=invreal) - fsc = sqrt(_frwd_sc_nd(s, x.shape)) + return s, axes, sqrt(_frwd_sc_nd(s, x.shape)) else: _check_norm(norm) - return s, axes, fsc def rfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, plan=None): @@ -386,7 +451,9 @@ def irfft2(a, s=None, axes=(-2, -1), norm=None, workers=None, plan=None): return NotImplemented if x is NotImplemented: return x - s, axes, fsc = _compute_nd_fwd_scale_for_rfft(norm, s, axes, x, invreal=True) + s, axes, fsc = _compute_nd_fwd_scale_for_rfft( + norm, s, axes, x, invreal=True + ) _check_plan(plan) with Workers(workers): output = mkl_fft.irfftn(x, s, axes, fwd_scale=fsc) @@ -414,7 +481,9 @@ def irfftn(a, s=None, axes=None, norm=None, workers=None, plan=None): return NotImplemented if x is NotImplemented: return x - s, axes, fsc = _compute_nd_fwd_scale_for_rfft(norm, s, axes, x, invreal=True) + s, axes, fsc = _compute_nd_fwd_scale_for_rfft( + norm, s, axes, x, invreal=True + ) _check_plan(plan) with Workers(workers): output = mkl_fft.irfftn(x, s, axes, fwd_scale=fsc) diff --git a/mkl_fft/_scipy_fftpack.py b/mkl_fft/_scipy_fftpack.py index 867f44c..330b5e5 100644 --- a/mkl_fft/_scipy_fftpack.py +++ b/mkl_fft/_scipy_fftpack.py @@ -24,10 +24,10 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from . import _pydfti as mkl_fft from . import _float_utils +from . import _pydfti as mkl_fft # pylint: disable=no-name-in-module -__all__ = ['fft', 'ifft', 'fftn', 'ifftn', 'fft2', 'ifft2', 'rfft', 'irfft'] +__all__ = ["fft", "ifft", "fftn", "ifftn", "fft2", "ifft2", "rfft", "irfft"] def fft(a, n=None, axis=-1, overwrite_x=False): @@ -50,21 +50,21 @@ def ifftn(a, shape=None, axes=None, overwrite_x=False): return mkl_fft.ifftn(x, shape=shape, axes=axes, overwrite_x=overwrite_x) -def fft2(a, shape=None, axes=(-2,-1), overwrite_x=False): +def fft2(a, shape=None, axes=(-2, -1), overwrite_x=False): x = _float_utils.__upcast_float16_array(a) return mkl_fft.fftn(x, shape=shape, axes=axes, overwrite_x=overwrite_x) -def ifft2(a, shape=None, axes=(-2,-1), overwrite_x=False): +def ifft2(a, shape=None, axes=(-2, -1), overwrite_x=False): x = _float_utils.__upcast_float16_array(a) return mkl_fft.ifftn(x, shape=shape, axes=axes, overwrite_x=overwrite_x) def rfft(a, n=None, axis=-1, overwrite_x=False): x = _float_utils.__upcast_float16_array(a) - return mkl_fft.rfftpack(a, n=n, axis=axis, overwrite_x=overwrite_x) + return mkl_fft.rfftpack(x, n=n, axis=axis, overwrite_x=overwrite_x) def irfft(a, n=None, axis=-1, overwrite_x=False): x = _float_utils.__upcast_float16_array(a) - return mkl_fft.irfftpack(a, n=n, axis=axis, overwrite_x=overwrite_x) + return mkl_fft.irfftpack(x, n=n, axis=axis, overwrite_x=overwrite_x) diff --git a/mkl_fft/_version.py b/mkl_fft/_version.py index dd1f201..d2d5627 100644 --- a/mkl_fft/_version.py +++ b/mkl_fft/_version.py @@ -1 +1 @@ -__version__ = '1.3.13' +__version__ = "1.3.13" diff --git a/mkl_fft/interfaces/__init__.py b/mkl_fft/interfaces/__init__.py index c126fb2..5dd8f77 100644 --- a/mkl_fft/interfaces/__init__.py +++ b/mkl_fft/interfaces/__init__.py @@ -23,5 +23,4 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from . import numpy_fft -from . import scipy_fft +from . import numpy_fft, scipy_fft diff --git a/mkl_fft/src/mklfft.c.src b/mkl_fft/src/mklfft.c.src index 5f0d4ac..0ff9c4c 100644 --- a/mkl_fft/src/mklfft.c.src +++ b/mkl_fft/src/mklfft.c.src @@ -303,7 +303,7 @@ compute_distance(npy_intp *x_strides, npy_intp *x_shape, npy_intp x_itemsize, in return (i1) ? _to_mkl_long(x_shape[0]) : 1; } - /* Right now, this is dead branch of code, since compute_distance is only called if array is ONESEGMENT, + /* Right now, this is dead branch of code, since compute_distance is only called if array is ONESEGMENT, * i.e. either C or F contiguous. * It is however preserved here, since in the future this may be called on a not any-contiguous array. */ @@ -435,7 +435,7 @@ compute_strides_and_distances_inout( c_contig = PyArray_IS_C_CONTIGUOUS(y); f_contig = PyArray_IS_F_CONTIGUOUS(y); - *vec_dist_out = compute_distance(y_strides, y_shape, y_itemsize, x_rank, i0, i0 + x_rank - 2, c_contig, f_contig); + *vec_dist_out = compute_distance(y_strides, y_shape, y_itemsize, x_rank, i0, i0 + x_rank - 2, c_contig, f_contig); } else { /* input vectors need not be equidistant, checking if they are * * may be expensive. Fall back on general iterations. */ @@ -762,7 +762,7 @@ int @REALIN@_@COMPLEXOUT@_mkl_@mode@_out( tmp2 += xout_strides[i] * MultiIter_IndexElem(mit, i); } - status = __cached_notinplace_DftiComputeForward_@MKL_IN_TYPE@_@MKL_OUT_TYPE@( + status = __cached_notinplace_DftiComputeForward_@MKL_IN_TYPE@_@MKL_OUT_TYPE@( (@MKL_IN_TYPE@*) tmp1, (@MKL_OUT_TYPE@*) tmp2, dfti_cache); if (status != 0) break; @@ -1648,7 +1648,7 @@ int multi_iter_free(&mit); } - + if (@POST_CONJUGATE@) { Py_BEGIN_ALLOW_THREADS @vml_conj_func@(xout_size, xout_data, xout_data, VML_HA); diff --git a/mkl_fft/src/mklfft.h b/mkl_fft/src/mklfft.h index 5212b87..6fa5c55 100644 --- a/mkl_fft/src/mklfft.h +++ b/mkl_fft/src/mklfft.h @@ -28,62 +28,95 @@ #include "numpy/arrayobject.h" typedef struct DftiCache { - DFTI_DESCRIPTOR_HANDLE hand; - int initialized; + DFTI_DESCRIPTOR_HANDLE hand; + int initialized; } DftiCache; extern int _free_dfti_cache(DftiCache *); /* Complex input, in-place */ -extern int cdouble_mkl_fft1d_in(PyArrayObject*, npy_intp, int, double, DftiCache*); -extern int cfloat_mkl_fft1d_in(PyArrayObject*, npy_intp, int, double, DftiCache*); -extern int cdouble_mkl_ifft1d_in(PyArrayObject*, npy_intp, int, double, DftiCache*); -extern int cfloat_mkl_ifft1d_in(PyArrayObject*, npy_intp, int, double, DftiCache*); +extern int cdouble_mkl_fft1d_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); +extern int cfloat_mkl_fft1d_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); +extern int cdouble_mkl_ifft1d_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); +extern int cfloat_mkl_ifft1d_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); /* Complex input/output, out-of-place */ -extern int cfloat_cfloat_mkl_fft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); -extern int cdouble_cdouble_mkl_fft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); -extern int cfloat_cfloat_mkl_ifft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); -extern int cdouble_cdouble_mkl_ifft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); +extern int cfloat_cfloat_mkl_fft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); +extern int cdouble_cdouble_mkl_fft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); +extern int cfloat_cfloat_mkl_ifft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); +extern int cdouble_cdouble_mkl_ifft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); /* Real input, complex output, out-of-place */ -extern int float_cfloat_mkl_fft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, int, double, DftiCache*); -extern int double_cdouble_mkl_fft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, int, double, DftiCache*); -extern int float_cfloat_mkl_ifft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, int, double, DftiCache*); -extern int double_cdouble_mkl_ifft1d_out(PyArrayObject*, npy_intp, int, PyArrayObject*, int, double, DftiCache*); +extern int float_cfloat_mkl_fft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, int, double, + DftiCache *); +extern int double_cdouble_mkl_fft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, int, double, + DftiCache *); +extern int float_cfloat_mkl_ifft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, int, double, + DftiCache *); +extern int double_cdouble_mkl_ifft1d_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, int, double, + DftiCache *); /* Real input, real output, in-place */ -extern int float_mkl_rfft_in(PyArrayObject*, npy_intp, int, double, DftiCache*); -extern int float_mkl_irfft_in(PyArrayObject*, npy_intp, int, double, DftiCache*); +extern int float_mkl_rfft_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); +extern int float_mkl_irfft_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); -extern int double_mkl_rfft_in(PyArrayObject*, npy_intp, int, double, DftiCache*); -extern int double_mkl_irfft_in(PyArrayObject*, npy_intp, int, double, DftiCache*); +extern int double_mkl_rfft_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); +extern int double_mkl_irfft_in(PyArrayObject *, npy_intp, int, double, + DftiCache *); /* Real input, real output, out-of-place */ -extern int float_float_mkl_rfft_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); -extern int float_float_mkl_irfft_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); +extern int float_float_mkl_rfft_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); +extern int float_float_mkl_irfft_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); -extern int double_double_mkl_rfft_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); -extern int double_double_mkl_irfft_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); +extern int double_double_mkl_rfft_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); +extern int double_double_mkl_irfft_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); /* Complex input. real output, out-of-place */ -extern int cdouble_double_mkl_irfft_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); -extern int cfloat_float_mkl_irfft_out(PyArrayObject*, npy_intp, int, PyArrayObject*, double, DftiCache*); +extern int cdouble_double_mkl_irfft_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); +extern int cfloat_float_mkl_irfft_out(PyArrayObject *, npy_intp, int, + PyArrayObject *, double, DftiCache *); /* Complex, ND, in-place */ -extern int cdouble_cdouble_mkl_fftnd_in(PyArrayObject*, double); -extern int cdouble_cdouble_mkl_ifftnd_in(PyArrayObject*, double); -extern int cfloat_cfloat_mkl_fftnd_in(PyArrayObject*, double); -extern int cfloat_cfloat_mkl_ifftnd_in(PyArrayObject*, double); - -extern int cdouble_cdouble_mkl_fftnd_out(PyArrayObject*, PyArrayObject*, double); -extern int cdouble_cdouble_mkl_ifftnd_out(PyArrayObject*, PyArrayObject*, double); -extern int cfloat_cfloat_mkl_fftnd_out(PyArrayObject*, PyArrayObject*, double); -extern int cfloat_cfloat_mkl_ifftnd_out(PyArrayObject*, PyArrayObject*, double); - -extern int float_cfloat_mkl_fftnd_out(PyArrayObject*, PyArrayObject*, double); -extern int float_cfloat_mkl_ifftnd_out(PyArrayObject*, PyArrayObject*, double); -extern int double_cdouble_mkl_fftnd_out(PyArrayObject*, PyArrayObject*, double); -extern int double_cdouble_mkl_ifftnd_out(PyArrayObject*, PyArrayObject*, double); - -extern char* mkl_dfti_error(MKL_LONG); +extern int cdouble_cdouble_mkl_fftnd_in(PyArrayObject *, double); +extern int cdouble_cdouble_mkl_ifftnd_in(PyArrayObject *, double); +extern int cfloat_cfloat_mkl_fftnd_in(PyArrayObject *, double); +extern int cfloat_cfloat_mkl_ifftnd_in(PyArrayObject *, double); + +extern int cdouble_cdouble_mkl_fftnd_out(PyArrayObject *, PyArrayObject *, + double); +extern int cdouble_cdouble_mkl_ifftnd_out(PyArrayObject *, PyArrayObject *, + double); +extern int cfloat_cfloat_mkl_fftnd_out(PyArrayObject *, PyArrayObject *, + double); +extern int cfloat_cfloat_mkl_ifftnd_out(PyArrayObject *, PyArrayObject *, + double); + +extern int float_cfloat_mkl_fftnd_out(PyArrayObject *, PyArrayObject *, double); +extern int float_cfloat_mkl_ifftnd_out(PyArrayObject *, PyArrayObject *, + double); +extern int double_cdouble_mkl_fftnd_out(PyArrayObject *, PyArrayObject *, + double); +extern int double_cdouble_mkl_ifftnd_out(PyArrayObject *, PyArrayObject *, + double); + +extern char *mkl_dfti_error(MKL_LONG); diff --git a/mkl_fft/src/multi_iter.h b/mkl_fft/src/multi_iter.h index 1429da7..b83421e 100644 --- a/mkl_fft/src/multi_iter.h +++ b/mkl_fft/src/multi_iter.h @@ -28,34 +28,33 @@ #ifndef MULTI_ITER_H #define MULTI_ITER_H -#include "numpy/arrayobject.h" #include "mkl.h" -#include +#include "numpy/arrayobject.h" #include +#include typedef struct multi_iter_t { npy_intp *shape; // shape of the tensor npy_intp *ind; // multi-index - int rank; // tensor rank, length of shape and of ind - char done; // boolean variable: True when end of iterator has been reached + int rank; // tensor rank, length of shape and of ind + char done; // boolean variable: True when end of iterator has been reached } multi_iter_t; typedef struct multi_iter_masked_t { npy_intp *shape; // shape of the tensor npy_intp *ind; // multi-index - int *mask; // list of indexes to iterate over - int rank; // tensor rank, length of shape and of ind - int mask_len; - char done; // boolean variable: True when end of iterator has been reached + int *mask; // list of indexes to iterate over + int rank; // tensor rank, length of shape and of ind + int mask_len; + char done; // boolean variable: True when end of iterator has been reached } multi_iter_masked_t; - #define MultiIter_Index(mit) ((mit).ind) #define MultiIter_Shape(mit) ((mit).shape) -#define MultiIter_Done(mit) ((mit).done) -#define MultiIter_Rank(mit) ((mit).rank) -#define MultiIter_Mask(mit) ((mit).mask) -#define MultiIter_MaskLength(mit) ((mit).mask_len) +#define MultiIter_Done(mit) ((mit).done) +#define MultiIter_Rank(mit) ((mit).rank) +#define MultiIter_Mask(mit) ((mit).mask) +#define MultiIter_MaskLength(mit) ((mit).mask_len) #define MultiIter_IndexElem(mit, i) ((mit).ind)[(i)] #define MultiIter_ShapeElem(mit, i) ((mit).shape)[(i)] @@ -72,131 +71,127 @@ void multi_iter_masked_free(multi_iter_masked_t*); int multi_iter_masked_next(multi_iter_masked_t*); */ -static NPY_INLINE void -multi_iter_new(multi_iter_t* mi, npy_intp shape[], int rank) { - int i; - char d = 0; +static NPY_INLINE void multi_iter_new(multi_iter_t *mi, npy_intp shape[], + int rank) { + int i; + char d = 0; - assert(rank > 0); + assert(rank > 0); - MultiIter_Index(*mi) = (npy_intp *) mkl_calloc(rank, sizeof(npy_intp), 64); - MultiIter_Shape(*mi) = (npy_intp *) mkl_malloc(rank * sizeof(npy_intp), 64); - memcpy(MultiIter_Shape(*mi), shape, rank * sizeof(npy_intp)); - MultiIter_Rank(*mi) = rank; + MultiIter_Index(*mi) = (npy_intp *)mkl_calloc(rank, sizeof(npy_intp), 64); + MultiIter_Shape(*mi) = (npy_intp *)mkl_malloc(rank * sizeof(npy_intp), 64); + memcpy(MultiIter_Shape(*mi), shape, rank * sizeof(npy_intp)); + MultiIter_Rank(*mi) = rank; - for(i=0; i < rank; i++) { - d |= MultiIter_IndexElem(*mi, i) >= MultiIter_ShapeElem(*mi, i); - if (d) break; - } + for (i = 0; i < rank; i++) { + d |= MultiIter_IndexElem(*mi, i) >= MultiIter_ShapeElem(*mi, i); + if (d) + break; + } - MultiIter_Done(*mi) = d; + MultiIter_Done(*mi) = d; - return; + return; } -static NPY_INLINE void -multi_iter_masked_new( - multi_iter_masked_t* mi, npy_intp shape[], int rank, int mask[], int mask_len) -{ - int i; - char d = 0; +static NPY_INLINE void multi_iter_masked_new(multi_iter_masked_t *mi, + npy_intp shape[], int rank, + int mask[], int mask_len) { + int i; + char d = 0; - assert(rank > 0); + assert(rank > 0); - MultiIter_Index(*mi) = (npy_intp *) mkl_calloc(rank, sizeof(npy_intp), 64); - MultiIter_Shape(*mi) = (npy_intp *) mkl_malloc(rank * sizeof(npy_intp), 64); - memcpy(MultiIter_Shape(*mi), shape, rank * sizeof(npy_intp)); - MultiIter_Rank(*mi) = rank; + MultiIter_Index(*mi) = (npy_intp *)mkl_calloc(rank, sizeof(npy_intp), 64); + MultiIter_Shape(*mi) = (npy_intp *)mkl_malloc(rank * sizeof(npy_intp), 64); + memcpy(MultiIter_Shape(*mi), shape, rank * sizeof(npy_intp)); + MultiIter_Rank(*mi) = rank; - for(i=0; i < rank; i++) { - d |= MultiIter_IndexElem(*mi, i) >= MultiIter_ShapeElem(*mi, i); - if (d) break; - } + for (i = 0; i < rank; i++) { + d |= MultiIter_IndexElem(*mi, i) >= MultiIter_ShapeElem(*mi, i); + if (d) + break; + } - MultiIter_Done(*mi) = d; + MultiIter_Done(*mi) = d; - assert(mask_len > 0); - MultiIter_MaskLength(*mi) = mask_len; - MultiIter_Mask(*mi) = (int *) mkl_malloc(mask_len * sizeof(int), 64); - memcpy(MultiIter_Mask(*mi), mask, mask_len * sizeof(int)); + assert(mask_len > 0); + MultiIter_MaskLength(*mi) = mask_len; + MultiIter_Mask(*mi) = (int *)mkl_malloc(mask_len * sizeof(int), 64); + memcpy(MultiIter_Mask(*mi), mask, mask_len * sizeof(int)); - return; + return; } +static NPY_INLINE void multi_iter_masked_free(multi_iter_masked_t *mi) { + if (mi) { + if (MultiIter_Index(*mi)) + mkl_free(MultiIter_Index(*mi)); -static NPY_INLINE void -multi_iter_masked_free(multi_iter_masked_t *mi) { - if (mi) { - if(MultiIter_Index(*mi)) - mkl_free(MultiIter_Index(*mi)); + if (MultiIter_Shape(*mi)) + mkl_free(MultiIter_Shape(*mi)); - if (MultiIter_Shape(*mi)) - mkl_free(MultiIter_Shape(*mi)); + if (MultiIter_Mask(*mi)) + mkl_free(MultiIter_Mask(*mi)); + } - if (MultiIter_Mask(*mi)) - mkl_free(MultiIter_Mask(*mi)); - } + return; +} - return; +static NPY_INLINE void multi_iter_free(multi_iter_t *mi) { + if (mi) { + if (MultiIter_Index(*mi)) + mkl_free(MultiIter_Index(*mi)); + + if (MultiIter_Shape(*mi)) + mkl_free(MultiIter_Shape(*mi)); + } + + return; } -static NPY_INLINE void -multi_iter_free(multi_iter_t *mi) { - if (mi) { - if(MultiIter_Index(*mi)) - mkl_free(MultiIter_Index(*mi)); +/* Modifies iterator in-place, returns 1 when iterator is empty, 0 otherwise */ +static NPY_INLINE int multi_iter_next(multi_iter_t *mi) { + int j, k; - if (MultiIter_Shape(*mi)) - mkl_free(MultiIter_Shape(*mi)); + if (MultiIter_Done(*mi)) + return 1; + for (k = MultiIter_Rank(*mi); k > 0; k--) { + j = k - 1; + if (++(MultiIter_IndexElem(*mi, j)) < MultiIter_ShapeElem(*mi, j)) + return 0; + else { + MultiIter_IndexElem(*mi, j) = 0; + if (!j) { + MultiIter_Done(*mi) = 1; + } } + } - return; + return 1; } - /* Modifies iterator in-place, returns 1 when iterator is empty, 0 otherwise */ -static NPY_INLINE int -multi_iter_next(multi_iter_t *mi) { - int j, k; - - if(MultiIter_Done(*mi)) return 1; - - for(k = MultiIter_Rank(*mi); k > 0; k--) { - j = k-1; - if (++(MultiIter_IndexElem(*mi, j)) < MultiIter_ShapeElem(*mi, j)) - return 0; - else { - MultiIter_IndexElem(*mi, j) = 0; - if (!j) { - MultiIter_Done(*mi) = 1; - } - } - } +static NPY_INLINE int multi_iter_masked_next(multi_iter_masked_t *mi) { + int j, k; + if (MultiIter_Done(*mi)) return 1; -} -/* Modifies iterator in-place, returns 1 when iterator is empty, 0 otherwise */ -static NPY_INLINE int -multi_iter_masked_next(multi_iter_masked_t *mi) { - int j, k; - - if(MultiIter_Done(*mi)) return 1; - - for(k = MultiIter_MaskLength(*mi); k >0; k--) { - j = MultiIter_MaskElem(*mi, k - 1); - if (++(MultiIter_IndexElem(*mi, j)) < MultiIter_ShapeElem(*mi, j)) - return 0; - else { - MultiIter_IndexElem(*mi, j) = 0; - if (!k) { - MultiIter_Done(*mi) = 1; - } - } + for (k = MultiIter_MaskLength(*mi); k > 0; k--) { + j = MultiIter_MaskElem(*mi, k - 1); + if (++(MultiIter_IndexElem(*mi, j)) < MultiIter_ShapeElem(*mi, j)) + return 0; + else { + MultiIter_IndexElem(*mi, j) = 0; + if (!k) { + MultiIter_Done(*mi) = 1; + } } + } - return 1; + return 1; } #endif diff --git a/mkl_fft/tests/test_fft1d.py b/mkl_fft/tests/test_fft1d.py index c226533..8de8682 100644 --- a/mkl_fft/tests/test_fft1d.py +++ b/mkl_fft/tests/test_fft1d.py @@ -13,7 +13,7 @@ # may be used to endorse or promote products derived from this software # without specific prior written permission. # -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS """AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE @@ -25,20 +25,17 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import numpy as np -from numpy.testing import ( - TestCase, assert_, assert_raises, assert_equal, - assert_warns, assert_allclose) from numpy import random as rnd -import sys -import warnings +from numpy.testing import TestCase, assert_, assert_allclose import mkl_fft + def naive_fft1d(vec): L = len(vec) - phase = -2j*np.pi*(np.arange(L)/float(L)) + phase = -2j * np.pi * (np.arange(L) / float(L)) phase = np.arange(L).reshape(-1, 1) * phase - return np.sum(vec*np.exp(phase), axis=1) + return np.sum(vec * np.exp(phase), axis=1) def _datacopied(arr, original): @@ -48,7 +45,7 @@ def _datacopied(arr, original): """ if arr is original: return False - if not isinstance(original, np.ndarray) and hasattr(original, '__array__'): + if not isinstance(original, np.ndarray) and hasattr(original, "__array__"): return False return arr.base is None @@ -58,103 +55,105 @@ def setUp(self): rnd.seed(1234567) self.xd1 = rnd.standard_normal(128) self.xf1 = self.xd1.astype(np.float32) - self.xz1 = rnd.standard_normal((128,2)).view(dtype=np.complex128).squeeze() + self.xz1 = ( + rnd.standard_normal((128, 2)).view(dtype=np.complex128).squeeze() + ) self.xc1 = self.xz1.astype(np.complex64) def test_vector1(self): """check that mkl_fft gives the same result of numpy.fft""" f1 = mkl_fft.fft(self.xz1) f2 = naive_fft1d(self.xz1) - assert_allclose(f1,f2, rtol=1e-7, atol=2e-12) + assert_allclose(f1, f2, rtol=1e-7, atol=2e-12) f1 = mkl_fft.fft(self.xc1) f2 = naive_fft1d(self.xc1) - assert_allclose(f1,f2, rtol=2e-6, atol=2e-6) + assert_allclose(f1, f2, rtol=2e-6, atol=2e-6) def test_vector2(self): - "ifft(fft(x)) is identity" + """ifft(fft(x)) is identity""" f1 = mkl_fft.fft(self.xz1) f2 = mkl_fft.ifft(f1) - assert_(np.allclose(self.xz1,f2)) + assert_(np.allclose(self.xz1, f2)) f1 = mkl_fft.fft(self.xc1) f2 = mkl_fft.ifft(f1) - assert_( np.allclose(self.xc1,f2)) + assert_(np.allclose(self.xc1, f2)) f1 = mkl_fft.fft(self.xd1) f2 = mkl_fft.ifft(f1) - assert_( np.allclose(self.xd1,f2)) + assert_(np.allclose(self.xd1, f2)) f1 = mkl_fft.fft(self.xf1) f2 = mkl_fft.ifft(f1) - assert_( np.allclose(self.xf1,f2, atol = 2.0e-7)) + assert_(np.allclose(self.xf1, f2, atol=2.0e-7)) def test_vector3(self): - "fft(ifft(x)) is identity" + """fft(ifft(x)) is identity""" f1 = mkl_fft.ifft(self.xz1) f2 = mkl_fft.fft(f1) - assert_(np.allclose(self.xz1,f2)) + assert_(np.allclose(self.xz1, f2)) f1 = mkl_fft.ifft(self.xc1) f2 = mkl_fft.fft(f1) - assert_( np.allclose(self.xc1,f2)) + assert_(np.allclose(self.xc1, f2)) f1 = mkl_fft.ifft(self.xd1) f2 = mkl_fft.fft(f1) - assert_( np.allclose(self.xd1,f2)) + assert_(np.allclose(self.xd1, f2)) f1 = mkl_fft.ifft(self.xf1) f2 = mkl_fft.fft(f1) - assert_( np.allclose(self.xf1, f2, atol = 2.0e-7)) + assert_(np.allclose(self.xf1, f2, atol=2.0e-7)) def test_vector4(self): - "fft of strided is same as fft of contiguous copy" + """fft of strided is same as fft of contiguous copy""" x = self.xz1[::2] f1 = mkl_fft.fft(x) f2 = mkl_fft.fft(x.copy()) - assert_(np.allclose(f1,f2)) + assert_(np.allclose(f1, f2)) x = self.xz1[::-1] f1 = mkl_fft.fft(x) f2 = mkl_fft.fft(x.copy()) - assert_(np.allclose(f1,f2)) + assert_(np.allclose(f1, f2)) def test_vector5(self): - "fft in-place is the same as fft out-of-place" + """fft in-place is the same as fft out-of-place""" x = self.xz1.copy()[::-2] f1 = mkl_fft.fft(x, overwrite_x=True) f2 = mkl_fft.fft(self.xz1[::-2]) - assert_(np.allclose(f1,f2)) + assert_(np.allclose(f1, f2)) def test_vector6(self): - "fft in place" + """fft in place""" x = self.xz1.copy() f1 = mkl_fft.fft(x, overwrite_x=True) assert_(not _datacopied(f1, x)) # this is in-place x = self.xz1.copy() f1 = mkl_fft.fft(x[::-2], overwrite_x=True) - assert_( not np.allclose(x, self.xz1) ) # this is also in-place - assert_( np.allclose(x[-2::-2], self.xz1[-2::-2]) ) - assert_( np.allclose(x[-1::-2], f1) ) + assert_(not np.allclose(x, self.xz1)) # this is also in-place + assert_(np.allclose(x[-2::-2], self.xz1[-2::-2])) + assert_(np.allclose(x[-1::-2], f1)) def test_vector7(self): - "fft of real array is the same as fft of its complex cast" + """fft of real array is the same as fft of its complex cast""" x = self.xd1[3:17:2] f1 = mkl_fft.fft(x) f2 = mkl_fft.fft(x.astype(np.complex128)) - assert_(np.allclose(f1,f2)) + assert_(np.allclose(f1, f2)) def test_vector8(self): - "ifft of real array is the same as fft of its complex cast" + """ifft of real array is the same as fft of its complex cast""" x = self.xd1[3:17:2] f1 = mkl_fft.ifft(x) f2 = mkl_fft.ifft(x.astype(np.complex128)) - assert_(np.allclose(f1,f2)) + assert_(np.allclose(f1, f2)) def test_vector9(self): - "works on subtypes of ndarray" - mask = np.zeros(self.xd1.shape, dtype='int') + """works on subtypes of ndarray""" + mask = np.zeros(self.xd1.shape, dtype="int") mask[1] = 1 mask[-2] = 1 x = np.ma.masked_array(self.xd1, mask=mask) @@ -163,40 +162,42 @@ def test_vector9(self): assert_allclose(f1, f2) def test_vector10(self): - "check n for real arrays" + """check n for real arrays""" x = self.xd1[:8].copy() - f1 = mkl_fft.fft(x, n = 7) + f1 = mkl_fft.fft(x, n=7) f2 = mkl_fft.fft(self.xd1[:7]) assert_allclose(f1, f2) - f1 = mkl_fft.fft(x, n = 9) + f1 = mkl_fft.fft(x, n=9) y = self.xd1[:9].copy() y[-1] = 0.0 f2 = mkl_fft.fft(y) assert_allclose(f1, f2) def test_vector11(self): - "check n for complex arrays" + """check n for complex arrays""" x = self.xz1[:8].copy() - f1 = mkl_fft.fft(x, n = 7) + f1 = mkl_fft.fft(x, n=7) f2 = mkl_fft.fft(self.xz1[:7]) assert_allclose(f1, f2) - f1 = mkl_fft.fft(x, n = 9) + f1 = mkl_fft.fft(x, n=9) y = self.xz1[:9].copy() y[-1] = 0.0 + 0.0j f2 = mkl_fft.fft(y) assert_allclose(f1, f2) def test_vector12(self): - "check fft of float-valued array" + """check fft of float-valued array""" x = np.arange(20) f1 = mkl_fft.fft(x) f2 = mkl_fft.fft(x.astype(np.float64)) assert_allclose(f1, f2) -class DuckArray(np.ndarray): pass +class DuckArray(np.ndarray): + pass + class Test_mklfft_matrix(TestCase): def setUp(self): @@ -204,8 +205,8 @@ def setUp(self): self.ad2 = rnd.standard_normal((4, 3)) self.af2 = self.ad2.astype(np.float32) self.az2 = np.dot( - rnd.standard_normal((17, 15, 2)), - np.array([1.0 + 0.0j, 0.0 + 1.0j], dtype=np.complex128) + rnd.standard_normal((17, 15, 2)), + np.array([1.0 + 0.0j, 0.0 + 1.0j], dtype=np.complex128), ) self.ac2 = self.az2.astype(np.complex64) self.mat = self.az2.view(DuckArray) @@ -214,11 +215,11 @@ def setUp(self): def test_matrix1(self): x = self.az2.copy() f1 = mkl_fft.fft(x) - f2 = np.array([ mkl_fft.fft(x[i]) for i in range(x.shape[0])]) + f2 = np.array([mkl_fft.fft(x[i]) for i in range(x.shape[0])]) assert_allclose(f1, f2) f1 = mkl_fft.fft(x, axis=0) - f2 = np.array([ mkl_fft.fft(x[:, i]) for i in range(x.shape[1])]).T + f2 = np.array([mkl_fft.fft(x[:, i]) for i in range(x.shape[1])]).T assert_allclose(f1, f2) def test_matrix2(self): @@ -228,24 +229,24 @@ def test_matrix2(self): def test_matrix3(self): x = self.az2.copy() - f1 = mkl_fft.fft(x[::3,::-1]) - f2 = mkl_fft.fft(x[::3,::-1].copy()) + f1 = mkl_fft.fft(x[::3, ::-1]) + f2 = mkl_fft.fft(x[::3, ::-1].copy()) assert_allclose(f1, f2) def test_matrix4(self): x = self.az2.copy() - f1 = mkl_fft.fft(x[::3,::-1]) - f2 = mkl_fft.fft(x[::3,::-1], overwrite_x=True) + f1 = mkl_fft.fft(x[::3, ::-1]) + f2 = mkl_fft.fft(x[::3, ::-1], overwrite_x=True) assert_allclose(f1, f2) def test_matrix5(self): - x = self.ad2; + x = self.ad2 f1 = mkl_fft.fft(x) f2 = mkl_fft.ifft(f1) assert_allclose(x, f2, atol=1e-10) def test_matrix6(self): - x = self.ad2; + x = self.ad2 f1 = mkl_fft.ifft(x) f2 = mkl_fft.fft(f1) assert_allclose(x, f2, atol=1e-10) @@ -253,17 +254,25 @@ def test_matrix6(self): def test_matrix7(self): x = self.ad2.copy() f1 = mkl_fft.fft(x) - f2 = np.array([ mkl_fft.fft(x[i]) for i in range(x.shape[0])]) + f2 = np.array([mkl_fft.fft(x[i]) for i in range(x.shape[0])]) assert_allclose(f1, f2) f1 = mkl_fft.fft(x, axis=0) - f2 = np.array([ mkl_fft.fft(x[:, i]) for i in range(x.shape[1])]).T + f2 = np.array([mkl_fft.fft(x[:, i]) for i in range(x.shape[1])]).T assert_allclose(f1, f2) def test_matrix8(self): from numpy.lib.stride_tricks import as_strided + x = self.xd1[:10].copy() - y = as_strided(x, shape=(4,4,), strides=(2*x.itemsize, x.itemsize)) + y = as_strided( + x, + shape=( + 4, + 4, + ), + strides=(2 * x.itemsize, x.itemsize), + ) f1 = mkl_fft.fft(y) f2 = mkl_fft.fft(y.copy()) assert_allclose(f1, f2, atol=1e-15, rtol=1e-7) @@ -275,40 +284,39 @@ def setUp(self): self.ad3 = rnd.standard_normal((7, 11, 19)) self.af3 = self.ad3.astype(np.float32) self.az3 = np.dot( - rnd.standard_normal((17, 13, 15, 2)), - np.array([1.0 + 0.0j, 0.0 + 1.0j], dtype=np.complex128) + rnd.standard_normal((17, 13, 15, 2)), + np.array([1.0 + 0.0j, 0.0 + 1.0j], dtype=np.complex128), ) self.ac3 = self.az3.astype(np.complex64) def test_array1(self): x = self.az3 for ax in range(x.ndim): - f1 = mkl_fft.fft(x, axis = ax) - f2 = mkl_fft.ifft(f1, axis = ax) + f1 = mkl_fft.fft(x, axis=ax) + f2 = mkl_fft.ifft(f1, axis=ax) assert_allclose(f2, x, atol=2e-15) def test_array2(self): x = self.ad3 for ax in range(x.ndim): - f1 = mkl_fft.fft(x, axis = ax) - f2 = mkl_fft.ifft(f1, axis = ax) + f1 = mkl_fft.fft(x, axis=ax) + f2 = mkl_fft.ifft(f1, axis=ax) assert_allclose(f2, x, atol=2e-15) def test_array3(self): x = self.az3 for ax in range(x.ndim): - f1 = mkl_fft.ifft(x, axis = ax) - f2 = mkl_fft.fft(f1, axis = ax) + f1 = mkl_fft.ifft(x, axis=ax) + f2 = mkl_fft.fft(f1, axis=ax) assert_allclose(f2, x, atol=2e-15) def test_array4(self): x = self.ad3 for ax in range(x.ndim): - f1 = mkl_fft.ifft(x, axis = ax) - f2 = mkl_fft.fft(f1, axis = ax) + f1 = mkl_fft.ifft(x, axis=ax) + f2 = mkl_fft.fft(f1, axis=ax) assert_allclose(f2, x, atol=2e-15) - def test_array5(self): """Inputs with zero strides are handled correctly""" z = self.az3 @@ -332,7 +340,7 @@ def test_array5(self): def test_array6(self): """Inputs with Fortran layout are handled correctly, issue 29""" z = self.az3 - z = z.astype(z.dtype, order='F') + z = z.astype(z.dtype, order="F") y1 = mkl_fft.fft(z, axis=0) y2 = mkl_fft.fft(self.az3, axis=0) assert_allclose(y1, y2, atol=2e-15) @@ -345,32 +353,34 @@ class Test_mklfft_rfftpack(TestCase): def setUp(self): rnd.seed(1234567) self.v1 = rnd.randn(16) - self.m2 = rnd.randn(5,7) - self.t3 = rnd.randn(5,7,11) + self.m2 = rnd.randn(5, 7) + self.t3 = rnd.randn(5, 7, 11) def test1(self): x = self.v1.copy() f1 = mkl_fft.rfftpack(x) f2 = mkl_fft.irfftpack(f1) - assert_allclose(f2,x) + assert_allclose(f2, x) def test2(self): x = self.v1.copy() f1 = mkl_fft.irfftpack(x) f2 = mkl_fft.rfftpack(f1) - assert_allclose(f2,x) + assert_allclose(f2, x) def test3(self): - for a in range(0,2): + for a in range(0, 2): for ovwr_x in [True, False]: for dt, atol in zip([np.float32, np.float64], [2e-7, 2e-15]): x = self.m2.copy().astype(dt) f1 = mkl_fft.rfftpack(x, axis=a, overwrite_x=ovwr_x) f2 = mkl_fft.irfftpack(f1, axis=a, overwrite_x=ovwr_x) - assert_allclose(f2, self.m2.astype(dt), atol=atol, err_msg=(a, ovwr_x)) + assert_allclose( + f2, self.m2.astype(dt), atol=atol, err_msg=(a, ovwr_x) + ) def test4(self): - for a in range(0,2): + for a in range(0, 2): for ovwr_x in [True, False]: for dt, atol in zip([np.float32, np.float64], [2e-7, 2e-15]): x = self.m2.copy().astype(dt) @@ -379,11 +389,10 @@ def test4(self): assert_allclose(f2, self.m2.astype(dt), atol=atol) def test5(self): - for a in range(0,3): + for a in range(0, 3): for ovwr_x in [True, False]: for dt, atol in zip([np.float32, np.float64], [4e-7, 4e-15]): x = self.t3.copy().astype(dt) f1 = mkl_fft.irfftpack(x, axis=a, overwrite_x=ovwr_x) f2 = mkl_fft.rfftpack(f1, axis=a, overwrite_x=ovwr_x) assert_allclose(f2, self.t3.astype(dt), atol=atol) - diff --git a/mkl_fft/tests/test_fftnd.py b/mkl_fft/tests/test_fftnd.py index da02abd..8f83236 100644 --- a/mkl_fft/tests/test_fftnd.py +++ b/mkl_fft/tests/test_fftnd.py @@ -25,19 +25,17 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import numpy as np -from numpy.testing import ( - TestCase, assert_, assert_raises, assert_equal, - assert_warns, assert_allclose) -from numpy import random as rnd -import sys -import warnings import pytest +from numpy import random as rnd +from numpy.testing import TestCase, assert_allclose + import mkl_fft -reps_64 = (2**11)*np.finfo(np.float64).eps -reps_32 = (2**11)*np.finfo(np.float32).eps -atol_64 = (2**9)*np.finfo(np.float64).eps -atol_32 = (2**9)*np.finfo(np.float32).eps +reps_64 = (2**11) * np.finfo(np.float64).eps +reps_32 = (2**11) * np.finfo(np.float32).eps +atol_64 = (2**9) * np.finfo(np.float64).eps +atol_32 = (2**9) * np.finfo(np.float32).eps + def _get_rtol_atol(x): dt = x.dtype @@ -46,7 +44,12 @@ def _get_rtol_atol(x): elif dt == np.float32 or dt == np.complex64: return reps_32, atol_32 else: - assert (dt == np.float64 or dt == np.complex128 or dt == np.float32 or dt == np.complex64), "Unexpected dtype {}".format(dt) + assert ( + dt == np.float64 + or dt == np.complex128 + or dt == np.float32 + or dt == np.complex64 + ), "Unexpected dtype {}".format(dt) return reps_64, atol_64 @@ -55,7 +58,7 @@ def setUp(self): rnd.seed(123456) self.md = rnd.randn(256, 256) self.mf = self.md.astype(np.float32) - self.mz = rnd.randn(256, 256*2).view(np.complex128) + self.mz = rnd.randn(256, 256 * 2).view(np.complex128) self.mc = self.mz.astype(np.complex64) def test_matrix1(self): @@ -66,8 +69,24 @@ def test_matrix1(self): t1 = mkl_fft.fftn(d) t2 = mkl_fft.fft(mkl_fft.fft(d, axis=0), axis=1) t3 = mkl_fft.fft(mkl_fft.fft(d, axis=1), axis=0) - assert_allclose(t1, t2, rtol=r_tol, atol=a_tol, err_msg = "failed test for dtype {}, max abs diff: {}".format(d.dtype, np.max(np.abs(t1-t2)))) - assert_allclose(t1, t3, rtol=r_tol, atol=a_tol, err_msg = "failed test for dtype {}, max abs diff: {}".format(d.dtype, np.max(np.abs(t1-t3)))) + assert_allclose( + t1, + t2, + rtol=r_tol, + atol=a_tol, + err_msg="failed test for dtype {}, max abs diff: {}".format( + d.dtype, np.max(np.abs(t1 - t2)) + ), + ) + assert_allclose( + t1, + t3, + rtol=r_tol, + atol=a_tol, + err_msg="failed test for dtype {}, max abs diff: {}".format( + d.dtype, np.max(np.abs(t1 - t3)) + ), + ) def test_matrix2(self): """ifftn(fftn(x)) is x""" @@ -75,7 +94,15 @@ def test_matrix2(self): d = ar.copy() r_tol, a_tol = _get_rtol_atol(d) t = mkl_fft.ifftn(mkl_fft.fftn(d)) - assert_allclose(d, t, rtol=r_tol, atol=a_tol, err_msg = "failed test for dtype {}, max abs diff: {}".format(d.dtype, np.max(np.abs(d-t)))) + assert_allclose( + d, + t, + rtol=r_tol, + atol=a_tol, + err_msg="failed test for dtype {}, max abs diff: {}".format( + d.dtype, np.max(np.abs(d - t)) + ), + ) def test_matrix3(self): """fftn(ifftn(x)) is x""" @@ -83,33 +110,40 @@ def test_matrix3(self): d = ar.copy() r_tol, a_tol = _get_rtol_atol(d) t = mkl_fft.fftn(mkl_fft.ifftn(d)) - assert_allclose(d, t, rtol=r_tol, atol=a_tol, err_msg = "failed test for dtype {}, max abs diff: {}".format(d.dtype, np.max(np.abs(d-t)))) - + assert_allclose( + d, + t, + rtol=r_tol, + atol=a_tol, + err_msg="failed test for dtype {}, max abs diff: {}".format( + d.dtype, np.max(np.abs(d - t)) + ), + ) def test_matrix4(self): """fftn of strided array is same as fftn of a contiguous copy""" for ar in [self.md, self.mz, self.mf, self.mc]: r_tol, a_tol = _get_rtol_atol(ar) - d_strided = ar[::2,::2] + d_strided = ar[::2, ::2] d_contig = d_strided.copy() t_strided = mkl_fft.fftn(d_strided) t_contig = mkl_fft.fftn(d_contig) assert_allclose(t_strided, t_contig, rtol=r_tol, atol=a_tol) - def test_matrix5(self): """fftn of strided array is same as fftn of a contiguous copy""" - rs = rnd.RandomState(1234) - x = rs.randn(6, 11, 12, 13) + np.random.seed(1234) + x = np.random.randn(6, 11, 12, 13) y = x[::-2, :, :, ::3] r_tol, a_tol = _get_rtol_atol(y) - f = mkl_fft.fftn(y, axes=(1,2)) + f = mkl_fft.fftn(y, axes=(1, 2)) for i0 in range(y.shape[0]): for i3 in range(y.shape[3]): assert_allclose( f[i0, :, :, i3], - mkl_fft.fftn(y[i0, :, : , i3]), - rtol=r_tol, atol=a_tol + mkl_fft.fftn(y[i0, :, :, i3]), + rtol=r_tol, + atol=a_tol, ) def test_matrix6(self): @@ -122,9 +156,18 @@ def test_matrix6(self): s = container(d.shape) kwargs = dict(s=s, axes=axes, norm=norm) r_tol, a_tol = _get_rtol_atol(d) - t = mkl_fft._numpy_fft.fftn(mkl_fft._numpy_fft.ifftn(d, **kwargs), **kwargs) - assert_allclose(d, t, rtol=r_tol, atol=a_tol, err_msg = "failed test for dtype {}, max abs diff: {}".format(d.dtype, np.max(np.abs(d-t)))) - + t = mkl_fft._numpy_fft.fftn( + mkl_fft._numpy_fft.ifftn(d, **kwargs), **kwargs + ) + assert_allclose( + d, + t, + rtol=r_tol, + atol=a_tol, + err_msg="failed test for dtype {}, max abs diff: {}".format( + d.dtype, np.max(np.abs(d - t)) + ), + ) class Test_Regressions(TestCase): @@ -133,7 +176,7 @@ def setUp(self): rnd.seed(123456) self.ad = rnd.randn(32, 17, 23) self.af = self.ad.astype(np.float32) - self.az = rnd.randn(32, 17, 23*2).view(np.complex128) + self.az = rnd.randn(32, 17, 23 * 2).view(np.complex128) self.ac = self.az.astype(np.complex64) def test_cf_contig(self): @@ -149,7 +192,14 @@ def test_cf_contig(self): def test_rfftn(self): """Test that rfftn works as expected""" - axes = [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)] + axes = [ + (0, 1, 2), + (0, 2, 1), + (1, 0, 2), + (1, 2, 0), + (2, 0, 1), + (2, 1, 0), + ] for x in [self.ad, self.af]: for a in axes: r_tol, a_tol = _get_rtol_atol(x) @@ -159,10 +209,10 @@ def test_rfftn(self): def test_gh64(self): """Test example from #64""" - a = np.arange(12).reshape((3,4)) + a = np.arange(12).reshape((3, 4)) x = a.astype(np.cdouble) # should executed successfully - r1 = mkl_fft.fftn(a, s=None, axes=(-2,-1)) + r1 = mkl_fft.fftn(a, s=None, axes=(-2, -1)) r2 = mkl_fft.fftn(x) r_tol, a_tol = _get_rtol_atol(x) assert_allclose(r1, r2, rtol=r_tol, atol=a_tol) @@ -173,11 +223,11 @@ def setUp(self): pass def test_scale_1d_vector(self): - X = np.ones(128, dtype='d') + X = np.ones(128, dtype="d") f1 = mkl_fft.fft(X, fwd_scale=0.25) f2 = mkl_fft.fft(X) r_tol, a_tol = _get_rtol_atol(X) - assert_allclose(4*f1, f2, rtol=r_tol, atol=a_tol) + assert_allclose(4 * f1, f2, rtol=r_tol, atol=a_tol) X1 = mkl_fft.ifft(f1, fwd_scale=0.25) assert_allclose(X, X1, rtol=r_tol, atol=a_tol) @@ -187,11 +237,18 @@ def test_scale_1d_vector(self): assert_allclose(X, X2, rtol=r_tol, atol=a_tol) def test_scale_1d_array(self): - X = np.ones((8, 4, 4,), dtype='d') + X = np.ones( + ( + 8, + 4, + 4, + ), + dtype="d", + ) f1 = mkl_fft.fft(X, axis=1, fwd_scale=0.25) f2 = mkl_fft.fft(X, axis=1) r_tol, a_tol = _get_rtol_atol(X) - assert_allclose(4*f1, f2, rtol=r_tol, atol=a_tol) + assert_allclose(4 * f1, f2, rtol=r_tol, atol=a_tol) X1 = mkl_fft.ifft(f1, axis=1, fwd_scale=0.25) assert_allclose(X, X1, rtol=r_tol, atol=a_tol) @@ -201,30 +258,32 @@ def test_scale_1d_array(self): assert_allclose(X, X2, rtol=r_tol, atol=a_tol) def test_scale_nd(self): - X = np.empty((2, 4, 8, 16), dtype='d') + X = np.empty((2, 4, 8, 16), dtype="d") X.flat[:] = np.cbrt(np.arange(0, X.size, dtype=X.dtype)) f = mkl_fft.fftn(X) f_scale = mkl_fft.fftn(X, fwd_scale=0.2) r_tol, a_tol = _get_rtol_atol(X) - assert_allclose(f, 5*f_scale, rtol=r_tol, atol=a_tol) + assert_allclose(f, 5 * f_scale, rtol=r_tol, atol=a_tol) def test_scale_nd_axes(self): - X = np.empty((4, 2, 16, 8), dtype='d') + X = np.empty((4, 2, 16, 8), dtype="d") X.flat[:] = np.cbrt(np.arange(X.size, dtype=X.dtype)) f = mkl_fft.fftn(X, axes=(0, 1, 2, 3)) f_scale = mkl_fft.fftn(X, axes=(0, 1, 2, 3), fwd_scale=0.2) r_tol, a_tol = _get_rtol_atol(X) - assert_allclose(f, 5*f_scale, rtol=r_tol, atol=a_tol) + assert_allclose(f, 5 * f_scale, rtol=r_tol, atol=a_tol) def test_gh109(): b_int = np.array([[5, 7, 6, 5], [4, 6, 4, 8], [9, 3, 7, 5]], dtype=np.int64) b = np.asarray(b_int, dtype=np.float32) - r1 = mkl_fft.fftn(b, s=None, axes=(0,), overwrite_x=False, fwd_scale=1/3) - r2 = mkl_fft.fftn(b_int, s=None, axes=(0,), overwrite_x=False, fwd_scale=1/3) + r1 = mkl_fft.fftn(b, s=None, axes=(0,), overwrite_x=False, fwd_scale=1 / 3) + r2 = mkl_fft.fftn( + b_int, s=None, axes=(0,), overwrite_x=False, fwd_scale=1 / 3 + ) rtol, atol = _get_rtol_atol(b) assert_allclose(r1, r2, rtol=rtol, atol=atol) diff --git a/mkl_fft/tests/test_interfaces.py b/mkl_fft/tests/test_interfaces.py index 221e6f5..eac5369 100644 --- a/mkl_fft/tests/test_interfaces.py +++ b/mkl_fft/tests/test_interfaces.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2017-2025, Intel Corporation # # Redistribution and use in source and binary forms, with or without @@ -24,13 +23,16 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import mkl_fft.interfaces as mfi -import pytest import numpy as np +import pytest + +import mkl_fft.interfaces as mfi -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64, np.complex64, np.complex128]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize( + "dtype", [np.float32, np.float64, np.complex64, np.complex128] +) def test_scipy_fft(norm, dtype): x = np.ones(511, dtype=dtype) w = mfi.scipy_fft.fft(x, norm=norm, workers=None, plan=None) @@ -39,8 +41,10 @@ def test_scipy_fft(norm, dtype): np.testing.assert_allclose(x, xx, atol=tol, rtol=tol) -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64, np.complex64, np.complex128]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize( + "dtype", [np.float32, np.float64, np.complex64, np.complex128] +) def test_numpy_fft(norm, dtype): x = np.ones(511, dtype=dtype) w = mfi.numpy_fft.fft(x, norm=norm) @@ -49,15 +53,17 @@ def test_numpy_fft(norm, dtype): np.testing.assert_allclose(x, xx, atol=tol, rtol=tol) -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_scipy_rfft(norm, dtype): x = np.ones(511, dtype=dtype) w = mfi.scipy_fft.rfft(x, norm=norm, workers=None, plan=None) - xx = mfi.scipy_fft.irfft(w, n=x.shape[0], norm=norm, workers=None, plan=None) + xx = mfi.scipy_fft.irfft( + w, n=x.shape[0], norm=norm, workers=None, plan=None + ) tol = 64 * np.finfo(np.dtype(dtype)).eps assert np.allclose(x, xx, atol=tol, rtol=tol) - + x = np.ones(510, dtype=dtype) w = mfi.scipy_fft.rfft(x, norm=norm, workers=None, plan=None) xx = mfi.scipy_fft.irfft(w, norm=norm, workers=None, plan=None) @@ -65,8 +71,8 @@ def test_scipy_rfft(norm, dtype): assert np.allclose(x, xx, atol=tol, rtol=tol) -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_numpy_rfft(norm, dtype): x = np.ones(511, dtype=dtype) w = mfi.numpy_fft.rfft(x, norm=norm) @@ -75,8 +81,10 @@ def test_numpy_rfft(norm, dtype): assert np.allclose(x, xx, atol=tol, rtol=tol) -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64, np.complex64, np.complex128]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize( + "dtype", [np.float32, np.float64, np.complex64, np.complex128] +) def test_scipy_fftn(norm, dtype): x = np.ones((37, 83), dtype=dtype) w = mfi.scipy_fft.fftn(x, norm=norm, workers=None, plan=None) @@ -85,8 +93,10 @@ def test_scipy_fftn(norm, dtype): assert np.allclose(x, xx, atol=tol, rtol=tol) -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64, np.complex64, np.complex128]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize( + "dtype", [np.float32, np.float64, np.complex64, np.complex128] +) def test_numpy_fftn(norm, dtype): x = np.ones((37, 83), dtype=dtype) w = mfi.numpy_fft.fftn(x, norm=norm) @@ -95,8 +105,8 @@ def test_numpy_fftn(norm, dtype): assert np.allclose(x, xx, atol=tol, rtol=tol) -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_scipy_rfftn(norm, dtype): x = np.ones((37, 83), dtype=dtype) w = mfi.scipy_fft.rfftn(x, norm=norm, workers=None, plan=None) @@ -111,8 +121,8 @@ def test_scipy_rfftn(norm, dtype): assert np.allclose(x, xx, atol=tol, rtol=tol) -@pytest.mark.parametrize('norm', [None, "forward", "backward", "ortho"]) -@pytest.mark.parametrize('dtype', [np.float32, np.float64]) +@pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) +@pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_numpy_rfftn(norm, dtype): x = np.ones((37, 83), dtype=dtype) w = mfi.numpy_fft.rfftn(x, norm=norm) @@ -123,13 +133,13 @@ def test_numpy_rfftn(norm, dtype): def _get_blacklisted_dtypes(): bl_list = [] - for dt in ['float16', 'float128', 'complex256']: + for dt in ["float16", "float128", "complex256"]: if hasattr(np, dt): bl_list.append(getattr(np, dt)) return bl_list - -@pytest.mark.parametrize('dtype', _get_blacklisted_dtypes()) + +@pytest.mark.parametrize("dtype", _get_blacklisted_dtypes()) def test_scipy_no_support_for(dtype): x = np.ones(16, dtype=dtype) w = mfi.scipy_fft.fft(x) @@ -138,19 +148,19 @@ def test_scipy_no_support_for(dtype): def test_scipy_fft_arg_validate(): with pytest.raises(ValueError): - mfi.scipy_fft.fft([1,2,3,4], norm=b"invalid") + mfi.scipy_fft.fft([1, 2, 3, 4], norm=b"invalid") with pytest.raises(NotImplementedError): - mfi.scipy_fft.fft([1,2,3,4], plan="magic") + mfi.scipy_fft.fft([1, 2, 3, 4], plan="magic") @pytest.mark.parametrize( - "func", + "func", [mfi.scipy_fft.rfft2, mfi.numpy_fft.rfft2], ids=["scipy", "numpy"], ) def test_axes(func): - x = np.arange(24.).reshape(2, 3, 4) + x = np.arange(24.0).reshape(2, 3, 4) res = func(x, axes=(1, 2)) exp = np.fft.rfft2(x, axes=(1, 2)) tol = 64 * np.finfo(np.float64).eps diff --git a/mkl_fft/tests/test_pocketfft.py b/mkl_fft/tests/test_pocketfft.py index 7f006a0..5d9ba62 100644 --- a/mkl_fft/tests/test_pocketfft.py +++ b/mkl_fft/tests/test_pocketfft.py @@ -1,17 +1,25 @@ # This file includes tests from numpy.fft module: # https://github.com/numpy/numpy/blob/main/numpy/fft/tests/test_pocketfft.py +# TODO: remove pylint disable when out kwarg is added +# pylint: disable=unexpected-keyword-arg + +import queue +import threading + import numpy as np import pytest from numpy.random import random from numpy.testing import ( - assert_array_equal, assert_raises, assert_allclose, IS_WASM - ) -import threading -import queue + IS_WASM, + assert_allclose, + assert_array_equal, + assert_raises, +) import mkl_fft.interfaces.numpy_fft as mkl_fft + def fft1(x): L = len(x) phase = -2j * np.pi * (np.arange(L) / L) @@ -32,17 +40,21 @@ def test_identity(self): x = random(maxlen) + 1j * random(maxlen) xr = random(maxlen) for i in range(1, maxlen): - assert_allclose(mkl_fft.ifft(mkl_fft.fft(x[0:i])), x[0:i], - atol=1e-12) - assert_allclose(mkl_fft.irfft(mkl_fft.rfft(xr[0:i]), i), - xr[0:i], atol=1e-12) + assert_allclose( + mkl_fft.ifft(mkl_fft.fft(x[0:i])), x[0:i], atol=1e-12 + ) + assert_allclose( + mkl_fft.irfft(mkl_fft.rfft(xr[0:i]), i), xr[0:i], atol=1e-12 + ) - @pytest.mark.parametrize("dtype", [np.single, np.double]) #, np.longdouble]) + @pytest.mark.parametrize( + "dtype", [np.single, np.double] + ) # , np.longdouble]) def test_identity_long_short(self, dtype): # Test with explicitly given number of points, both for n # smaller and for n larger than the input size. maxlen = 16 - atol = 5 * np.spacing(np.array(1., dtype=dtype)) + atol = 5 * np.spacing(np.array(1.0, dtype=dtype)) x = random(maxlen).astype(dtype) + 1j * random(maxlen).astype(dtype) xx = np.concatenate([x, np.zeros_like(x)]) xr = random(maxlen).astype(dtype) @@ -55,11 +67,13 @@ def test_identity_long_short(self, dtype): assert check_r.dtype == dtype assert_allclose(check_r, xxr[0:i], atol=atol, rtol=0) - @pytest.mark.parametrize("dtype", [np.single, np.double]) #, np.longdouble]) + @pytest.mark.parametrize( + "dtype", [np.single, np.double] + ) # , np.longdouble]) def test_identity_long_short_reversed(self, dtype): # Also test explicitly given number of points in reversed order. maxlen = 16 - atol = 5 * np.spacing(np.array(1., dtype=dtype)) + atol = 5 * np.spacing(np.array(1.0, dtype=dtype)) x = random(maxlen).astype(dtype) + 1j * random(maxlen).astype(dtype) xx = np.concatenate([x, np.zeros_like(x)]) for i in range(1, maxlen * 2): @@ -73,7 +87,7 @@ def test_identity_long_short_reversed(self, dtype): n = i // 2 + 1 y.imag[0] = 0 if i % 2 == 0: - y.imag[n - 1:] = 0 + y.imag[n - 1 :] = 0 yy = np.concatenate([y, np.zeros_like(y)]) check_via_r = mkl_fft.rfft(mkl_fft.irfft(x, n=i), n=i) assert check_via_r.dtype == x.dtype @@ -83,10 +97,12 @@ def test_fft(self): x = random(30) + 1j * random(30) assert_allclose(fft1(x), mkl_fft.fft(x), atol=1e-6) assert_allclose(fft1(x), mkl_fft.fft(x, norm="backward"), atol=1e-6) - assert_allclose(fft1(x) / np.sqrt(30), - mkl_fft.fft(x, norm="ortho"), atol=1e-6) - assert_allclose(fft1(x) / 30., - mkl_fft.fft(x, norm="forward"), atol=1e-6) + assert_allclose( + fft1(x) / np.sqrt(30), mkl_fft.fft(x, norm="ortho"), atol=1e-6 + ) + assert_allclose( + fft1(x) / 30.0, mkl_fft.fft(x, norm="forward"), atol=1e-6 + ) @pytest.mark.skip("out is not supported") @pytest.mark.parametrize("axis", (0, 1)) @@ -182,7 +198,7 @@ def test_fft_inplace_out(self, axis): @pytest.mark.skip("out is not supported") def test_fft_bad_out(self): - x = np.arange(30.) + x = np.arange(30.0) with pytest.raises(TypeError, match="must be of ArrayType"): mkl_fft.fft(x, out="") with pytest.raises(ValueError, match="has wrong shape"): @@ -190,85 +206,132 @@ def test_fft_bad_out(self): with pytest.raises(TypeError, match="Cannot cast"): mkl_fft.fft(x, out=np.zeros_like(x, dtype=float)) - @pytest.mark.parametrize('norm', (None, 'backward', 'ortho', 'forward')) + @pytest.mark.parametrize("norm", (None, "backward", "ortho", "forward")) def test_ifft(self, norm): x = random(30) + 1j * random(30) assert_allclose( - x, mkl_fft.ifft(mkl_fft.fft(x, norm=norm), norm=norm), - atol=1e-6) + x, mkl_fft.ifft(mkl_fft.fft(x, norm=norm), norm=norm), atol=1e-6 + ) # Ensure we get the correct error message - with pytest.raises(ValueError, - match='Invalid number of FFT data points'): + with pytest.raises( + ValueError, match="Invalid number of FFT data points" + ): mkl_fft.ifft([], norm=norm) def test_fft2(self): x = random((30, 20)) + 1j * random((30, 20)) - assert_allclose(mkl_fft.fft(mkl_fft.fft(x, axis=1), axis=0), - mkl_fft.fft2(x), atol=1e-6) - assert_allclose(mkl_fft.fft2(x), - mkl_fft.fft2(x, norm="backward"), atol=1e-6) - assert_allclose(mkl_fft.fft2(x) / np.sqrt(30 * 20), - mkl_fft.fft2(x, norm="ortho"), atol=1e-6) - assert_allclose(mkl_fft.fft2(x) / (30. * 20.), - mkl_fft.fft2(x, norm="forward"), atol=1e-6) + assert_allclose( + mkl_fft.fft(mkl_fft.fft(x, axis=1), axis=0), + mkl_fft.fft2(x), + atol=1e-6, + ) + assert_allclose( + mkl_fft.fft2(x), mkl_fft.fft2(x, norm="backward"), atol=1e-6 + ) + assert_allclose( + mkl_fft.fft2(x) / np.sqrt(30 * 20), + mkl_fft.fft2(x, norm="ortho"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.fft2(x) / (30.0 * 20.0), + mkl_fft.fft2(x, norm="forward"), + atol=1e-6, + ) def test_ifft2(self): x = random((30, 20)) + 1j * random((30, 20)) - assert_allclose(mkl_fft.ifft(mkl_fft.ifft(x, axis=1), axis=0), - mkl_fft.ifft2(x), atol=1e-6) - assert_allclose(mkl_fft.ifft2(x), - mkl_fft.ifft2(x, norm="backward"), atol=1e-6) - assert_allclose(mkl_fft.ifft2(x) * np.sqrt(30 * 20), - mkl_fft.ifft2(x, norm="ortho"), atol=1e-6) - assert_allclose(mkl_fft.ifft2(x) * (30. * 20.), - mkl_fft.ifft2(x, norm="forward"), atol=1e-6) + assert_allclose( + mkl_fft.ifft(mkl_fft.ifft(x, axis=1), axis=0), + mkl_fft.ifft2(x), + atol=1e-6, + ) + assert_allclose( + mkl_fft.ifft2(x), mkl_fft.ifft2(x, norm="backward"), atol=1e-6 + ) + assert_allclose( + mkl_fft.ifft2(x) * np.sqrt(30 * 20), + mkl_fft.ifft2(x, norm="ortho"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.ifft2(x) * (30.0 * 20.0), + mkl_fft.ifft2(x, norm="forward"), + atol=1e-6, + ) def test_fftn(self): x = random((30, 20, 10)) + 1j * random((30, 20, 10)) assert_allclose( mkl_fft.fft(mkl_fft.fft(mkl_fft.fft(x, axis=2), axis=1), axis=0), - mkl_fft.fftn(x), atol=1e-6) - assert_allclose(mkl_fft.fftn(x), - mkl_fft.fftn(x, norm="backward"), atol=1e-6) - assert_allclose(mkl_fft.fftn(x) / np.sqrt(30 * 20 * 10), - mkl_fft.fftn(x, norm="ortho"), atol=1e-6) - assert_allclose(mkl_fft.fftn(x) / (30. * 20. * 10.), - mkl_fft.fftn(x, norm="forward"), atol=1e-6) + mkl_fft.fftn(x), + atol=1e-6, + ) + assert_allclose( + mkl_fft.fftn(x), mkl_fft.fftn(x, norm="backward"), atol=1e-6 + ) + assert_allclose( + mkl_fft.fftn(x) / np.sqrt(30 * 20 * 10), + mkl_fft.fftn(x, norm="ortho"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.fftn(x) / (30.0 * 20.0 * 10.0), + mkl_fft.fftn(x, norm="forward"), + atol=1e-6, + ) def test_ifftn(self): x = random((30, 20, 10)) + 1j * random((30, 20, 10)) assert_allclose( mkl_fft.ifft(mkl_fft.ifft(mkl_fft.ifft(x, axis=2), axis=1), axis=0), - mkl_fft.ifftn(x), atol=1e-6) - assert_allclose(mkl_fft.ifftn(x), - mkl_fft.ifftn(x, norm="backward"), atol=1e-6) - assert_allclose(mkl_fft.ifftn(x) * np.sqrt(30 * 20 * 10), - mkl_fft.ifftn(x, norm="ortho"), atol=1e-6) - assert_allclose(mkl_fft.ifftn(x) * (30. * 20. * 10.), - mkl_fft.ifftn(x, norm="forward"), atol=1e-6) + mkl_fft.ifftn(x), + atol=1e-6, + ) + assert_allclose( + mkl_fft.ifftn(x), mkl_fft.ifftn(x, norm="backward"), atol=1e-6 + ) + assert_allclose( + mkl_fft.ifftn(x) * np.sqrt(30 * 20 * 10), + mkl_fft.ifftn(x, norm="ortho"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.ifftn(x) * (30.0 * 20.0 * 10.0), + mkl_fft.ifftn(x, norm="forward"), + atol=1e-6, + ) def test_rfft(self): x = random(30) for n in [x.size, 2 * x.size]: - for norm in [None, 'backward', 'ortho', 'forward']: + for norm in [None, "backward", "ortho", "forward"]: assert_allclose( - mkl_fft.fft(x, n=n, norm=norm)[:(n // 2 + 1)], - mkl_fft.rfft(x, n=n, norm=norm), atol=1e-6) + mkl_fft.fft(x, n=n, norm=norm)[: (n // 2 + 1)], + mkl_fft.rfft(x, n=n, norm=norm), + atol=1e-6, + ) assert_allclose( mkl_fft.rfft(x, n=n), - mkl_fft.rfft(x, n=n, norm="backward"), atol=1e-6) + mkl_fft.rfft(x, n=n, norm="backward"), + atol=1e-6, + ) assert_allclose( mkl_fft.rfft(x, n=n) / np.sqrt(n), - mkl_fft.rfft(x, n=n, norm="ortho"), atol=1e-6) + mkl_fft.rfft(x, n=n, norm="ortho"), + atol=1e-6, + ) assert_allclose( mkl_fft.rfft(x, n=n) / n, - mkl_fft.rfft(x, n=n, norm="forward"), atol=1e-6) + mkl_fft.rfft(x, n=n, norm="forward"), + atol=1e-6, + ) def test_rfft_even(self): x = np.arange(8) n = 4 y = mkl_fft.rfft(x, n) - assert_allclose(y, mkl_fft.fft(x[:n])[:n // 2 + 1], rtol=1e-14) + assert_allclose(y, mkl_fft.fft(x[:n])[: n // 2 + 1], rtol=1e-14) def test_rfft_odd(self): x = np.array([1, 0, 2, 3, -3]) @@ -278,124 +341,206 @@ def test_rfft_odd(self): def test_irfft(self): x = random(30) assert_allclose(x, mkl_fft.irfft(mkl_fft.rfft(x)), atol=1e-6) - assert_allclose(x, mkl_fft.irfft(mkl_fft.rfft(x, norm="backward"), - norm="backward"), atol=1e-6) - assert_allclose(x, mkl_fft.irfft(mkl_fft.rfft(x, norm="ortho"), - norm="ortho"), atol=1e-6) - assert_allclose(x, mkl_fft.irfft(mkl_fft.rfft(x, norm="forward"), - norm="forward"), atol=1e-6) + assert_allclose( + x, + mkl_fft.irfft(mkl_fft.rfft(x, norm="backward"), norm="backward"), + atol=1e-6, + ) + assert_allclose( + x, + mkl_fft.irfft(mkl_fft.rfft(x, norm="ortho"), norm="ortho"), + atol=1e-6, + ) + assert_allclose( + x, + mkl_fft.irfft(mkl_fft.rfft(x, norm="forward"), norm="forward"), + atol=1e-6, + ) def test_rfft2(self): x = random((30, 20)) assert_allclose(mkl_fft.fft2(x)[:, :11], mkl_fft.rfft2(x), atol=1e-6) - assert_allclose(mkl_fft.rfft2(x), - mkl_fft.rfft2(x, norm="backward"), atol=1e-6) - assert_allclose(mkl_fft.rfft2(x) / np.sqrt(30 * 20), - mkl_fft.rfft2(x, norm="ortho"), atol=1e-6) - assert_allclose(mkl_fft.rfft2(x) / (30. * 20.), - mkl_fft.rfft2(x, norm="forward"), atol=1e-6) + assert_allclose( + mkl_fft.rfft2(x), mkl_fft.rfft2(x, norm="backward"), atol=1e-6 + ) + assert_allclose( + mkl_fft.rfft2(x) / np.sqrt(30 * 20), + mkl_fft.rfft2(x, norm="ortho"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.rfft2(x) / (30.0 * 20.0), + mkl_fft.rfft2(x, norm="forward"), + atol=1e-6, + ) def test_irfft2(self): x = random((30, 20)) assert_allclose(x, mkl_fft.irfft2(mkl_fft.rfft2(x)), atol=1e-6) - assert_allclose(x, mkl_fft.irfft2(mkl_fft.rfft2(x, norm="backward"), - norm="backward"), atol=1e-6) - assert_allclose(x, mkl_fft.irfft2(mkl_fft.rfft2(x, norm="ortho"), - norm="ortho"), atol=1e-6) - assert_allclose(x, mkl_fft.irfft2(mkl_fft.rfft2(x, norm="forward"), - norm="forward"), atol=1e-6) + assert_allclose( + x, + mkl_fft.irfft2(mkl_fft.rfft2(x, norm="backward"), norm="backward"), + atol=1e-6, + ) + assert_allclose( + x, + mkl_fft.irfft2(mkl_fft.rfft2(x, norm="ortho"), norm="ortho"), + atol=1e-6, + ) + assert_allclose( + x, + mkl_fft.irfft2(mkl_fft.rfft2(x, norm="forward"), norm="forward"), + atol=1e-6, + ) def test_rfftn(self): x = random((30, 20, 10)) assert_allclose(mkl_fft.fftn(x)[:, :, :6], mkl_fft.rfftn(x), atol=1e-6) - assert_allclose(mkl_fft.rfftn(x), - mkl_fft.rfftn(x, norm="backward"), atol=1e-6) - assert_allclose(mkl_fft.rfftn(x) / np.sqrt(30 * 20 * 10), - mkl_fft.rfftn(x, norm="ortho"), atol=1e-6) - assert_allclose(mkl_fft.rfftn(x) / (30. * 20. * 10.), - mkl_fft.rfftn(x, norm="forward"), atol=1e-6) + assert_allclose( + mkl_fft.rfftn(x), mkl_fft.rfftn(x, norm="backward"), atol=1e-6 + ) + assert_allclose( + mkl_fft.rfftn(x) / np.sqrt(30 * 20 * 10), + mkl_fft.rfftn(x, norm="ortho"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.rfftn(x) / (30.0 * 20.0 * 10.0), + mkl_fft.rfftn(x, norm="forward"), + atol=1e-6, + ) # Regression test for gh-27159 x = np.ones((2, 3)) result = mkl_fft.rfftn(x, axes=(0, 0, 1), s=(10, 20, 40)) assert result.shape == (10, 21) - expected = mkl_fft.fft(mkl_fft.fft(mkl_fft.rfft(x, axis=1, n=40), - axis=0, n=20), axis=0, n=10) + expected = mkl_fft.fft( + mkl_fft.fft(mkl_fft.rfft(x, axis=1, n=40), axis=0, n=20), + axis=0, + n=10, + ) assert expected.shape == (10, 21) assert_allclose(result, expected, atol=1e-6) def test_irfftn(self): x = random((30, 20, 10)) assert_allclose(x, mkl_fft.irfftn(mkl_fft.rfftn(x)), atol=1e-6) - assert_allclose(x, mkl_fft.irfftn(mkl_fft.rfftn(x, norm="backward"), - norm="backward"), atol=1e-6) - assert_allclose(x, mkl_fft.irfftn(mkl_fft.rfftn(x, norm="ortho"), - norm="ortho"), atol=1e-6) - assert_allclose(x, mkl_fft.irfftn(mkl_fft.rfftn(x, norm="forward"), - norm="forward"), atol=1e-6) + assert_allclose( + x, + mkl_fft.irfftn(mkl_fft.rfftn(x, norm="backward"), norm="backward"), + atol=1e-6, + ) + assert_allclose( + x, + mkl_fft.irfftn(mkl_fft.rfftn(x, norm="ortho"), norm="ortho"), + atol=1e-6, + ) + assert_allclose( + x, + mkl_fft.irfftn(mkl_fft.rfftn(x, norm="forward"), norm="forward"), + atol=1e-6, + ) def test_hfft(self): x = random(14) + 1j * random(14) x_herm = np.concatenate((random(1), x, random(1))) x = np.concatenate((x_herm, x[::-1].conj())) assert_allclose(mkl_fft.fft(x), mkl_fft.hfft(x_herm), atol=1e-6) - assert_allclose(mkl_fft.hfft(x_herm), - mkl_fft.hfft(x_herm, norm="backward"), atol=1e-6) - assert_allclose(mkl_fft.hfft(x_herm) / np.sqrt(30), - mkl_fft.hfft(x_herm, norm="ortho"), atol=1e-6) - assert_allclose(mkl_fft.hfft(x_herm) / 30., - mkl_fft.hfft(x_herm, norm="forward"), atol=1e-6) + assert_allclose( + mkl_fft.hfft(x_herm), + mkl_fft.hfft(x_herm, norm="backward"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.hfft(x_herm) / np.sqrt(30), + mkl_fft.hfft(x_herm, norm="ortho"), + atol=1e-6, + ) + assert_allclose( + mkl_fft.hfft(x_herm) / 30.0, + mkl_fft.hfft(x_herm, norm="forward"), + atol=1e-6, + ) def test_ihfft(self): x = random(14) + 1j * random(14) x_herm = np.concatenate((random(1), x, random(1))) x = np.concatenate((x_herm, x[::-1].conj())) assert_allclose(x_herm, mkl_fft.ihfft(mkl_fft.hfft(x_herm)), atol=1e-6) - assert_allclose(x_herm, mkl_fft.ihfft(mkl_fft.hfft(x_herm, - norm="backward"), norm="backward"), atol=1e-6) - assert_allclose(x_herm, mkl_fft.ihfft(mkl_fft.hfft(x_herm, - norm="ortho"), norm="ortho"), atol=1e-6) - assert_allclose(x_herm, mkl_fft.ihfft(mkl_fft.hfft(x_herm, - norm="forward"), norm="forward"), atol=1e-6) - - @pytest.mark.parametrize("op", [mkl_fft.fftn, mkl_fft.ifftn, - mkl_fft.rfftn, mkl_fft.irfftn]) + assert_allclose( + x_herm, + mkl_fft.ihfft( + mkl_fft.hfft(x_herm, norm="backward"), norm="backward" + ), + atol=1e-6, + ) + assert_allclose( + x_herm, + mkl_fft.ihfft(mkl_fft.hfft(x_herm, norm="ortho"), norm="ortho"), + atol=1e-6, + ) + assert_allclose( + x_herm, + mkl_fft.ihfft(mkl_fft.hfft(x_herm, norm="forward"), norm="forward"), + atol=1e-6, + ) + + @pytest.mark.parametrize( + "op", [mkl_fft.fftn, mkl_fft.ifftn, mkl_fft.rfftn, mkl_fft.irfftn] + ) def test_axes(self, op): x = random((30, 20, 10)) - axes = [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)] + axes = [ + (0, 1, 2), + (0, 2, 1), + (1, 0, 2), + (1, 2, 0), + (2, 0, 1), + (2, 1, 0), + ] for a in axes: op_tr = op(np.transpose(x, a)) tr_op = np.transpose(op(x, axes=a), a) assert_allclose(op_tr, tr_op, atol=1e-6) - @pytest.mark.parametrize("op", [mkl_fft.fftn, mkl_fft.ifftn, - mkl_fft.fft2, mkl_fft.ifft2]) + @pytest.mark.parametrize( + "op", [mkl_fft.fftn, mkl_fft.ifftn, mkl_fft.fft2, mkl_fft.ifft2] + ) def test_s_negative_1(self, op): x = np.arange(100).reshape(10, 10) # should use the whole input array along the first axis assert op(x, s=(-1, 5), axes=(0, 1)).shape == (10, 5) @pytest.mark.skip("no warning is raised in mkl_ftt") - @pytest.mark.parametrize("op", [mkl_fft.fftn, mkl_fft.ifftn, - mkl_fft.rfftn, mkl_fft.irfftn]) + @pytest.mark.parametrize( + "op", [mkl_fft.fftn, mkl_fft.ifftn, mkl_fft.rfftn, mkl_fft.irfftn] + ) def test_s_axes_none(self, op): x = np.arange(100).reshape(10, 10) - with pytest.warns(match='`axes` should not be `None` if `s`'): + with pytest.warns(match="`axes` should not be `None` if `s`"): op(x, s=(-1, 5)) @pytest.mark.skip("no warning is raised in mkl_ftt") @pytest.mark.parametrize("op", [mkl_fft.fft2, mkl_fft.ifft2]) def test_s_axes_none_2D(self, op): x = np.arange(100).reshape(10, 10) - with pytest.warns(match='`axes` should not be `None` if `s`'): + with pytest.warns(match="`axes` should not be `None` if `s`"): op(x, s=(-1, 5), axes=None) @pytest.mark.skip("no warning is raised in mkl_ftt") - @pytest.mark.parametrize("op", [mkl_fft.fftn, mkl_fft.ifftn, - mkl_fft.rfftn, mkl_fft.irfftn, - mkl_fft.fft2, mkl_fft.ifft2]) + @pytest.mark.parametrize( + "op", + [ + mkl_fft.fftn, + mkl_fft.ifftn, + mkl_fft.rfftn, + mkl_fft.irfftn, + mkl_fft.fft2, + mkl_fft.ifft2, + ], + ) def test_s_contains_none(self, op): x = random((30, 20, 10)) - with pytest.warns(match='array containing `None` values to `s`'): + with pytest.warns(match="array containing `None` values to `s`"): op(x, s=(10, None, 10), axes=(0, 1, 2)) def test_all_1d_norm_preserving(self): @@ -403,19 +548,19 @@ def test_all_1d_norm_preserving(self): x = random(30) x_norm = np.linalg.norm(x) n = x.size * 2 - func_pairs = [(mkl_fft.fft, mkl_fft.ifft), - (mkl_fft.rfft, mkl_fft.irfft), - # hfft: order so the first function takes x.size samples - # (necessary for comparison to x_norm above) - (mkl_fft.ihfft, mkl_fft.hfft), - ] + func_pairs = [ + (mkl_fft.fft, mkl_fft.ifft), + (mkl_fft.rfft, mkl_fft.irfft), + # hfft: order so the first function takes x.size samples + # (necessary for comparison to x_norm above) + (mkl_fft.ihfft, mkl_fft.hfft), + ] for forw, back in func_pairs: for n in [x.size, 2 * x.size]: - for norm in [None, 'backward', 'ortho', 'forward']: + for norm in [None, "backward", "ortho", "forward"]: tmp = forw(x, n=n, norm=norm) tmp = back(tmp, n=n, norm=norm) - assert_allclose(x_norm, - np.linalg.norm(tmp), atol=1e-6) + assert_allclose(x_norm, np.linalg.norm(tmp), atol=1e-6) @pytest.mark.skip("out is not supported") @pytest.mark.parametrize("axes", [(0, 1), (0, 2), None]) @@ -449,7 +594,9 @@ def zeros_like(x): assert_array_equal(result2, expected2) @pytest.mark.skip("out is not supported") - @pytest.mark.parametrize("fft", [mkl_fft.fftn, mkl_fft.ifftn, mkl_fft.rfftn]) + @pytest.mark.parametrize( + "fft", [mkl_fft.fftn, mkl_fft.ifftn, mkl_fft.rfftn] + ) def test_fftn_out_and_s_interaction(self, fft): # With s, shape varies, so generally one cannot pass in out. if fft is mkl_fft.rfftn: @@ -480,35 +627,42 @@ def test_irfftn_out_and_s_interaction(self, s): @pytest.mark.parametrize( - "dtype", - [np.float32, np.float64, np.complex64, np.complex128]) -@pytest.mark.parametrize("order", ["F", 'non-contiguous']) + "dtype", [np.float32, np.float64, np.complex64, np.complex128] +) +@pytest.mark.parametrize("order", ["F", "non-contiguous"]) @pytest.mark.parametrize( - "fft", - [mkl_fft.fft, mkl_fft.fft2, mkl_fft.fftn, - mkl_fft.ifft, mkl_fft.ifft2, mkl_fft.ifftn]) + "fft", + [ + mkl_fft.fft, + mkl_fft.fft2, + mkl_fft.fftn, + mkl_fft.ifft, + mkl_fft.ifft2, + mkl_fft.ifftn, + ], +) def test_fft_with_order(dtype, order, fft): # Check that FFT/IFFT produces identical results for C, Fortran and # non contiguous arrays - rng = np.random.RandomState(42) - X = rng.rand(8, 7, 13).astype(dtype, copy=False) + np.random.seed(42) + X = np.random.rand(8, 7, 13).astype(dtype, copy=False) # See discussion in pull/14178 _tol = 8.0 * np.sqrt(np.log2(X.size)) * np.finfo(X.dtype).eps - if order == 'F': + if order == "F": Y = np.asfortranarray(X) else: # Make a non contiguous array Y = X[::-1] X = np.ascontiguousarray(X[::-1]) - if fft.__name__.endswith('fft'): + if fft.__name__.endswith("fft"): for axis in range(3): X_res = fft(X, axis=axis) Y_res = fft(Y, axis=axis) assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol) - elif fft.__name__.endswith(('fft2', 'fftn')): + elif fft.__name__.endswith(("fft2", "fftn")): axes = [(0, 1), (1, 2), (0, 2)] - if fft.__name__.endswith('fftn'): + if fft.__name__.endswith("fftn"): axes.extend([(0,), (1,), (2,), None]) for ax in axes: X_res = fft(X, axes=ax) @@ -521,13 +675,14 @@ def test_fft_with_order(dtype, order, fft): @pytest.mark.parametrize("order", ["F", "C"]) @pytest.mark.parametrize("n", [None, 7, 12]) def test_fft_output_order(order, n): - rng = np.random.RandomState(42) - x = rng.rand(10) + np.random.seed(42) + x = np.random.rand(10) x = np.asarray(x, dtype=np.complex64, order=order) res = mkl_fft.fft(x, n=n) assert res.flags.c_contiguous == x.flags.c_contiguous assert res.flags.f_contiguous == x.flags.f_contiguous + @pytest.mark.skipif(IS_WASM, reason="Cannot start thread") class TestFFTThreadSafe: threads = 16 @@ -541,15 +696,20 @@ def worker(args, q): expected = func(*args) # Spin off a bunch of threads to call the same function simultaneously - t = [threading.Thread(target=worker, args=(args, q)) - for i in range(self.threads)] + t = [ + threading.Thread(target=worker, args=(args, q)) + for i in range(self.threads) + ] [x.start() for x in t] [x.join() for x in t] # Make sure all threads returned the correct value - for i in range(self.threads): - assert_array_equal(q.get(timeout=5), expected, - 'Function returned wrong value in multithreaded context') + for _ in range(self.threads): + assert_array_equal( + q.get(timeout=5), + expected, + "Function returned wrong value in multithreaded context", + ) def test_fft(self): a = np.ones(self.input_shape) * 1 + 0j @@ -580,23 +740,37 @@ def test_irfft_with_n_large_regression(): # Regression test for gh-25679 x = np.arange(5) * (1 + 1j) result = mkl_fft.hfft(x, n=10) - expected = np.array([20., 9.91628173, -11.8819096, 7.1048486, - -6.62459848, 4., -3.37540152, -0.16057669, - 1.8819096, -20.86055364]) + expected = np.array( + [ + 20.0, + 9.91628173, + -11.8819096, + 7.1048486, + -6.62459848, + 4.0, + -3.37540152, + -0.16057669, + 1.8819096, + -20.86055364, + ] + ) assert_allclose(result, expected) -@pytest.mark.parametrize("fft", [ - mkl_fft.fft, mkl_fft.ifft, mkl_fft.rfft, mkl_fft.irfft -]) -@pytest.mark.parametrize("data", [ - np.array([False, True, False]), - np.arange(10, dtype=np.uint8), - np.arange(5, dtype=np.int16), -]) +@pytest.mark.parametrize( + "fft", [mkl_fft.fft, mkl_fft.ifft, mkl_fft.rfft, mkl_fft.irfft] +) +@pytest.mark.parametrize( + "data", + [ + np.array([False, True, False]), + np.arange(10, dtype=np.uint8), + np.arange(5, dtype=np.int16), + ], +) def test_fft_with_integer_or_bool_input(data, fft): # Regression test for gh-25819 result = fft(data) - float_data = data.astype(np.result_type(data, 1.)) + float_data = data.astype(np.result_type(data, 1.0)) expected = fft(float_data) assert_allclose(result, expected, rtol=1e-15) diff --git a/pyproject.toml b/pyproject.toml index fb33340..17392f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,14 +3,14 @@ # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Intel Corporation nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -24,54 +24,67 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [build-system] -requires = ["setuptools>=64", "Cython", "numpy"] build-backend = "setuptools.build_meta" +requires = ["setuptools>=64", "Cython", "numpy"] [project] -name = "mkl_fft" -dynamic = ["version"] -description = "MKL-based FFT transforms for NumPy arrays" -readme = { file = "README.md", content-type = "text/markdown" } -requires-python = ">=3.9,<3.13" -license = { text = "BSD" } authors = [ - { name = "Intel Corporation", email = "scripting@intel.com" } + {name = "Intel Corporation", email = "scripting@intel.com"} ] -keywords = ["DFTI", "FFT", "Fourier", "MKL"] classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Science/Research", - "Intended Audience :: Developers", - "License :: OSI Approved", - "Programming Language :: C", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: Implementation :: CPython", - "Topic :: Software Development", - "Topic :: Scientific/Engineering", - "Operating System :: Microsoft :: Windows", - "Operating System :: POSIX", - "Operating System :: Unix", + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "License :: OSI Approved", + "Programming Language :: C", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Software Development", + "Topic :: Scientific/Engineering", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix" ] dependencies = ["numpy >=1.26.4", "mkl", "mkl-service"] +description = "MKL-based FFT transforms for NumPy arrays" +dynamic = ["version"] +keywords = ["DFTI", "FFT", "Fourier", "MKL"] +license = {text = "BSD"} +name = "mkl_fft" +readme = {file = "README.md", content-type = "text/markdown"} +requires-python = ">=3.9,<3.13" [project.optional-dependencies] test = ["pytest"] [project.urls] -Homepage = "http://github.com/IntelPython/mkl_fft" Download = "http://github.com/IntelPython/mkl_fft" +Homepage = "http://github.com/IntelPython/mkl_fft" + +[tool.black] +exclude = "_vendored/conv_template.py" +line-length = 80 + +[tool.isort] +ensure_newline_before_comments = true +force_grid_wrap = 0 +include_trailing_comma = true +line_length = 80 +multi_line_output = 3 +skip = ["_vendored/conv_template.py"] +use_parentheses = true [tool.setuptools] -packages = ["mkl_fft", "mkl_fft.interfaces"] include-package-data = true - -[tool.setuptools.package-data] -"mkl_fft" = ["tests/*.py"] +packages = ["mkl_fft", "mkl_fft.interfaces"] [tool.setuptools.dynamic] version = {attr = "mkl_fft._version.__version__"} + +[tool.setuptools.package-data] +"mkl_fft" = ["tests/*.py"] diff --git a/setup.py b/setup.py index ec78807..9ca40fc 100644 --- a/setup.py +++ b/setup.py @@ -24,65 +24,72 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import sys import os +import sys from os.path import join + import Cython.Build -from setuptools import setup, Extension import numpy as np +from setuptools import Extension, setup sys.path.insert(0, os.path.dirname(__file__)) # Ensures local imports work -from _vendored.conv_template import process_file as process_c_file +from _vendored.conv_template import process_file as process_c_file # noqa: E402 + def extensions(): - mkl_root = os.environ.get('MKLROOT', None) + mkl_root = os.environ.get("MKLROOT", None) if mkl_root: mkl_info = { - 'include_dirs': [join(mkl_root, 'include')], - 'library_dirs': [join(mkl_root, 'lib'), join(mkl_root, 'lib', 'intel64')], - 'libraries': ['mkl_rt'] + "include_dirs": [join(mkl_root, "include")], + "library_dirs": [ + join(mkl_root, "lib"), + join(mkl_root, "lib", "intel64"), + ], + "libraries": ["mkl_rt"], } else: - try: - mkl_info = get_info('mkl') - except: - mkl_info = dict() + raise ValueError("MKLROOT environment variable not set.") - mkl_include_dirs = mkl_info.get('include_dirs', []) - mkl_library_dirs = mkl_info.get('library_dirs', []) - mkl_libraries = mkl_info.get('libraries', ['mkl_rt']) + mkl_include_dirs = mkl_info.get("include_dirs", []) + mkl_library_dirs = mkl_info.get("library_dirs", []) + mkl_libraries = mkl_info.get("libraries", ["mkl_rt"]) mklfft_templ = join("mkl_fft", "src", "mklfft.c.src") processed_mklfft_fn = join("mkl_fft", "src", "mklfft.c") src_processed = process_c_file(mklfft_templ) - with open(processed_mklfft_fn, 'w') as fid: + with open(processed_mklfft_fn, "w") as fid: fid.write(src_processed) return [ Extension( "mkl_fft._pydfti", - sources = [ + sources=[ join("mkl_fft", "_pydfti.pyx"), join("mkl_fft", "src", "mklfft.c"), ], - depends = [ - join("mkl_fft", "src", 'mklfft.h'), - join("mkl_fft", "src", "multi_iter.h") + depends=[ + join("mkl_fft", "src", "mklfft.h"), + join("mkl_fft", "src", "multi_iter.h"), ], - include_dirs = [join("mkl_fft", "src"), np.get_include()] + mkl_include_dirs, - libraries = mkl_libraries, - library_dirs = mkl_library_dirs, - extra_compile_args = [ - '-DNDEBUG', + include_dirs=[join("mkl_fft", "src"), np.get_include()] + + mkl_include_dirs, + libraries=mkl_libraries, + library_dirs=mkl_library_dirs, + extra_compile_args=[ + "-DNDEBUG", # '-ggdb', '-O0', '-Wall', '-Wextra', '-DDEBUG', ], - define_macros=[("NPY_NO_DEPRECATED_API", None), ("PY_ARRAY_UNIQUE_SYMBOL", "mkl_fft_ext")], + define_macros=[ + ("NPY_NO_DEPRECATED_API", None), + ("PY_ARRAY_UNIQUE_SYMBOL", "mkl_fft_ext"), + ], ) ] + setup( - cmdclass={'build_ext': Cython.Build.build_ext}, + cmdclass={"build_ext": Cython.Build.build_ext}, ext_modules=extensions(), zip_safe=False, )