nvmath-python 1.0.0__cp314-cp314t-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 +130 -0
- nvmath/_internal/threadsafe.py +106 -0
- nvmath/_internal/utils.py +43 -0
- nvmath/_internal/workspace.py +490 -0
- nvmath/_utils.py +147 -0
- nvmath/bindings/__init__.py +60 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/common_types.pxd +31 -0
- nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +54 -0
- nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusolverMp.pxd +71 -0
- nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverSp.pxd +75 -0
- nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +471 -0
- nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +174 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +812 -0
- nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1461 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +267 -0
- nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +98 -0
- nvmath/bindings/cudss.pyi +443 -0
- nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +301 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +326 -0
- nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +189 -0
- nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +320 -0
- nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +422 -0
- nvmath/bindings/cusolverMp.pxd +98 -0
- nvmath/bindings/cusolverMp.pyi +114 -0
- nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverSp.pxd +95 -0
- nvmath/bindings/cusolverSp.pyi +70 -0
- nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +546 -0
- nvmath/bindings/cusparse.pyi +1017 -0
- nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +252 -0
- nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +324 -0
- nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +664 -0
- nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1045 -0
- nvmath/bindings/cycublasMp.pxd +171 -0
- nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +277 -0
- nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +333 -0
- nvmath/bindings/cycufftMp.pxd +342 -0
- nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +141 -0
- nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +137 -0
- nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +443 -0
- nvmath/bindings/cycusolverMp.pxd +107 -0
- nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverSp.pxd +93 -0
- nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +679 -0
- nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +135 -0
- nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +189 -0
- nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +118 -0
- nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1562 -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.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
- nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +131 -0
- nvmath/bindings/nvpl/blas.pyi +168 -0
- nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +280 -0
- nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +93 -0
- nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +168 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +191 -0
- nvmath/device/__init__.py +38 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +315 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +300 -0
- nvmath/device/common_numba_cuda_mlir.py +202 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1606 -0
- nvmath/device/cublasdx_backend.py +860 -0
- nvmath/device/cublasdx_numba.py +1534 -0
- nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
- nvmath/device/cufftdx.py +373 -0
- nvmath/device/cufftdx_backend.py +220 -0
- nvmath/device/cufftdx_numba.py +140 -0
- nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2708 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +567 -0
- nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
- nvmath/device/cusolverdx_overload_backend.py +1029 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +441 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +138 -0
- nvmath/device/vector_types_numba.py +259 -0
- nvmath/distributed/__init__.py +200 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nccl.py +86 -0
- nvmath/distributed/_internal/nvshmem.py +307 -0
- nvmath/distributed/_internal/symmetric_memory.py +35 -0
- nvmath/distributed/_internal/tensor_ifc.py +70 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
- nvmath/distributed/_internal/tensor_wrapper.py +81 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution/__init__.py +30 -0
- nvmath/distributed/distribution/_configuration.py +39 -0
- nvmath/distributed/distribution/distributions.py +1024 -0
- nvmath/distributed/distribution/redistribute.py +1284 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +82 -0
- nvmath/distributed/fft/fft.py +2742 -0
- nvmath/distributed/linalg/__init__.py +22 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -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 +171 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
- nvmath/distributed/linalg/generic/__init__.py +8 -0
- nvmath/distributed/linalg/generic/_caching.py +66 -0
- nvmath/distributed/linalg/generic/_configuration.py +61 -0
- nvmath/distributed/linalg/generic/_factorization.py +172 -0
- nvmath/distributed/linalg/generic/_initialization.py +966 -0
- nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
- nvmath/distributed/linalg/generic/solvermod.py +1368 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +189 -0
- nvmath/fft/_exec_utils.py +82 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +3122 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +18 -0
- nvmath/internal/_device_utils.py +45 -0
- nvmath/internal/_layout/__init__.pxd +3 -0
- nvmath/internal/_layout/__init__.py +7 -0
- nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_layout/_layout.pxd +1303 -0
- nvmath/internal/_layout/_layout.pyi +1145 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +13 -0
- nvmath/internal/memory.pyi +50 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +9 -0
- nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
- nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_jit.pxd +7 -0
- nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
- nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -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 +242 -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/package_ifc.py +168 -0
- nvmath/internal/package_ifc_cuda.py +57 -0
- nvmath/internal/package_ifc_cupy.py +67 -0
- nvmath/internal/package_ifc_torch.py +69 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +179 -0
- nvmath/internal/tensor_ifc_cupy.py +234 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
- nvmath/internal/tensor_ifc_numpy.py +184 -0
- nvmath/internal/tensor_ifc_torch.py +178 -0
- nvmath/internal/tensor_wrapper.py +160 -0
- nvmath/internal/typemaps.py +113 -0
- nvmath/internal/utils.py +805 -0
- nvmath/linalg/__init__.py +56 -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 +234 -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/solver_utils.py +432 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +157 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +170 -0
- nvmath/linalg/advanced/_configuration.py +351 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1316 -0
- nvmath/linalg/advanced/matmulmod.py +3734 -0
- nvmath/linalg/generic/__init__.py +53 -0
- nvmath/linalg/generic/_configuration/__init__.py +39 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +734 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
- nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +2094 -0
- nvmath/linalg/generic/solvermod.py +1301 -0
- nvmath/memory.py +279 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +147 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +506 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +227 -0
- nvmath/sparse/advanced/direct_solver.py +2069 -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 +2353 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +422 -0
- nvmath/sparse/ust/_cpp.py +28 -0
- nvmath/sparse/ust/_drawer.py +565 -0
- nvmath/sparse/ust/_emitter.py +1033 -0
- nvmath/sparse/ust/_jit.py +188 -0
- nvmath/sparse/ust/_kernel.py +282 -0
- nvmath/sparse/ust/_utils.py +149 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/tensor.py +1016 -0
- nvmath/sparse/ust/tensor_format.py +957 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +120 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
- nvmath/tensor/_internal/cutensor_utils.py +230 -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 +1900 -0
- nvmath_python-1.0.0.dist-info/METADATA +134 -0
- nvmath_python-1.0.0.dist-info/RECORD +332 -0
- nvmath_python-1.0.0.dist-info/WHEEL +5 -0
- nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-1.0.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface to seamlessly use Torch tensor objects.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["TorchTensor"]
|
|
10
|
+
|
|
11
|
+
import contextlib
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
14
|
+
import torch
|
|
15
|
+
|
|
16
|
+
from .package_ifc import StreamHolder
|
|
17
|
+
from .tensor_ifc import TensorHolder
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TorchTensor(TensorHolder[torch.Tensor]):
|
|
21
|
+
"""
|
|
22
|
+
TensorHolder for Torch Tensors.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
name = "torch"
|
|
26
|
+
module = torch
|
|
27
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(
|
|
28
|
+
conversion_function=lambda name: getattr(torch, name), exception_type=AttributeError
|
|
29
|
+
)
|
|
30
|
+
host_tensor_class: type["TorchTensor"] # set once NumpyTensor is defined
|
|
31
|
+
device_tensor_class: type["TorchTensor"] # set once CudaTensor is defined
|
|
32
|
+
|
|
33
|
+
def __init__(self, tensor):
|
|
34
|
+
super().__init__(tensor)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def data_ptr(self):
|
|
38
|
+
return self.tensor.data_ptr()
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def device(self):
|
|
42
|
+
return str(self.tensor.device).split(":")[0]
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def device_id(self):
|
|
46
|
+
index = self.tensor.device.index
|
|
47
|
+
return "cpu" if index is None else index
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def dtype(self):
|
|
51
|
+
"""Name of the data type"""
|
|
52
|
+
return str(self.tensor.dtype).split(".")[-1]
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def itemsize(self):
|
|
56
|
+
return self.tensor.itemsize
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def shape(self):
|
|
60
|
+
return tuple(self.tensor.shape)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def size(self):
|
|
64
|
+
return self.tensor.nelement()
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def strides(self):
|
|
68
|
+
return self.tensor.stride()
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def empty(
|
|
72
|
+
cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
|
|
73
|
+
):
|
|
74
|
+
"""
|
|
75
|
+
Create an empty tensor of the specified shape and data type on the specified device
|
|
76
|
+
(None, 'cpu', or device id).
|
|
77
|
+
|
|
78
|
+
Note, that the strides, if specified, should correspond to a dense
|
|
79
|
+
(possibly permuted) tensor and MUST NOT overlap.
|
|
80
|
+
Otherwise, the behaviour is not defined.
|
|
81
|
+
"""
|
|
82
|
+
dtype = TorchTensor.name_to_dtype[dtype]
|
|
83
|
+
stream_ctx = contextlib.nullcontext() if stream_holder is None else stream_holder.ctx
|
|
84
|
+
with stream_ctx:
|
|
85
|
+
if strides:
|
|
86
|
+
# note: torch strides is not scaled by bytes
|
|
87
|
+
tensor = torch.empty_strided(shape, strides, dtype=dtype, device=device_id)
|
|
88
|
+
else:
|
|
89
|
+
tensor = torch.empty(shape, dtype=dtype, device=device_id)
|
|
90
|
+
|
|
91
|
+
return cls(tensor)
|
|
92
|
+
|
|
93
|
+
def asndbuffer(self):
|
|
94
|
+
raise RuntimeError("Converting torch tensor to ndbuffer is not supported")
|
|
95
|
+
|
|
96
|
+
def to(self, device_id, stream_holder):
|
|
97
|
+
if not (device_id == "cpu" or isinstance(device_id, int)):
|
|
98
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
99
|
+
|
|
100
|
+
# For h2d the data on the CPU is available and we block on `to()`, so a stream
|
|
101
|
+
# is not needed. It is currently ignored if provided.
|
|
102
|
+
|
|
103
|
+
# For d2h and d2d, we require a stream to ensure that the source data is ready
|
|
104
|
+
# before the copy operation is launched.
|
|
105
|
+
if self.device_id != "cpu" and stream_holder is None:
|
|
106
|
+
raise AssertionError("Internal error: a stream holder should be provided for d2h or d2d copies.")
|
|
107
|
+
|
|
108
|
+
# Always block for h2d and d2h copies to ensure that the copied data is ready
|
|
109
|
+
# for consumption when `to()` return.
|
|
110
|
+
|
|
111
|
+
# For d2d, the `torch.to()` operation is launched on the source device on the
|
|
112
|
+
# specified stream, so this stream must be on the source device. Their
|
|
113
|
+
# implementation ensures correct ordering between the current streams on the
|
|
114
|
+
# source and target devices.
|
|
115
|
+
|
|
116
|
+
blocking = self.device_id == "cpu" or device_id == "cpu"
|
|
117
|
+
|
|
118
|
+
stream_ctx = contextlib.nullcontext() if stream_holder is None else stream_holder.ctx
|
|
119
|
+
with stream_ctx:
|
|
120
|
+
tensor_device = self.tensor.to(device=device_id, non_blocking=not blocking)
|
|
121
|
+
|
|
122
|
+
return TorchTensor(tensor_device)
|
|
123
|
+
|
|
124
|
+
def copy_(self, src, stream_holder):
|
|
125
|
+
"""
|
|
126
|
+
Inplace copy of src (copy the data from src into self).
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
# For d2h and d2d, we require a stream to ensure that the source data is ready
|
|
130
|
+
# before the copy operation is launched.
|
|
131
|
+
if src.device_id != "cpu" and stream_holder is None:
|
|
132
|
+
raise AssertionError("Internal error: a stream holder should be provided for d2h or d2d copies.")
|
|
133
|
+
|
|
134
|
+
stream_ctx = contextlib.nullcontext() if stream_holder is None else stream_holder.ctx
|
|
135
|
+
with stream_ctx:
|
|
136
|
+
self.tensor.copy_(src.tensor)
|
|
137
|
+
|
|
138
|
+
def istensor(self):
|
|
139
|
+
"""
|
|
140
|
+
Check if the object is ndarray-like.
|
|
141
|
+
"""
|
|
142
|
+
return isinstance(self.tensor, torch.Tensor)
|
|
143
|
+
|
|
144
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
145
|
+
if copy:
|
|
146
|
+
raise NotImplementedError("reshape with copy=True not implemented")
|
|
147
|
+
if copy is False:
|
|
148
|
+
return self.__class__(self.tensor.view(shape))
|
|
149
|
+
return self.__class__(self.tensor.reshape(shape))
|
|
150
|
+
|
|
151
|
+
def memory_buffer(self):
|
|
152
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
153
|
+
storage = self.tensor.untyped_storage()
|
|
154
|
+
size = self.size
|
|
155
|
+
v = self.tensor.view(self.shape)
|
|
156
|
+
# TODO: ensure tensor is dense for now, and later support linear
|
|
157
|
+
# memory with constant stride.
|
|
158
|
+
v.set_(storage, self.tensor.storage_offset(), (size,), (1,))
|
|
159
|
+
return TorchTensor(v)
|
|
160
|
+
|
|
161
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
162
|
+
"""
|
|
163
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
164
|
+
shape and strides.
|
|
165
|
+
"""
|
|
166
|
+
assert len(self.shape) == 1, "Internal error."
|
|
167
|
+
storage = self.tensor.untyped_storage()
|
|
168
|
+
t = self.tensor.view(self.shape)
|
|
169
|
+
t.set_(storage, self.tensor.storage_offset(), shape, strides)
|
|
170
|
+
return TorchTensor(t)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def is_conjugate(self) -> bool:
|
|
174
|
+
return self.tensor.is_conj()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
TorchTensor.host_tensor_class = TorchTensor
|
|
178
|
+
TorchTensor.device_tensor_class = TorchTensor
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Entry point to using tensors from different libraries seamlessly.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["infer_tensor_package", "wrap_operand", "wrap_operands", "to", "copy_", "TensorHolder", "AnyTensor"]
|
|
10
|
+
|
|
11
|
+
import warnings
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
from . import formatters
|
|
17
|
+
from .ndbuffer import NDBuffer
|
|
18
|
+
from .tensor_ifc import AnyTensor, Tensor, TensorHolder
|
|
19
|
+
from .tensor_ifc_numpy import CudaTensor, NumpyTensor
|
|
20
|
+
|
|
21
|
+
_TENSOR_TYPES: dict[str, type[TensorHolder]] = {"numpy": NumpyTensor, "cuda": CudaTensor}
|
|
22
|
+
|
|
23
|
+
_SUPPORTED_PACKAGES = tuple(_TENSOR_TYPES.keys())
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def infer_tensor_package(tensor):
|
|
27
|
+
"""
|
|
28
|
+
Infer the package that defines this tensor.
|
|
29
|
+
"""
|
|
30
|
+
if issubclass(tensor.__class__, np.ndarray):
|
|
31
|
+
return "numpy"
|
|
32
|
+
if type(tensor) is NDBuffer:
|
|
33
|
+
return "cuda" if tensor.device == "cuda" else "cupy_host"
|
|
34
|
+
module = tensor.__class__.__module__
|
|
35
|
+
package = module.split(".")[0]
|
|
36
|
+
maybe_register_package(package)
|
|
37
|
+
return package
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def maybe_register_package(package):
|
|
41
|
+
global _SUPPORTED_PACKAGES
|
|
42
|
+
if package not in _SUPPORTED_PACKAGES:
|
|
43
|
+
global _TENSOR_TYPES
|
|
44
|
+
from .. import memory
|
|
45
|
+
from . import package_wrapper
|
|
46
|
+
|
|
47
|
+
if package == "torch":
|
|
48
|
+
from .package_ifc_torch import TorchPackage
|
|
49
|
+
from .tensor_ifc_torch import TorchTensor
|
|
50
|
+
|
|
51
|
+
_TENSOR_TYPES[package] = TorchTensor
|
|
52
|
+
package_wrapper.PACKAGE[package] = TorchPackage
|
|
53
|
+
memory.lazy_load_torch()
|
|
54
|
+
elif package == "cupy":
|
|
55
|
+
from .package_ifc_cupy import CupyPackage
|
|
56
|
+
from .tensor_ifc_cupy import CupyTensor, HostTensor
|
|
57
|
+
|
|
58
|
+
_TENSOR_TYPES[package] = CupyTensor
|
|
59
|
+
_TENSOR_TYPES["cupy_host"] = HostTensor
|
|
60
|
+
package_wrapper.PACKAGE[package] = CupyPackage
|
|
61
|
+
package_wrapper.PACKAGE["cupy_host"] = CupyPackage
|
|
62
|
+
memory.lazy_load_cupy()
|
|
63
|
+
else:
|
|
64
|
+
message = f"""{package} not supported yet. Currently must be one of ['numpy', 'cupy', 'torch']"""
|
|
65
|
+
raise ValueError(message)
|
|
66
|
+
_SUPPORTED_PACKAGES = tuple(_TENSOR_TYPES.keys())
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def wrap_operand(native_operand: Tensor) -> TensorHolder[Tensor]:
|
|
70
|
+
"""
|
|
71
|
+
Wrap one "native" operand so that package-agnostic API can be used.
|
|
72
|
+
"""
|
|
73
|
+
if isinstance(native_operand, TensorHolder):
|
|
74
|
+
msg = (
|
|
75
|
+
"wrap_operand() is being called unnecessarily because the input is already a TensorHolder. "
|
|
76
|
+
"Only public facing APIs should call wrap_operand(). "
|
|
77
|
+
"Internal APIs should assume the operands are TensorHolder already."
|
|
78
|
+
"Trying to wrap a TensorHolder will become an error in the future."
|
|
79
|
+
)
|
|
80
|
+
warnings.warn(msg, DeprecationWarning)
|
|
81
|
+
return native_operand
|
|
82
|
+
wrapped_operand = _TENSOR_TYPES[infer_tensor_package(native_operand)](native_operand)
|
|
83
|
+
return wrapped_operand
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def check_valid_package(native_operands):
|
|
87
|
+
"""
|
|
88
|
+
Check if the operands belong to one of the supported packages.
|
|
89
|
+
"""
|
|
90
|
+
operands_pkg = [infer_tensor_package(o) for o in native_operands]
|
|
91
|
+
checks = [p in _SUPPORTED_PACKAGES for p in operands_pkg]
|
|
92
|
+
if not all(checks):
|
|
93
|
+
unknown = [f"{location}: {operands_pkg[location]}" for location, predicate in enumerate(checks) if predicate is False]
|
|
94
|
+
unknown = formatters.array2string(unknown)
|
|
95
|
+
message = f"""The operands should be ndarray-like objects from one of {_SUPPORTED_PACKAGES} packages.
|
|
96
|
+
The unsupported operands as a sequence of "position: package" is: \n{unknown}"""
|
|
97
|
+
raise ValueError(message)
|
|
98
|
+
|
|
99
|
+
return operands_pkg
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def check_valid_operand_type(wrapped_operands):
|
|
103
|
+
"""
|
|
104
|
+
Check if the wrapped operands are ndarray-like.
|
|
105
|
+
"""
|
|
106
|
+
istensor = [o.istensor() for o in wrapped_operands]
|
|
107
|
+
if not all(istensor):
|
|
108
|
+
unknown = [
|
|
109
|
+
f"{location}: {type(wrapped_operands[location].tensor)}"
|
|
110
|
+
for location, predicate in enumerate(istensor)
|
|
111
|
+
if predicate is False
|
|
112
|
+
]
|
|
113
|
+
unknown = formatters.array2string(unknown)
|
|
114
|
+
message = f"""The operands should be ndarray-like objects from one of {_SUPPORTED_PACKAGES} packages.
|
|
115
|
+
The unsupported operands as a sequence of "position: type" is: \n{unknown}"""
|
|
116
|
+
raise ValueError(message)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _wrapper_helper(operand: Tensor | TensorHolder, index: int, packages: list[str]) -> TensorHolder[Tensor]:
|
|
120
|
+
if isinstance(operand, TensorHolder):
|
|
121
|
+
msg = (
|
|
122
|
+
"wrap_operands() is being called unnecessarily because at least one input is already a TensorHolder. "
|
|
123
|
+
"Only public facing APIs should call wrap_operands(). "
|
|
124
|
+
"Internal APIs should assume the operands are TensorHolder already."
|
|
125
|
+
"Trying to wrap a TensorHolder will become an error in the future."
|
|
126
|
+
)
|
|
127
|
+
warnings.warn(msg, DeprecationWarning)
|
|
128
|
+
return operand
|
|
129
|
+
return _TENSOR_TYPES[packages[index]](operand)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def wrap_operands(native_operands: Sequence[Tensor]) -> Sequence[TensorHolder[Tensor]]:
|
|
133
|
+
"""
|
|
134
|
+
Wrap the "native" operands so that package-agnostic API can be used.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
operands_pkg = check_valid_package(native_operands)
|
|
138
|
+
|
|
139
|
+
wrapped_operands = tuple(_wrapper_helper(o, i, operands_pkg) for i, o in enumerate(native_operands))
|
|
140
|
+
|
|
141
|
+
check_valid_operand_type(wrapped_operands)
|
|
142
|
+
|
|
143
|
+
return wrapped_operands
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def to(operands: Sequence[TensorHolder], device_id, stream_holder) -> Sequence[TensorHolder]:
|
|
147
|
+
"""
|
|
148
|
+
Copy the wrapped operands to the specified device_id (None or int) and return the
|
|
149
|
+
wrapped operands on the device.
|
|
150
|
+
"""
|
|
151
|
+
assert isinstance(operands, Sequence) and isinstance(operands[0], TensorHolder)
|
|
152
|
+
return tuple(o.to(device_id, stream_holder) for o in operands)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def copy_(src: Sequence[TensorHolder], dest: Sequence[TensorHolder], stream_holder):
|
|
156
|
+
"""
|
|
157
|
+
Copy the wrapped operands in src to the corresponding wrapped operands in dest.
|
|
158
|
+
"""
|
|
159
|
+
for s, d in zip(src, dest, strict=True):
|
|
160
|
+
d.copy_(s, stream_holder=stream_holder)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Functions to link type names with CUDA data and compute types.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["COMPUTE_TYPE_TO_NAME", "DATA_TYPE_TO_NAME", "NAME_TO_DATA_TYPE", "NAME_TO_COMPUTE_TYPE", "NAME_TO_DATA_WIDTH"]
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
|
|
13
|
+
from nvmath._utils import ComputeType
|
|
14
|
+
from nvmath._utils import CudaDataType as cudaDataType
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_cuda_data_type_map(cuda_data_type_enum_class):
|
|
18
|
+
"""
|
|
19
|
+
Map the data type name to the corresponding CUDA data type.
|
|
20
|
+
"""
|
|
21
|
+
cuda_data_type_pattern = re.compile(r"CUDA_(?P<cr>C|R)_(?P<width>\d+)(?P<type>F|I|U|BF)_?(?P<kind>(E\dM\d)?)")
|
|
22
|
+
|
|
23
|
+
type_code_map = {"i": "int", "u": "uint", "f": "float", "bf": "bfloat"}
|
|
24
|
+
# A map from (width, exponent kind) to qualifiers (finite, unsigned zero, ...) for data
|
|
25
|
+
# types.
|
|
26
|
+
type_qualifier_map = {
|
|
27
|
+
(8, "e4m3"): "fn",
|
|
28
|
+
# FP4: finite-only, packed 2 per byte, see for example:
|
|
29
|
+
# - https://github.com/pytorch/pytorch/issues/146414
|
|
30
|
+
# - https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
|
|
31
|
+
(4, "e2m1"): "fn_x2",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
complex_types = {"float": "complex", "bfloat": "bcomplex"}
|
|
35
|
+
|
|
36
|
+
cuda_data_type_map = {}
|
|
37
|
+
data_type_width_map = {}
|
|
38
|
+
for d in cuda_data_type_enum_class:
|
|
39
|
+
m = cuda_data_type_pattern.match(d.name)
|
|
40
|
+
|
|
41
|
+
is_complex = m.group("cr").lower() == "c"
|
|
42
|
+
type_code = type_code_map[m.group("type").lower()]
|
|
43
|
+
|
|
44
|
+
# We'll generalize this if and when we support Gaussian integers.
|
|
45
|
+
if is_complex and type_code not in complex_types:
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
width = int(m.group("width"))
|
|
49
|
+
if is_complex:
|
|
50
|
+
width *= 2
|
|
51
|
+
type_code = complex_types[type_code]
|
|
52
|
+
|
|
53
|
+
name = type_code + str(width)
|
|
54
|
+
|
|
55
|
+
# Handle narrow type kinds.
|
|
56
|
+
if width <= 8:
|
|
57
|
+
kind = m.group("kind").lower()
|
|
58
|
+
# Handle type qualifiers for narrow types.
|
|
59
|
+
kind += type_qualifier_map.get((width, kind), "")
|
|
60
|
+
if kind:
|
|
61
|
+
name += "_" + kind
|
|
62
|
+
|
|
63
|
+
cuda_data_type_map[name] = d
|
|
64
|
+
data_type_width_map[name] = width
|
|
65
|
+
|
|
66
|
+
return cuda_data_type_map, data_type_width_map
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def create_cuda_compute_type_map(cuda_compute_type_enum_class):
|
|
70
|
+
"""
|
|
71
|
+
Map the data type name to the corresponding CUDA compute type.
|
|
72
|
+
"""
|
|
73
|
+
cuda_compute_type_pattern = re.compile(r"COMPUTE_(?:(?P<width>\d+)(?P<type>F|I|U|BF)|(?P<tf32>TF32))")
|
|
74
|
+
|
|
75
|
+
type_code_map = {"i": "int", "u": "uint", "f": "float", "bf": "bfloat"}
|
|
76
|
+
|
|
77
|
+
cuda_compute_type_map = {}
|
|
78
|
+
for c in cuda_compute_type_enum_class:
|
|
79
|
+
if c.name == "COMPUTE_DEFAULT":
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
m = cuda_compute_type_pattern.match(c.name)
|
|
83
|
+
|
|
84
|
+
if not m:
|
|
85
|
+
raise ValueError("Internal error - unexpected enum entry")
|
|
86
|
+
|
|
87
|
+
if m.group("tf32"):
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
name = type_code_map[m.group("type").lower()] + m.group("width")
|
|
91
|
+
cuda_compute_type_map[name] = c
|
|
92
|
+
|
|
93
|
+
# Treat complex types as special case.
|
|
94
|
+
cuda_compute_type_map["bcomplex32"] = cuda_compute_type_enum_class.COMPUTE_16BF
|
|
95
|
+
cuda_compute_type_map["complex32"] = cuda_compute_type_enum_class.COMPUTE_16F
|
|
96
|
+
cuda_compute_type_map["complex64"] = cuda_compute_type_enum_class.COMPUTE_32F
|
|
97
|
+
cuda_compute_type_map["complex128"] = cuda_compute_type_enum_class.COMPUTE_64F
|
|
98
|
+
|
|
99
|
+
return cuda_compute_type_map
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
NAME_TO_DATA_TYPE, NAME_TO_DATA_WIDTH = create_cuda_data_type_map(cudaDataType)
|
|
103
|
+
NAME_TO_ITEM_SIZE = {k: v // 8 for k, v in NAME_TO_DATA_WIDTH.items() if v % 8 == 0}
|
|
104
|
+
DATA_TYPE_TO_NAME = {v: k for k, v in NAME_TO_DATA_TYPE.items()}
|
|
105
|
+
NAME_TO_COMPUTE_TYPE = create_cuda_compute_type_map(ComputeType)
|
|
106
|
+
COMPUTE_TYPE_TO_NAME = {v: k for k, v in NAME_TO_COMPUTE_TYPE.items()}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
FFTW_SUPPORTED_SINGLE = (cudaDataType.CUDA_R_32F, cudaDataType.CUDA_C_32F)
|
|
110
|
+
FFTW_SUPPORTED_DOUBLE = (cudaDataType.CUDA_R_64F, cudaDataType.CUDA_C_64F)
|
|
111
|
+
FFTW_SUPPORTED_FLOAT = (cudaDataType.CUDA_R_32F, cudaDataType.CUDA_R_64F)
|
|
112
|
+
FFTW_SUPPORTED_COMPLEX = (cudaDataType.CUDA_C_32F, cudaDataType.CUDA_C_64F)
|
|
113
|
+
FFTW_SUPPORTED_TYPES = sorted(FFTW_SUPPORTED_SINGLE + FFTW_SUPPORTED_DOUBLE)
|