nvmath-python 0.9.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nvmath/__init__.pxd +0 -0
- nvmath/__init__.py +45 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/attribute_ifc_factory.py +330 -0
- nvmath/_internal/layout.py +70 -0
- nvmath/_internal/templates.py +383 -0
- nvmath/_utils.py +150 -0
- nvmath/bindings/__init__.py +51 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +47 -0
- nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +277 -0
- nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +179 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +746 -0
- nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1337 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +219 -0
- nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +86 -0
- nvmath/bindings/cudss.pyi +282 -0
- nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +241 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +260 -0
- nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +159 -0
- nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +242 -0
- nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +416 -0
- nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +338 -0
- nvmath/bindings/cusparse.pyi +659 -0
- nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +198 -0
- nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +294 -0
- nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +684 -0
- nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1055 -0
- nvmath/bindings/cycublasMp.pxd +183 -0
- nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +224 -0
- nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +326 -0
- nvmath/bindings/cycufftMp.pxd +334 -0
- nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +146 -0
- nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +154 -0
- nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +446 -0
- nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +470 -0
- nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +150 -0
- nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +192 -0
- nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +126 -0
- nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1244 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +13 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
- nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +85 -0
- nvmath/bindings/nvpl/blas.pyi +122 -0
- nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +166 -0
- nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +92 -0
- nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +100 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +179 -0
- nvmath/device/__init__.py +21 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +313 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +310 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1805 -0
- nvmath/device/cublasdx_backend.py +807 -0
- nvmath/device/cublasdx_numba.py +1612 -0
- nvmath/device/cufftdx.py +510 -0
- nvmath/device/cufftdx_backend.py +196 -0
- nvmath/device/cufftdx_numba.py +196 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2690 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +1624 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +445 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +147 -0
- nvmath/device/vector_types_numba.py +203 -0
- nvmath/distributed/__init__.py +205 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nvshmem.py +302 -0
- nvmath/distributed/_internal/tensor_ifc.py +67 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
- nvmath/distributed/_internal/tensor_wrapper.py +78 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution.py +770 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +79 -0
- nvmath/distributed/fft/fft.py +2801 -0
- nvmath/distributed/linalg/__init__.py +12 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -0
- nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/distributed/linalg/advanced/__init__.py +8 -0
- nvmath/distributed/linalg/advanced/_configuration.py +166 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/distributed/reshape/__init__.py +6 -0
- nvmath/distributed/reshape/_configuration.py +39 -0
- nvmath/distributed/reshape/reshape.py +1256 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +208 -0
- nvmath/fft/_exec_utils.py +109 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +2903 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +12 -0
- nvmath/internal/_device_utils.py +54 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +10 -0
- nvmath/internal/memory.pyi +46 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +7 -0
- nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +240 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
- nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
- nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
- nvmath/internal/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
- nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
- nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/data_layout.pxd +72 -0
- nvmath/internal/ndbuffer/data_layout.pyi +23 -0
- nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/jit.pxd +7 -0
- nvmath/internal/ndbuffer/jit.pyi +6 -0
- nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
- nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
- nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/package_utils.pxd +11 -0
- nvmath/internal/ndbuffer/package_utils.pyi +12 -0
- nvmath/internal/package_ifc.py +147 -0
- nvmath/internal/package_ifc_cuda.py +49 -0
- nvmath/internal/package_ifc_cupy.py +49 -0
- nvmath/internal/package_ifc_torch.py +31 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +194 -0
- nvmath/internal/tensor_ifc_cupy.py +241 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
- nvmath/internal/tensor_ifc_numpy.py +183 -0
- nvmath/internal/tensor_ifc_torch.py +176 -0
- nvmath/internal/tensor_wrapper.py +157 -0
- nvmath/internal/typemaps.py +162 -0
- nvmath/internal/utils.py +771 -0
- nvmath/linalg/__init__.py +46 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
- nvmath/linalg/_internal/algo_config_ifc.py +43 -0
- nvmath/linalg/_internal/batch.py +217 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +766 -0
- nvmath/linalg/_internal/layout.py +624 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +134 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +149 -0
- nvmath/linalg/advanced/_configuration.py +349 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1348 -0
- nvmath/linalg/advanced/matmulmod.py +3937 -0
- nvmath/linalg/generic/__init__.py +43 -0
- nvmath/linalg/generic/_configuration/__init__.py +37 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +609 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +1060 -0
- nvmath/memory.py +282 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +144 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +445 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +230 -0
- nvmath/sparse/advanced/direct_solver.py +1884 -0
- nvmath/sparse/generic/__init__.py +7 -0
- nvmath/sparse/generic/_configuration.py +129 -0
- nvmath/sparse/generic/_helpers.py +137 -0
- nvmath/sparse/generic/_thunks.py +21 -0
- nvmath/sparse/generic/matmulmod.py +2426 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +378 -0
- nvmath/sparse/ust/_drawer.py +552 -0
- nvmath/sparse/ust/_emitter.py +553 -0
- nvmath/sparse/ust/_jit.py +212 -0
- nvmath/sparse/ust/_kernel.py +346 -0
- nvmath/sparse/ust/_semiring.py +71 -0
- nvmath/sparse/ust/_utils.py +102 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/semiring_ops.py +71 -0
- nvmath/sparse/ust/tensor.py +1027 -0
- nvmath/sparse/ust/tensor_drawer.py +552 -0
- nvmath/sparse/ust/tensor_emitter.py +558 -0
- nvmath/sparse/ust/tensor_format.py +935 -0
- nvmath/sparse/ust/tensor_jit.py +212 -0
- nvmath/sparse/ust/tensor_kernel.py +348 -0
- nvmath/sparse/ust/tensor_utils.py +380 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +95 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
- nvmath/tensor/_internal/cutensor_utils.py +162 -0
- nvmath/tensor/_internal/data.py +43 -0
- nvmath/tensor/_internal/einsum_parser.py +444 -0
- nvmath/tensor/_internal/typemaps.py +96 -0
- nvmath/tensor/contract.py +1861 -0
- nvmath_python-0.9.0.dist-info/METADATA +127 -0
- nvmath_python-0.9.0.dist-info/RECORD +309 -0
- nvmath_python-0.9.0.dist-info/WHEEL +5 -0
- nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
nvmath/fft/__init__.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
__all__ = ["FFTDirection", "FFTOptions", "DeviceCallable", "ExecutionCUDA", "ExecutionCPU"]
|
|
6
|
+
|
|
7
|
+
import warnings
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from enum import IntEnum
|
|
10
|
+
from logging import Logger
|
|
11
|
+
from typing import Literal
|
|
12
|
+
|
|
13
|
+
from nvmath.memory import BaseCUDAMemoryManager
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ExecutionCUDA:
|
|
18
|
+
"""
|
|
19
|
+
A data class for providing GPU execution options to the :class:`FFT` object and the
|
|
20
|
+
family of wrapper functions :func:`fft`, :func:`ifft`, :func:`rfft`, and :func:`irfft`.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
device_id: CUDA device ordinal (only used if the operand resides on the CPU). The
|
|
24
|
+
default value is 0.
|
|
25
|
+
|
|
26
|
+
.. seealso::
|
|
27
|
+
:class:`ExecutionCPU`, :class:`FFT`, :func:`fft`, :func:`ifft`, :func:`rfft`, and
|
|
28
|
+
:func:`irfft`.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
name: Literal["cuda"] = field(default="cuda", init=False)
|
|
32
|
+
# If not specified, it defaults to the deprecated FFTOptions.device_id or 0
|
|
33
|
+
# Keep None as an option to differentiate between the user-provided 0 and the default 0.
|
|
34
|
+
device_id: int | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class ExecutionCPU:
|
|
39
|
+
"""
|
|
40
|
+
A data class for providing CPU execution options to the :class:`FFT` object and the
|
|
41
|
+
family of wrapper functions :func:`fft`, :func:`ifft`, :func:`rfft`, and :func:`irfft`.
|
|
42
|
+
|
|
43
|
+
Attributes:
|
|
44
|
+
num_threads: The number of CPU threads used to execute the plan.
|
|
45
|
+
If not specified, defaults to the number of CPU cores available to the
|
|
46
|
+
process.
|
|
47
|
+
|
|
48
|
+
.. seealso::
|
|
49
|
+
:class:`ExecutionCUDA`, :class:`FFT`, :func:`fft`, :func:`ifft`, :func:`rfft`, and
|
|
50
|
+
:func:`irfft`.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
name: Literal["cpu"] = field(default="cpu", init=False)
|
|
54
|
+
num_threads: int | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class FFTOptions:
|
|
59
|
+
"""
|
|
60
|
+
A data class for providing options to the :class:`FFT` object and the family of wrapper
|
|
61
|
+
functions :func:`fft`, :func:`ifft`, :func:`rfft`, and :func:`irfft`.
|
|
62
|
+
|
|
63
|
+
Attributes:
|
|
64
|
+
fft_type: The type of FFT to perform, available options include ``'C2C'``,
|
|
65
|
+
``'C2R'``, and ``'R2C'``. The default is ``'C2C'`` for complex input and
|
|
66
|
+
``'R2C'`` for real input.
|
|
67
|
+
|
|
68
|
+
inplace: Specify if the operation is in-place (`True` or `False`). The operand is
|
|
69
|
+
overwritten by the result if ``inplace`` is `True`. The default is `False`.
|
|
70
|
+
|
|
71
|
+
last_axis_parity: For complex-to-real FFT (corresponding to ``fft_type='C2R'``),
|
|
72
|
+
specify whether the size of the last axis in the result should be even or odd.
|
|
73
|
+
The even size is calculated as :math:`2 * (m - 1)`, where :math:`m` is the the
|
|
74
|
+
size of the last axis of the operand, and the odd size is calculated as :math:`2
|
|
75
|
+
* (m - 1) + 1`. The specified value should be either ``'even'`` or ``'odd'``,
|
|
76
|
+
with the default being ``'even'``.
|
|
77
|
+
|
|
78
|
+
result_layout: The layout to use for the result, either ``'natural'`` or
|
|
79
|
+
``'optimized'``. For the ``'natural'`` option, the result layout is the same as
|
|
80
|
+
that of the operand. The default is ``'optimized'``, which generally provides
|
|
81
|
+
much better performance and should be used if the user doesn't care about the
|
|
82
|
+
result layout matching the operand layout. However in rare cases, depending on
|
|
83
|
+
the device type, shape and strides of the operand, and the FFT dimensions, the
|
|
84
|
+
``'natural'`` layout may perform better. This option is ignored if ``inplace``
|
|
85
|
+
is specified to be True.
|
|
86
|
+
|
|
87
|
+
device_id: CUDA device ordinal (used if the operand resides on the CPU).
|
|
88
|
+
Device 0 will be used if not specified.
|
|
89
|
+
|
|
90
|
+
.. deprecated:: 0.2.0
|
|
91
|
+
The ``device_id`` should be specified as ``execution`` option,
|
|
92
|
+
see :attr:`ExecutionCUDA.device_id`.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
logger (logging.Logger): Python Logger object. The root logger will be used if a
|
|
96
|
+
logger object is not provided.
|
|
97
|
+
|
|
98
|
+
blocking: A flag specifying the behavior of the execution functions and methods,
|
|
99
|
+
such as :func:`fft` and :meth:`FFT.execute`. When ``blocking`` is `True`, the
|
|
100
|
+
execution methods do not return until the operation is complete. When
|
|
101
|
+
``blocking`` is ``"auto"``, the methods return immediately when the input tensor
|
|
102
|
+
is on the GPU and ``execution`` is set to 'CUDA'. The execution methods always
|
|
103
|
+
block when the input tensor is on the CPU or ``execution`` is specified to 'CPU'
|
|
104
|
+
to ensure that the user doesn't inadvertently use the result before it becomes
|
|
105
|
+
available. The default is ``"auto"``.
|
|
106
|
+
|
|
107
|
+
allocator: An object that supports the :class:`BaseCUDAMemoryManager` protocol, used
|
|
108
|
+
to draw device memory. If an allocator is not provided, a memory allocator from
|
|
109
|
+
the library package will be used (:func:`torch.cuda.caching_allocator_alloc` for
|
|
110
|
+
PyTorch operands, :func:`cupy.cuda.alloc` otherwise). Currently, CPU execution
|
|
111
|
+
does not allow specifying a memory pool.
|
|
112
|
+
|
|
113
|
+
.. seealso::
|
|
114
|
+
:class:`ExecutionCUDA`, :class:`ExecutionCPU`, :class:`FFT`, :func:`fft`,
|
|
115
|
+
:func:`ifft`, :func:`rfft`, and :func:`irfft`.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
fft_type: Literal["C2C", "C2R", "R2C"] | None = None
|
|
119
|
+
inplace: bool = False
|
|
120
|
+
last_axis_parity: Literal["even", "odd"] = "even"
|
|
121
|
+
result_layout: Literal["natural", "optimized"] = "optimized"
|
|
122
|
+
device_id: int | None = None
|
|
123
|
+
logger: Logger | None = None
|
|
124
|
+
blocking: Literal[True, "auto"] = "auto"
|
|
125
|
+
allocator: BaseCUDAMemoryManager | None = None
|
|
126
|
+
|
|
127
|
+
def __post_init__(self):
|
|
128
|
+
valid_fft_types = [None, "C2C", "C2R", "R2C"]
|
|
129
|
+
if self.fft_type not in valid_fft_types:
|
|
130
|
+
raise ValueError(f"The value specified for 'fft_type' must be one of {valid_fft_types}.")
|
|
131
|
+
|
|
132
|
+
if not isinstance(self.inplace, bool):
|
|
133
|
+
raise ValueError("The value specified for 'inplace' must be of type bool (True or False).")
|
|
134
|
+
|
|
135
|
+
valid_last_axis_parity = ["even", "odd"]
|
|
136
|
+
if self.last_axis_parity not in valid_last_axis_parity:
|
|
137
|
+
raise ValueError(f"The value specified for 'last_axis_parity' must be one of {valid_last_axis_parity}.")
|
|
138
|
+
|
|
139
|
+
valid_result_layout_options = ["natural", "optimized"]
|
|
140
|
+
if self.result_layout not in valid_result_layout_options:
|
|
141
|
+
raise ValueError(f"The value specified for 'result_layout' must be one of {valid_result_layout_options}.")
|
|
142
|
+
|
|
143
|
+
if self.blocking not in (True, "auto"):
|
|
144
|
+
raise ValueError("The value specified for 'blocking' must be either True or 'auto'.")
|
|
145
|
+
|
|
146
|
+
if self.device_id is not None:
|
|
147
|
+
msg = "`FFTOptions.device_id` is deprecated. Use `ExecutionCUDA.device_id` instead."
|
|
148
|
+
warnings.warn(msg, DeprecationWarning)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass
|
|
152
|
+
class DeviceCallable:
|
|
153
|
+
"""A data class capturing LTO-IR callables.
|
|
154
|
+
|
|
155
|
+
Attributes:
|
|
156
|
+
ltoir: A device-callable function in LTO-IR format, which can be provided as as
|
|
157
|
+
either as a :class:`bytes` object or as a pointer to the LTO-IR as Python
|
|
158
|
+
:class:`int`.
|
|
159
|
+
|
|
160
|
+
size: The size of the LTO-IR callable. If not specified and a :class:`bytes` object
|
|
161
|
+
is passed for ``ltoir``, the size is calculated from it. If a pointer is
|
|
162
|
+
provided for the LTO-IR, `size` must be specified.
|
|
163
|
+
|
|
164
|
+
data: A device pointer to user data used in the callback. The default is None,
|
|
165
|
+
which means a null pointer will be used in the callback.
|
|
166
|
+
|
|
167
|
+
.. seealso::
|
|
168
|
+
:meth:`FFT.plan`, :func:`fft`, :func:`ifft`, :func:`rfft`, and :func:`irfft`.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
ltoir: int | bytes | None = None
|
|
172
|
+
size: int | None = None
|
|
173
|
+
data: int | None = None
|
|
174
|
+
|
|
175
|
+
def __post_init__(self):
|
|
176
|
+
if self.ltoir is None:
|
|
177
|
+
return
|
|
178
|
+
if not isinstance(self.ltoir, int | bytes):
|
|
179
|
+
raise ValueError(
|
|
180
|
+
"The LTO-IR code must be provided as a bytes object or as a Python int "
|
|
181
|
+
"representing the pointer to the LTO-IR code."
|
|
182
|
+
)
|
|
183
|
+
if isinstance(self.ltoir, int) and self.size is None:
|
|
184
|
+
raise ValueError(
|
|
185
|
+
"The size of the LTO-IR code specified as a pointer must be explicitly provided using the 'size' option."
|
|
186
|
+
)
|
|
187
|
+
if isinstance(self.ltoir, bytes):
|
|
188
|
+
self.size = len(self.ltoir)
|
|
189
|
+
if not isinstance(self.size, int):
|
|
190
|
+
raise ValueError(f"Invalid size value: {self.size}.")
|
|
191
|
+
if self.data is None:
|
|
192
|
+
self.data = 0
|
|
193
|
+
if not isinstance(self.data, int):
|
|
194
|
+
raise ValueError("The 'data' attribute must be a Python int representing a device pointer to user data.")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
KeywordArgType = dict
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class FFTDirection(IntEnum):
|
|
201
|
+
"""An IntEnum class specifying the direction of the transform.
|
|
202
|
+
|
|
203
|
+
.. seealso::
|
|
204
|
+
:meth:`FFT.execute`, :func:`fft`
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
FORWARD = -1
|
|
208
|
+
INVERSE = 1
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from nvmath.bindings import cufft # type: ignore
|
|
8
|
+
from nvmath.bindings._internal import utils as _bindings_utils # type: ignore
|
|
9
|
+
from nvmath.fft import _configuration
|
|
10
|
+
|
|
11
|
+
IS_EXEC_GPU_AVAILABLE = False
|
|
12
|
+
IS_EXEC_CPU_AVAILABLE = False
|
|
13
|
+
NUM_THREADS_DEFAULT = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _get_num_threads_default():
|
|
17
|
+
global NUM_THREADS_DEFAULT
|
|
18
|
+
if NUM_THREADS_DEFAULT is None:
|
|
19
|
+
if os.name == "posix":
|
|
20
|
+
num_threads = len(os.sched_getaffinity(0))
|
|
21
|
+
else:
|
|
22
|
+
# `sched_getaffinity` is not supported on Windows
|
|
23
|
+
num_threads = os.cpu_count() or 1
|
|
24
|
+
num_threads = max(1, num_threads // 2)
|
|
25
|
+
NUM_THREADS_DEFAULT = num_threads
|
|
26
|
+
return NUM_THREADS_DEFAULT
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _check_init_cufft():
|
|
30
|
+
global IS_EXEC_GPU_AVAILABLE
|
|
31
|
+
if not IS_EXEC_GPU_AVAILABLE:
|
|
32
|
+
try:
|
|
33
|
+
cufft.get_version()
|
|
34
|
+
except (
|
|
35
|
+
_bindings_utils.FunctionNotFoundError,
|
|
36
|
+
_bindings_utils.NotSupportedError,
|
|
37
|
+
RuntimeError,
|
|
38
|
+
) as e:
|
|
39
|
+
raise RuntimeError(
|
|
40
|
+
"The FFT CUDA execution is not available. "
|
|
41
|
+
"Please check if CUDA toolkit and cuFFT are installed and visible to nvmath."
|
|
42
|
+
) from e
|
|
43
|
+
|
|
44
|
+
IS_EXEC_GPU_AVAILABLE = True
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _check_init_fftw():
|
|
48
|
+
global IS_EXEC_CPU_AVAILABLE
|
|
49
|
+
if not IS_EXEC_CPU_AVAILABLE:
|
|
50
|
+
from nvmath.bindings.nvpl import fft as _fftw
|
|
51
|
+
from nvmath.bindings.nvpl._internal import fft as _internal_fftw
|
|
52
|
+
|
|
53
|
+
env_lib_name = os.environ.get("NVMATH_FFT_CPU_LIBRARY")
|
|
54
|
+
|
|
55
|
+
if env_lib_name:
|
|
56
|
+
_internal_fftw._set_lib_so_names((env_lib_name,))
|
|
57
|
+
try:
|
|
58
|
+
_internal_fftw._inspect_function_pointers()
|
|
59
|
+
loaded_lib_name = _internal_fftw._get_current_lib_so_name()
|
|
60
|
+
except (
|
|
61
|
+
_bindings_utils.FunctionNotFoundError,
|
|
62
|
+
_bindings_utils.NotSupportedError,
|
|
63
|
+
RuntimeError,
|
|
64
|
+
) as e:
|
|
65
|
+
raise RuntimeError(
|
|
66
|
+
"The FFT CPU execution is not available, because no FFTW-compatible "
|
|
67
|
+
"library was found. Please make sure to install optional dependency required "
|
|
68
|
+
"for FFT execution (NVPL on aarch64 platforms or MKL on x86_64 platforms). "
|
|
69
|
+
"Users can use other FFTW3-compatible libraries. In order to do that, please "
|
|
70
|
+
"specify the library name as "
|
|
71
|
+
"`NVMATH_FFT_CPU_LIBRARY=some_fftw3_compatible_lib.so` and make sure "
|
|
72
|
+
"the library can be found within current `LD_LIBRARY_PATH`"
|
|
73
|
+
) from e
|
|
74
|
+
|
|
75
|
+
if env_lib_name:
|
|
76
|
+
assert env_lib_name == loaded_lib_name
|
|
77
|
+
|
|
78
|
+
lib_nvpl = "libnvpl_fftw.so"
|
|
79
|
+
if not loaded_lib_name.startswith(lib_nvpl):
|
|
80
|
+
_fftw.init_threads_float()
|
|
81
|
+
_fftw.init_threads_double()
|
|
82
|
+
|
|
83
|
+
IS_EXEC_CPU_AVAILABLE = True
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _cross_setup_execution_and_options(
|
|
87
|
+
options: _configuration.FFTOptions,
|
|
88
|
+
execution: _configuration.ExecutionCUDA | _configuration.ExecutionCPU,
|
|
89
|
+
):
|
|
90
|
+
if execution.name == "cpu":
|
|
91
|
+
_check_init_fftw()
|
|
92
|
+
if options.device_id is not None:
|
|
93
|
+
raise ValueError("The 'device_id' is not a valid option when 'execution' is specified to be 'cpu'.")
|
|
94
|
+
if execution.num_threads is None:
|
|
95
|
+
execution.num_threads = _get_num_threads_default()
|
|
96
|
+
if not isinstance(execution.num_threads, int) or execution.num_threads <= 0:
|
|
97
|
+
raise ValueError("The 'num_threads' must be a positive integer")
|
|
98
|
+
else:
|
|
99
|
+
assert execution.name == "cuda"
|
|
100
|
+
_check_init_cufft()
|
|
101
|
+
if execution.device_id is None:
|
|
102
|
+
execution.device_id = options.device_id or 0
|
|
103
|
+
elif options.device_id is not None and execution.device_id != options.device_id:
|
|
104
|
+
raise ValueError(
|
|
105
|
+
f"Got conflicting 'device_id' passed in 'execution' ({execution.device_id}) "
|
|
106
|
+
f"and 'options' ({options.device_id}). It should be passed as 'execution' "
|
|
107
|
+
f"configuration only."
|
|
108
|
+
)
|
|
109
|
+
return options, execution
|
nvmath/fft/_helpers.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
__all__ = ["compile_prolog", "compile_epilog"]
|
|
6
|
+
|
|
7
|
+
import functools
|
|
8
|
+
|
|
9
|
+
from nvmath.bindings import cufft as _cufft # type: ignore
|
|
10
|
+
|
|
11
|
+
# Currently supported element data types for FFT callback functions.
|
|
12
|
+
VALID_DTYPES = {"float32": "Real", "float64": "DoubleReal", "complex64": "Complex", "complex128": "DoubleComplex"}
|
|
13
|
+
|
|
14
|
+
# Python <> CUDA magled types.
|
|
15
|
+
TYPE_MAP = {
|
|
16
|
+
"float32": "f", # float
|
|
17
|
+
"float64": "d", # double
|
|
18
|
+
"complex64": "6float2", # float2
|
|
19
|
+
"complex128": "7double2", # double2
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _check_numba_available():
|
|
24
|
+
try:
|
|
25
|
+
import numba # noqa: F401
|
|
26
|
+
except ModuleNotFoundError as e:
|
|
27
|
+
raise RuntimeError("Numba is required to compile FFT prolog and epilog functions.") from e
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _compile(
|
|
31
|
+
function, element_dtype, user_info_dtype, *, name=None, phase=None, representation="ltoir", compute_capability=None
|
|
32
|
+
):
|
|
33
|
+
_check_numba_available()
|
|
34
|
+
|
|
35
|
+
import numba
|
|
36
|
+
import numba.cuda
|
|
37
|
+
|
|
38
|
+
assert phase in ["Load", "Store"], "Internal error."
|
|
39
|
+
|
|
40
|
+
if element_dtype not in VALID_DTYPES:
|
|
41
|
+
raise ValueError(
|
|
42
|
+
f"The specified operand data type '{element_dtype}' is not currently supported. "
|
|
43
|
+
f"It must be one of {VALID_DTYPES.keys()}."
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
data_type = getattr(numba.cuda.types.types, element_dtype)
|
|
47
|
+
|
|
48
|
+
if user_info_dtype in VALID_DTYPES:
|
|
49
|
+
info_type = getattr(numba.cuda.types.types, user_info_dtype)
|
|
50
|
+
elif isinstance(user_info_dtype, numba.types.Type):
|
|
51
|
+
info_type = user_info_dtype
|
|
52
|
+
else:
|
|
53
|
+
raise ValueError(
|
|
54
|
+
f"The specified user information data type '{user_info_dtype}' is not supported. "
|
|
55
|
+
f"It must be a Numba custom type or one of {VALID_DTYPES.keys()}."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
dataptr_type = numba.types.CPointer(data_type)
|
|
59
|
+
infoptr_type = numba.types.CPointer(info_type)
|
|
60
|
+
offset_type = numba.types.uint64
|
|
61
|
+
smemptr_type = dataptr_type
|
|
62
|
+
|
|
63
|
+
if phase == "Load":
|
|
64
|
+
insert = ""
|
|
65
|
+
return_type = data_type
|
|
66
|
+
signature = numba.core.typing.signature(return_type, dataptr_type, offset_type, infoptr_type, smemptr_type)
|
|
67
|
+
else:
|
|
68
|
+
insert = TYPE_MAP[element_dtype]
|
|
69
|
+
return_type = numba.types.void
|
|
70
|
+
signature = numba.core.typing.signature(return_type, dataptr_type, offset_type, data_type, infoptr_type, smemptr_type)
|
|
71
|
+
|
|
72
|
+
if name is None:
|
|
73
|
+
snippet = VALID_DTYPES[element_dtype]
|
|
74
|
+
length = 16 + len(phase) + len(snippet)
|
|
75
|
+
# the signature of callbacks differs - the offset argument
|
|
76
|
+
# changed type from size_t to unsigned long long int
|
|
77
|
+
offset_dtype = "m" if _cufft.get_version() < 11300 else "y"
|
|
78
|
+
name = f"_Z{length}cufftJITCallback{phase}{snippet}Pv{offset_dtype}{insert}S_S_"
|
|
79
|
+
|
|
80
|
+
if compute_capability is None:
|
|
81
|
+
compute_capability = numba.cuda.get_current_device().compute_capability
|
|
82
|
+
else:
|
|
83
|
+
if not isinstance(compute_capability, str):
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"The compute capability must be specified as a string ('80', '89', ...). "
|
|
86
|
+
f"The provided value {compute_capability} is invalid."
|
|
87
|
+
)
|
|
88
|
+
cc_number = int(compute_capability)
|
|
89
|
+
compute_capability = (cc_number // 10, cc_number % 10)
|
|
90
|
+
|
|
91
|
+
return numba.cuda.compile(
|
|
92
|
+
function,
|
|
93
|
+
signature,
|
|
94
|
+
debug=None,
|
|
95
|
+
lineinfo=False,
|
|
96
|
+
device=True,
|
|
97
|
+
fastmath=False,
|
|
98
|
+
cc=compute_capability,
|
|
99
|
+
opt=True,
|
|
100
|
+
abi="c",
|
|
101
|
+
abi_info={"abi_name": name},
|
|
102
|
+
output=representation,
|
|
103
|
+
forceinline=False,
|
|
104
|
+
launch_bounds=None,
|
|
105
|
+
)[0]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
compile_prolog = functools.wraps(_compile)(functools.partial(_compile, phase="Load"))
|
|
109
|
+
compile_epilog = functools.wraps(_compile)(functools.partial(_compile, phase="Store"))
|
|
110
|
+
|
|
111
|
+
SHARED_FFT_HELPER_DOCUMENTATION = {
|
|
112
|
+
"element_dtype": """The data type of the ``data_in`` argument, one of ``['float32', 'float64', 'complex64',
|
|
113
|
+
'complex128']``. It must have the same data type as that of the FFT operand for prolog functions or the FFT
|
|
114
|
+
result for epilog functions.""",
|
|
115
|
+
"user_info_dtype": """The data type of the ``user_info`` argument. It must be one of ``['float32', 'float64',
|
|
116
|
+
'complex64', 'complex128']`` or an object of type :class:`numba.types.Type`. The offset is computed based on
|
|
117
|
+
the memory layout (shape and strides) of the operand (input for prolog, output for epilog). If the user
|
|
118
|
+
would like to pass additional tensor as `user_info` and access it based on the offset, it is crucial to know
|
|
119
|
+
memory layout of the operand. Please note, the actual layout of the input tensor may differ from the layout
|
|
120
|
+
of the tensor passed to fft call. To learn the memory layout of the input or output, please use stateful FFT
|
|
121
|
+
API and :meth:`nvmath.fft.FFT.get_input_layout` :meth:`nvmath.fft.FFT.get_output_layout` respectively.
|
|
122
|
+
|
|
123
|
+
.. note::
|
|
124
|
+
Currently, in the callback, the position of the element in the input and output operands are described
|
|
125
|
+
with a single flat offset, even if the original operand is multi-dimensional tensor.
|
|
126
|
+
|
|
127
|
+
""",
|
|
128
|
+
"compute_capability": """The target compute capability, specified as a string (``'80'``, ``'89'``, ...). The
|
|
129
|
+
default is the compute capability of the current device. For cuFFT in CUDA Toolkit 12.8, 12.9
|
|
130
|
+
on Blackwell devices (compute capability 12.0), the default
|
|
131
|
+
compute capability of the current device may fail to compile. As a workaround, ``'50'``
|
|
132
|
+
can be specified.""",
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
compile_prolog.__doc__ = """
|
|
136
|
+
compile_prolog(prolog_fn, element_dtype, user_info_dtype, *, compute_capability=None)
|
|
137
|
+
|
|
138
|
+
Compile a Python function to LTO-IR to provide as a prolog function for
|
|
139
|
+
:func:`~nvmath.fft.fft` and :meth:`~nvmath.fft.FFT.plan`.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
prolog_fn: The prolog function to be compiled to LTO-IR. It must have the signature:
|
|
143
|
+
``prolog_fn(data_in, offset, user_info, reserved_for_future_use)``, and it
|
|
144
|
+
essentially returns transformed ``data_in`` at ``offset``.
|
|
145
|
+
|
|
146
|
+
element_dtype: {element_dtype}
|
|
147
|
+
|
|
148
|
+
user_info_dtype: {user_info_dtype}
|
|
149
|
+
|
|
150
|
+
compute_capability: {compute_capability}
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
The function compiled to LTO-IR as `bytes` object.
|
|
154
|
+
|
|
155
|
+
.. seealso::
|
|
156
|
+
:func:`~nvmath.fft.fft`, :meth:`~nvmath.fft.FFT.plan`,
|
|
157
|
+
:func:`~nvmath.fft.compile_epilog`.
|
|
158
|
+
|
|
159
|
+
Notes:
|
|
160
|
+
- The user must ensure that the specified argument types meet the requirements
|
|
161
|
+
listed above.
|
|
162
|
+
""".format(**SHARED_FFT_HELPER_DOCUMENTATION)
|
|
163
|
+
compile_prolog.__name__ = "compile_prolog"
|
|
164
|
+
|
|
165
|
+
compile_epilog.__doc__ = """
|
|
166
|
+
compile_epilog(epilog_fn, element_dtype, user_info_dtype, *, compute_capability=None)
|
|
167
|
+
|
|
168
|
+
Compile a Python function to LTO-IR to provide as an epilog function for
|
|
169
|
+
:func:`~nvmath.fft.fft` and :meth:`~nvmath.fft.FFT.plan`.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
epilog_fn: The epilog function to be compiled to LTO-IR. It must have the signature:
|
|
173
|
+
``epilog_fn(data_out, offset, data, user_info, reserved_for_future_use)``, and
|
|
174
|
+
it essentially stores transformed ``data`` into ``data_out`` at ``offset``.
|
|
175
|
+
|
|
176
|
+
element_dtype: {element_dtype}
|
|
177
|
+
|
|
178
|
+
user_info_dtype: {user_info_dtype}
|
|
179
|
+
|
|
180
|
+
compute_capability: {compute_capability}
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
The function compiled to LTO-IR as `bytes` object.
|
|
184
|
+
|
|
185
|
+
.. seealso::
|
|
186
|
+
:func:`~nvmath.fft.fft`, :meth:`~nvmath.fft.FFT.plan`,
|
|
187
|
+
:func:`~nvmath.fft.compile_prolog`.
|
|
188
|
+
|
|
189
|
+
Examples:
|
|
190
|
+
|
|
191
|
+
The cuFFT library expects the end user to manage scaling of the outputs, so in order
|
|
192
|
+
to replicate the ``norm`` option found in `other Python FFT libraries
|
|
193
|
+
<https://numpy.org/doc/stable/reference/routines.fft.html#normalization>`_ we can
|
|
194
|
+
define an epilog which performs the scaling.
|
|
195
|
+
|
|
196
|
+
>>> import cupy as cp
|
|
197
|
+
>>> import nvmath
|
|
198
|
+
>>> import math
|
|
199
|
+
|
|
200
|
+
Create the data for a batched 1-D FFT.
|
|
201
|
+
|
|
202
|
+
>>> B, N = 256, 1024
|
|
203
|
+
>>> a = cp.random.rand(B, N, dtype=cp.float64) + 1j * cp.random.rand(B, N, dtype=cp.float64)
|
|
204
|
+
|
|
205
|
+
Compute a normalization factor that will create unitary transforms.
|
|
206
|
+
|
|
207
|
+
>>> norm_factor = 1.0 / math.sqrt(N)
|
|
208
|
+
|
|
209
|
+
Define the epilog function for the FFT.
|
|
210
|
+
|
|
211
|
+
>>> def rescale(data_out, offset, data, user_info, unused):
|
|
212
|
+
... data_out[offset] = data * norm_factor
|
|
213
|
+
|
|
214
|
+
Compile the epilog to LTO-IR. In a system with GPUs that have different compute
|
|
215
|
+
capability, the `compute_capability` option must be specified to the
|
|
216
|
+
`compile_prolog` or `compile_epilog` helpers. Alternatively, the epilog can be
|
|
217
|
+
compiled in the context of the device where the FFT to which the epilog is provided
|
|
218
|
+
is executed. In this case we use the current device context, where the operands have
|
|
219
|
+
been created.
|
|
220
|
+
|
|
221
|
+
>>> with cp.cuda.Device():
|
|
222
|
+
... epilog = nvmath.fft.compile_epilog(rescale, "complex128", "complex128")
|
|
223
|
+
|
|
224
|
+
Perform the forward FFT, applying the rescaling as a epilog.
|
|
225
|
+
|
|
226
|
+
>>> r = nvmath.fft.fft(a, axes=[-1], epilog=dict(ltoir=epilog))
|
|
227
|
+
|
|
228
|
+
Test that the fused FFT run result matches the result of other libraries.
|
|
229
|
+
|
|
230
|
+
>>> s = cp.fft.fftn(a, axes=[-1], norm="ortho")
|
|
231
|
+
>>> assert cp.allclose(r, s)
|
|
232
|
+
|
|
233
|
+
Notes:
|
|
234
|
+
- The user must ensure that the specified argument types meet the requirements
|
|
235
|
+
listed above.
|
|
236
|
+
""".format(**SHARED_FFT_HELPER_DOCUMENTATION)
|
|
237
|
+
compile_epilog.__name__ = "compile_epilog"
|