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,26 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface class to encapsulate low-level calls to get and set matrix layout attributes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["MatrixLayoutInterface"]
|
|
10
|
+
|
|
11
|
+
from nvmath._internal.attribute_ifc_factory import make_cublas_attribute_interface
|
|
12
|
+
from nvmath.bindings import cublasLt as cublaslt
|
|
13
|
+
|
|
14
|
+
# Create a class, MatrixLayoutInterface, such that each enum member in
|
|
15
|
+
# MatrixLayoutAttribute is exposed as a lowercase property (getter + setter).
|
|
16
|
+
# For example, if the class instance is stored as ``layout_ifc``,
|
|
17
|
+
# then the enum member ``ROWS`` becomes the property
|
|
18
|
+
# ``layout_ifc.rows``.
|
|
19
|
+
MatrixLayoutInterface = make_cublas_attribute_interface(
|
|
20
|
+
class_module=__name__,
|
|
21
|
+
class_name="MatrixLayoutInterface",
|
|
22
|
+
attribute_enum=cublaslt.MatrixLayoutAttribute,
|
|
23
|
+
get_attribute_dtype_fn=cublaslt.get_matrix_layout_attribute_dtype,
|
|
24
|
+
get_attribute_fn=cublaslt.matrix_layout_get_attribute,
|
|
25
|
+
set_attribute_fn=cublaslt.matrix_layout_set_attribute,
|
|
26
|
+
)
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"BatchInfo",
|
|
7
|
+
"compute_f_strides",
|
|
8
|
+
"LHSLayout",
|
|
9
|
+
"RHSLayout",
|
|
10
|
+
"get_lhs_layout",
|
|
11
|
+
"get_rhs_layout",
|
|
12
|
+
"wrap_solver_operands",
|
|
13
|
+
"wrap_check_solver_lhs",
|
|
14
|
+
"wrap_check_solver_rhs",
|
|
15
|
+
"parse_solver_operands",
|
|
16
|
+
"copy_operands",
|
|
17
|
+
"SolverBackend",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
import enum
|
|
21
|
+
import math
|
|
22
|
+
from collections.abc import Sequence
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
from typing import Literal, TypeAlias, TypeGuard, cast
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
|
|
28
|
+
from nvmath.internal import tensor_wrapper, utils
|
|
29
|
+
from nvmath.internal.package_ifc import StreamHolder
|
|
30
|
+
from nvmath.internal.tensor_ifc import Tensor, TensorHolder
|
|
31
|
+
|
|
32
|
+
SUPPORTED_DTYPE_NAMES = {"float32", "float64", "complex64", "complex128"}
|
|
33
|
+
WrappedOperand: TypeAlias = TensorHolder | Sequence[TensorHolder]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SolverBackend(enum.IntEnum):
|
|
37
|
+
CUSOLVER = 0
|
|
38
|
+
CUBLAS = 1
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def compute_f_strides(shape: tuple[int, ...]) -> tuple[int, ...]:
|
|
42
|
+
"""Column-major (Fortran / LAPACK) strides: first axis is stride 1."""
|
|
43
|
+
strides = [1] * len(shape)
|
|
44
|
+
stride = 1
|
|
45
|
+
for i in range(len(shape)):
|
|
46
|
+
strides[i] = stride
|
|
47
|
+
stride *= shape[i]
|
|
48
|
+
return tuple(strides)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True, slots=True)
|
|
52
|
+
class LHSLayout:
|
|
53
|
+
# cuSOLVER/cuBLAS interpret matrix operands as column-major. An F-order LHS
|
|
54
|
+
# can be used as-is with op=N. A C-order LHS has the same memory layout as
|
|
55
|
+
# the column-major representation of A.T, so solve uses op=T to recover A @ x = b.
|
|
56
|
+
order: Literal["F", "C"]
|
|
57
|
+
lda: int
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass(frozen=True, slots=True)
|
|
61
|
+
class RHSLayout:
|
|
62
|
+
ldb: int
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
66
|
+
class BatchInfo:
|
|
67
|
+
explicitly_batched: bool
|
|
68
|
+
implicitly_batched: bool
|
|
69
|
+
batch_shape: tuple[int, ...] | None
|
|
70
|
+
batch_count: int
|
|
71
|
+
|
|
72
|
+
def __post_init__(self):
|
|
73
|
+
if self.explicitly_batched:
|
|
74
|
+
if self.implicitly_batched:
|
|
75
|
+
raise ValueError("The operand cannot be both explicitly and implicitly batched.")
|
|
76
|
+
if self.batch_shape is not None:
|
|
77
|
+
raise ValueError("The explicitly batched operand cannot have a batch shape.")
|
|
78
|
+
elif self.implicitly_batched:
|
|
79
|
+
if self.batch_shape is None:
|
|
80
|
+
raise ValueError("The implicitly batched operand must have a batch shape.")
|
|
81
|
+
else:
|
|
82
|
+
if self.batch_shape is not None:
|
|
83
|
+
raise ValueError("The non-batched operand cannot have a batch shape.")
|
|
84
|
+
if self.batch_count != 1:
|
|
85
|
+
raise ValueError("The non-batched operand must have a batch count of 1.")
|
|
86
|
+
|
|
87
|
+
def __str__(self) -> str:
|
|
88
|
+
if not self.explicitly_batched and not self.implicitly_batched:
|
|
89
|
+
return "non-batched"
|
|
90
|
+
if self.explicitly_batched:
|
|
91
|
+
return f"explicit batching (batch_count={self.batch_count})"
|
|
92
|
+
return f"implicit batching (batch_shape={self.batch_shape}, batch_count={self.batch_count})"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _is_operand_sequence(operand: WrappedOperand) -> TypeGuard[Sequence[TensorHolder]]:
|
|
96
|
+
return isinstance(operand, Sequence)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_lhs_layout(lhs: WrappedOperand, check_inplace_compatible_strides: bool = True) -> LHSLayout:
|
|
100
|
+
if _is_operand_sequence(lhs):
|
|
101
|
+
unique_strides = {tuple(operand.strides) for operand in lhs}
|
|
102
|
+
if check_inplace_compatible_strides and len(unique_strides) != 1:
|
|
103
|
+
raise ValueError(
|
|
104
|
+
f"When inplace_a is True, the strides of the LHS must be the same for all batches, but got {unique_strides}."
|
|
105
|
+
)
|
|
106
|
+
strides = unique_strides.pop()
|
|
107
|
+
else:
|
|
108
|
+
lhs = cast(TensorHolder, lhs)
|
|
109
|
+
strides = tuple(lhs.strides)
|
|
110
|
+
|
|
111
|
+
# Store the leading dimension for the column-major view seen by GETRF/GETRS.
|
|
112
|
+
if strides[-2] == 1:
|
|
113
|
+
return LHSLayout("F", strides[-1])
|
|
114
|
+
if strides[-1] == 1:
|
|
115
|
+
return LHSLayout("C", strides[-2])
|
|
116
|
+
|
|
117
|
+
if check_inplace_compatible_strides:
|
|
118
|
+
raise ValueError(
|
|
119
|
+
f"When inplace_a is True, the LHS must have either column-major or row-major layout, but got strides {strides}."
|
|
120
|
+
)
|
|
121
|
+
raise AssertionError(f"Internal error: unable to determine LHS layout from strides {strides}.")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def get_rhs_layout(rhs: WrappedOperand, nrhs: int, check_inplace_compatible_strides: bool = True) -> RHSLayout:
|
|
125
|
+
if _is_operand_sequence(rhs):
|
|
126
|
+
unique_strides = {tuple(operand.strides) for operand in rhs}
|
|
127
|
+
if check_inplace_compatible_strides and len(unique_strides) != 1:
|
|
128
|
+
raise ValueError(
|
|
129
|
+
f"When inplace_b is True, the strides of the RHS must be the same for all batches, but got {unique_strides}."
|
|
130
|
+
)
|
|
131
|
+
strides = unique_strides.pop()
|
|
132
|
+
shape = tuple(rhs[0].shape)
|
|
133
|
+
else:
|
|
134
|
+
rhs = cast(TensorHolder, rhs)
|
|
135
|
+
strides = tuple(rhs.strides)
|
|
136
|
+
shape = tuple(rhs.shape)
|
|
137
|
+
|
|
138
|
+
if len(strides) == 1:
|
|
139
|
+
if check_inplace_compatible_strides and strides[-1] != 1:
|
|
140
|
+
raise ValueError(f"When inplace_b is True, vector RHS operands must have unit stride, but got strides {strides}.")
|
|
141
|
+
return RHSLayout(shape[-1])
|
|
142
|
+
|
|
143
|
+
if check_inplace_compatible_strides and strides[-2] != 1:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
f"When inplace_b is True, matrix RHS operands must have column-major layout, but got strides {strides}."
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return RHSLayout(strides[-1] if nrhs > 1 else shape[-2])
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def check_inplace_lhs_storage(lhs: WrappedOperand, batch_info: BatchInfo) -> None:
|
|
152
|
+
if batch_info.explicitly_batched:
|
|
153
|
+
lhs = cast(Sequence[TensorHolder], lhs)
|
|
154
|
+
# Full non-overlap validation is hard for arbitrary views, so
|
|
155
|
+
# cheaply guard the most obvious dangerous explicit-batch case:
|
|
156
|
+
# repeated views of the same matrix.
|
|
157
|
+
data_ptrs = {o.data_ptr for o in lhs}
|
|
158
|
+
if len(data_ptrs) != batch_info.batch_count:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
f"When inplace_a is True, each batch in LHS must not share overlapping memory, "
|
|
161
|
+
f"but only got {len(data_ptrs)} unique data pointers for {batch_info.batch_count} batches."
|
|
162
|
+
)
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
lhs_holder = cast(TensorHolder, lhs)
|
|
166
|
+
if batch_info.implicitly_batched and 0 in lhs_holder.strides[:-2]:
|
|
167
|
+
# Full non-overlap validation is hard for arbitrary strided views,
|
|
168
|
+
# so cheaply guard the most obvious dangerous implicit-batch case:
|
|
169
|
+
# broadcasted batches (for example torch.expand) with zero batch
|
|
170
|
+
# strides, where multiple batch items share one matrix.
|
|
171
|
+
raise ValueError(
|
|
172
|
+
f"When inplace_a is True, each batch in LHS must not share overlapping memory, "
|
|
173
|
+
f"but found the implicitly batched LHS with strides {lhs_holder.strides}."
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def check_inplace_rhs_storage(rhs: WrappedOperand, batch_info: BatchInfo) -> None:
|
|
178
|
+
if batch_info.explicitly_batched:
|
|
179
|
+
rhs = cast(Sequence[TensorHolder], rhs)
|
|
180
|
+
# Full non-overlap validation is hard for arbitrary views, so
|
|
181
|
+
# cheaply guard the most obvious dangerous explicit-batch case:
|
|
182
|
+
# repeated views of the same RHS operand.
|
|
183
|
+
data_ptrs = {o.data_ptr for o in rhs}
|
|
184
|
+
if len(data_ptrs) != batch_info.batch_count:
|
|
185
|
+
raise ValueError(
|
|
186
|
+
f"When inplace_b is True, each batch in RHS must not share overlapping memory, "
|
|
187
|
+
f"but only got {len(data_ptrs)} unique data pointers for {batch_info.batch_count} batches."
|
|
188
|
+
)
|
|
189
|
+
return
|
|
190
|
+
|
|
191
|
+
rhs_holder = cast(TensorHolder, rhs)
|
|
192
|
+
if batch_info.implicitly_batched and 0 in rhs_holder.strides[:-2]:
|
|
193
|
+
# Full non-overlap validation is hard for arbitrary strided views,
|
|
194
|
+
# so cheaply guard the most obvious dangerous implicit-batch case:
|
|
195
|
+
# broadcasted batches (for example torch.expand) with zero batch
|
|
196
|
+
# strides, where multiple batch items share one RHS operand.
|
|
197
|
+
raise ValueError(
|
|
198
|
+
f"When inplace_b is True, each batch in RHS must not share overlapping memory, "
|
|
199
|
+
f"but found the implicitly batched RHS with strides {rhs_holder.strides}."
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def get_single_or_sequence_attr(obj, attribute_name: str, check_consistency: bool = False):
|
|
204
|
+
if isinstance(obj, Sequence):
|
|
205
|
+
result = obj[0].__getattribute__(attribute_name)
|
|
206
|
+
if check_consistency:
|
|
207
|
+
for i, o in enumerate(obj, start=1):
|
|
208
|
+
if get_single_or_sequence_attr(o, attribute_name) != result:
|
|
209
|
+
raise ValueError(
|
|
210
|
+
f"The {attribute_name} of the {i}th object ({o}) in the sequence "
|
|
211
|
+
f"({obj}) is different from the first object ({obj[0]})."
|
|
212
|
+
)
|
|
213
|
+
return result
|
|
214
|
+
else:
|
|
215
|
+
return obj.__getattribute__(attribute_name)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def wrap_solver_operands(operands: Tensor | Sequence[Tensor], check_consistency: bool = True):
|
|
219
|
+
explicitly_batched = isinstance(operands, Sequence)
|
|
220
|
+
if isinstance(operands, Sequence):
|
|
221
|
+
results = tensor_wrapper.wrap_operands(operands) # type: ignore
|
|
222
|
+
if check_consistency:
|
|
223
|
+
# Check the consistency of the operands
|
|
224
|
+
utils.get_operands_dtype(results)
|
|
225
|
+
utils.get_operands_device_id(results)
|
|
226
|
+
shapes = [o.shape for o in results]
|
|
227
|
+
for i, shape in enumerate(shapes, start=1):
|
|
228
|
+
if shape != shapes[0]:
|
|
229
|
+
raise ValueError(
|
|
230
|
+
f"The shape of the {i}th operand ({shape}) is not the same as the first operand ({shapes[0]})."
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
results = tensor_wrapper.wrap_operand(operands) # type: ignore
|
|
234
|
+
return results, explicitly_batched
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def wrap_check_solver_lhs(a: Tensor | Sequence[Tensor], check_inplace_a_layout: bool = False):
|
|
238
|
+
lhs, explicitly_batched = wrap_solver_operands(a, check_consistency=True)
|
|
239
|
+
implicitly_batched = False
|
|
240
|
+
lhs_layout = None
|
|
241
|
+
if explicitly_batched:
|
|
242
|
+
# shape consistency is checked in wrap_solver_operands
|
|
243
|
+
shape = lhs[0].shape
|
|
244
|
+
batch_count = len(lhs)
|
|
245
|
+
n0, n1 = shape
|
|
246
|
+
if n0 != n1:
|
|
247
|
+
raise ValueError(f"For explicitly batched LHS, the shape of each batch must be square, but got {shape}.")
|
|
248
|
+
n = n0
|
|
249
|
+
batch_shape = None
|
|
250
|
+
else:
|
|
251
|
+
shape = lhs.shape
|
|
252
|
+
ndim = len(shape)
|
|
253
|
+
if ndim == 2:
|
|
254
|
+
batch_shape = None
|
|
255
|
+
n0, n1 = shape
|
|
256
|
+
batch_count = 1
|
|
257
|
+
else:
|
|
258
|
+
implicitly_batched = True
|
|
259
|
+
*batch_shape, n0, n1 = shape
|
|
260
|
+
batch_shape = tuple(batch_shape)
|
|
261
|
+
batch_count = math.prod(batch_shape)
|
|
262
|
+
if n0 != n1:
|
|
263
|
+
raise ValueError(f"The last two dimensions of the LHS must be the same, but got {n0} and {n1}.")
|
|
264
|
+
n = n0
|
|
265
|
+
|
|
266
|
+
batch_info = BatchInfo(
|
|
267
|
+
explicitly_batched=explicitly_batched,
|
|
268
|
+
implicitly_batched=implicitly_batched,
|
|
269
|
+
batch_shape=batch_shape,
|
|
270
|
+
batch_count=batch_count,
|
|
271
|
+
)
|
|
272
|
+
if check_inplace_a_layout:
|
|
273
|
+
check_inplace_lhs_storage(lhs, batch_info)
|
|
274
|
+
# CPU inputs are copied to internal GPU buffers, so their layout does not
|
|
275
|
+
# need to satisfy in-place solver requirements.
|
|
276
|
+
if get_single_or_sequence_attr(lhs, "device") == "cuda":
|
|
277
|
+
lhs_layout = get_lhs_layout(lhs)
|
|
278
|
+
|
|
279
|
+
return lhs, batch_info, n, lhs_layout
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def wrap_check_solver_rhs(b: Tensor | Sequence[Tensor], check_inplace_b_layout: bool = False):
|
|
283
|
+
rhs, explicitly_batched = wrap_solver_operands(b, check_consistency=True)
|
|
284
|
+
implicitly_batched = False
|
|
285
|
+
rhs_layout = None
|
|
286
|
+
if explicitly_batched:
|
|
287
|
+
# shape consistency is checked in wrap_solver_operands
|
|
288
|
+
shape = rhs[0].shape
|
|
289
|
+
batch_count = len(rhs)
|
|
290
|
+
ndim = len(shape)
|
|
291
|
+
if ndim == 1:
|
|
292
|
+
n, nrhs = shape[0], 1
|
|
293
|
+
elif ndim == 2:
|
|
294
|
+
n, nrhs = shape
|
|
295
|
+
else:
|
|
296
|
+
raise ValueError(f"For explicitly batched RHS, the shape of each batch must be 1D or 2D, but got {ndim}D.")
|
|
297
|
+
batch_shape = None
|
|
298
|
+
else:
|
|
299
|
+
shape = rhs.shape
|
|
300
|
+
ndim = len(shape)
|
|
301
|
+
if ndim >= 3:
|
|
302
|
+
implicitly_batched = True
|
|
303
|
+
*batch_shape, n, nrhs = shape
|
|
304
|
+
batch_shape = tuple(batch_shape)
|
|
305
|
+
batch_count = math.prod(batch_shape)
|
|
306
|
+
else:
|
|
307
|
+
batch_shape = None
|
|
308
|
+
batch_count = 1
|
|
309
|
+
if ndim == 1:
|
|
310
|
+
n, nrhs = shape[0], 1
|
|
311
|
+
else:
|
|
312
|
+
n, nrhs = shape
|
|
313
|
+
|
|
314
|
+
batch_info = BatchInfo(
|
|
315
|
+
explicitly_batched=explicitly_batched,
|
|
316
|
+
implicitly_batched=implicitly_batched,
|
|
317
|
+
batch_shape=batch_shape,
|
|
318
|
+
batch_count=batch_count,
|
|
319
|
+
)
|
|
320
|
+
if check_inplace_b_layout:
|
|
321
|
+
check_inplace_rhs_storage(rhs, batch_info)
|
|
322
|
+
# CPU inputs are copied to internal GPU buffers, so their layout does not
|
|
323
|
+
# need to satisfy in-place solver requirements.
|
|
324
|
+
if get_single_or_sequence_attr(rhs, "device") == "cuda":
|
|
325
|
+
rhs_layout = get_rhs_layout(rhs, nrhs)
|
|
326
|
+
|
|
327
|
+
return rhs, batch_info, n, nrhs, rhs_layout
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def parse_solver_operands(
|
|
331
|
+
a: Tensor | Sequence[Tensor],
|
|
332
|
+
b: Tensor | Sequence[Tensor],
|
|
333
|
+
check_inplace_a_layout: bool = False,
|
|
334
|
+
check_inplace_b_layout: bool = False,
|
|
335
|
+
):
|
|
336
|
+
lhs, lhs_batch_info, n_lhs, lhs_layout = wrap_check_solver_lhs(a, check_inplace_a_layout=check_inplace_a_layout)
|
|
337
|
+
rhs, rhs_batch_info, n_rhs, nrhs, rhs_layout = wrap_check_solver_rhs(b, check_inplace_b_layout=check_inplace_b_layout)
|
|
338
|
+
if lhs_batch_info.batch_count != rhs_batch_info.batch_count:
|
|
339
|
+
raise ValueError(
|
|
340
|
+
f"The number of batches in the LHS and RHS must be the same, but "
|
|
341
|
+
f"got {lhs_batch_info.batch_count} for the LHS and {rhs_batch_info.batch_count} for the RHS."
|
|
342
|
+
)
|
|
343
|
+
if (
|
|
344
|
+
lhs_batch_info.batch_shape is not None
|
|
345
|
+
and rhs_batch_info.batch_shape is not None
|
|
346
|
+
and lhs_batch_info.batch_shape != rhs_batch_info.batch_shape
|
|
347
|
+
):
|
|
348
|
+
raise ValueError(
|
|
349
|
+
f"For implicitly batched LHS & RHS, the batch shapes must be the same, but "
|
|
350
|
+
f"got {lhs_batch_info.batch_shape} for the LHS and {rhs_batch_info.batch_shape} for the RHS."
|
|
351
|
+
)
|
|
352
|
+
if n_lhs != n_rhs:
|
|
353
|
+
raise ValueError(f"The number of columns in the LHS ({n_lhs}) and RHS ({n_rhs}) must be the same.")
|
|
354
|
+
|
|
355
|
+
# Consistency within LHS or RHS has been checked in wrap_check_solver_lhs/rhs
|
|
356
|
+
# Here we only need to check the consistency between LHS and RHS.
|
|
357
|
+
package_lhs = get_single_or_sequence_attr(lhs, "name")
|
|
358
|
+
device_id_lhs = get_single_or_sequence_attr(lhs, "device_id")
|
|
359
|
+
dtype_name_lhs = get_single_or_sequence_attr(lhs, "dtype")
|
|
360
|
+
|
|
361
|
+
# We have managed to wrap the operands so we can skip checking the package consistency
|
|
362
|
+
package_rhs = get_single_or_sequence_attr(rhs, "name")
|
|
363
|
+
device_id_rhs = get_single_or_sequence_attr(rhs, "device_id")
|
|
364
|
+
dtype_name_rhs = get_single_or_sequence_attr(rhs, "dtype")
|
|
365
|
+
|
|
366
|
+
if package_lhs != package_rhs:
|
|
367
|
+
raise ValueError(f"The package for the LHS ({package_lhs}) and RHS ({package_rhs}) must be the same.")
|
|
368
|
+
if device_id_lhs != device_id_rhs:
|
|
369
|
+
raise ValueError(f"The device id for the LHS ({device_id_lhs}) and RHS ({device_id_rhs}) must be the same.")
|
|
370
|
+
if dtype_name_lhs != dtype_name_rhs:
|
|
371
|
+
raise ValueError(f"The dtype for the LHS ({dtype_name_lhs}) and RHS ({dtype_name_rhs}) must be the same.")
|
|
372
|
+
|
|
373
|
+
return (
|
|
374
|
+
lhs,
|
|
375
|
+
lhs_batch_info,
|
|
376
|
+
rhs,
|
|
377
|
+
rhs_batch_info,
|
|
378
|
+
n_lhs,
|
|
379
|
+
nrhs,
|
|
380
|
+
package_lhs,
|
|
381
|
+
device_id_lhs,
|
|
382
|
+
dtype_name_lhs,
|
|
383
|
+
lhs_layout,
|
|
384
|
+
rhs_layout,
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def copy_operands(
|
|
389
|
+
dst: WrappedOperand,
|
|
390
|
+
src: WrappedOperand,
|
|
391
|
+
stream_holder: StreamHolder,
|
|
392
|
+
):
|
|
393
|
+
if _is_operand_sequence(dst):
|
|
394
|
+
if not _is_operand_sequence(src):
|
|
395
|
+
raise AssertionError("The source must be a sequence if the destination is a sequence.")
|
|
396
|
+
for d, s in zip(dst, src, strict=True):
|
|
397
|
+
d.copy_(s, stream_holder=stream_holder)
|
|
398
|
+
else:
|
|
399
|
+
if _is_operand_sequence(src):
|
|
400
|
+
raise AssertionError("The source must be a single operand if the destination is a single operand.")
|
|
401
|
+
dst = cast(TensorHolder, dst)
|
|
402
|
+
src = cast(TensorHolder, src)
|
|
403
|
+
dst.copy_(src, stream_holder=stream_holder)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def get_operands_ptr_array(
|
|
407
|
+
wrapped_operands: WrappedOperand,
|
|
408
|
+
batch_indices: tuple[tuple[int, ...], ...] | None = None,
|
|
409
|
+
) -> TensorHolder:
|
|
410
|
+
if _is_operand_sequence(wrapped_operands):
|
|
411
|
+
device_ptrs = [o.data_ptr for o in wrapped_operands]
|
|
412
|
+
else:
|
|
413
|
+
wrapped_operands = cast(TensorHolder, wrapped_operands)
|
|
414
|
+
assert batch_indices is not None, "Internal Error."
|
|
415
|
+
starting_ptr = wrapped_operands.data_ptr
|
|
416
|
+
offsets = wrapped_operands.strides[: len(batch_indices[0])] # type: ignore
|
|
417
|
+
device_ptrs = []
|
|
418
|
+
for index in batch_indices:
|
|
419
|
+
device_ptrs.append(
|
|
420
|
+
starting_ptr + wrapped_operands.itemsize * sum(o * i for o, i in zip(offsets, index, strict=True))
|
|
421
|
+
)
|
|
422
|
+
return tensor_wrapper.wrap_operand(np.array(device_ptrs, dtype=np.uint64))
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def update_operands_ptr_array(
|
|
426
|
+
ptr_operand: TensorHolder,
|
|
427
|
+
wrapped_operands: WrappedOperand,
|
|
428
|
+
stream_holder: StreamHolder,
|
|
429
|
+
batch_indices: tuple[tuple[int, ...], ...] | None = None,
|
|
430
|
+
):
|
|
431
|
+
device_ptrs = get_operands_ptr_array(wrapped_operands, batch_indices)
|
|
432
|
+
ptr_operand.copy_(device_ptrs, stream_holder=stream_holder)
|
|
@@ -0,0 +1,144 @@
|
|
|
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 CUBLAS compute types.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"NAMES_TO_DEFAULT_SCALE_TYPE",
|
|
11
|
+
"NAMES_TO_DEFAULT_COMPUTE_TYPE",
|
|
12
|
+
"SUPPORTED_TYPES",
|
|
13
|
+
"COMPUTE_TYPE_TO_DEFAULT_SCALE_TYPE",
|
|
14
|
+
"SCALE_TYPE_TO_DEFAULT_COMPUTE_TYPE",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
from nvmath.bindings import cublas # type: ignore
|
|
18
|
+
from nvmath.internal.typemaps import cudaDataType
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def create_default_scale_type_map():
|
|
22
|
+
"""
|
|
23
|
+
Map the data type name to the corresponding CUDA data type that's appropriate for
|
|
24
|
+
default scale.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
dt = cudaDataType
|
|
28
|
+
|
|
29
|
+
scale_type_map = {}
|
|
30
|
+
# FP4 scale types (https://docs.nvidia.com/cuda/cublas/index.html#id105)
|
|
31
|
+
scale_type_map["float4_e2m1fn_x2", "float4_e2m1fn_x2"] = dt.CUDA_R_32F
|
|
32
|
+
# FP8 scale types
|
|
33
|
+
scale_type_map["float8_e4m3fn", "float8_e5m2"] = dt.CUDA_R_32F
|
|
34
|
+
scale_type_map["float8_e5m2", "float8_e4m3fn"] = dt.CUDA_R_32F
|
|
35
|
+
scale_type_map["float8_e4m3fn", "float8_e4m3fn"] = dt.CUDA_R_32F
|
|
36
|
+
scale_type_map["bfloat16", "bfloat16"] = dt.CUDA_R_32F
|
|
37
|
+
scale_type_map["float16", "float16"] = dt.CUDA_R_32F
|
|
38
|
+
scale_type_map["float32", "float32"] = dt.CUDA_R_32F
|
|
39
|
+
scale_type_map["float64", "float64"] = dt.CUDA_R_64F
|
|
40
|
+
scale_type_map["complex32", "complex32"] = dt.CUDA_C_32F
|
|
41
|
+
scale_type_map["complex64", "complex64"] = dt.CUDA_C_32F
|
|
42
|
+
scale_type_map["complex128", "complex128"] = dt.CUDA_C_64F
|
|
43
|
+
|
|
44
|
+
return scale_type_map
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def create_compute_type_to_scale_type_map(is_complex):
|
|
48
|
+
"""
|
|
49
|
+
Map the compute type to the corresponding CUDA data type that's appropriate for
|
|
50
|
+
default scale.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
dt = cudaDataType
|
|
54
|
+
ct = cublas.ComputeType
|
|
55
|
+
|
|
56
|
+
scale_type_map = {}
|
|
57
|
+
scale_type_map[ct.COMPUTE_16F] = dt.CUDA_R_16F
|
|
58
|
+
scale_type_map[ct.COMPUTE_16F_PEDANTIC] = dt.CUDA_R_16F
|
|
59
|
+
|
|
60
|
+
f32 = dt.CUDA_C_32F if is_complex else dt.CUDA_R_32F
|
|
61
|
+
f64 = dt.CUDA_C_64F if is_complex else dt.CUDA_R_64F
|
|
62
|
+
|
|
63
|
+
scale_type_map[ct.COMPUTE_32F] = f32
|
|
64
|
+
scale_type_map[ct.COMPUTE_32F_PEDANTIC] = f32
|
|
65
|
+
scale_type_map[ct.COMPUTE_32F_FAST_16F] = f32
|
|
66
|
+
scale_type_map[ct.COMPUTE_32F_FAST_16BF] = f32
|
|
67
|
+
scale_type_map[ct.COMPUTE_32F_FAST_TF32] = f32
|
|
68
|
+
scale_type_map[ct.COMPUTE_32F_EMULATED_16BFX9] = f32
|
|
69
|
+
scale_type_map[ct.COMPUTE_64F] = f64
|
|
70
|
+
scale_type_map[ct.COMPUTE_64F_PEDANTIC] = f64
|
|
71
|
+
scale_type_map[ct.COMPUTE_64F_EMULATED_FIXEDPOINT] = f64
|
|
72
|
+
|
|
73
|
+
return scale_type_map
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def create_scale_type_to_compute_type_map():
|
|
77
|
+
"""
|
|
78
|
+
Map the scale type to the corresponding compute type that's an appropriate default.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
dt = cudaDataType
|
|
82
|
+
ct = cublas.ComputeType
|
|
83
|
+
|
|
84
|
+
compute_type_map = {}
|
|
85
|
+
compute_type_map[dt.CUDA_R_16F] = ct.COMPUTE_16F
|
|
86
|
+
compute_type_map[dt.CUDA_R_16BF] = ct.COMPUTE_32F
|
|
87
|
+
compute_type_map[dt.CUDA_R_32F] = ct.COMPUTE_32F
|
|
88
|
+
compute_type_map[dt.CUDA_C_32F] = ct.COMPUTE_32F
|
|
89
|
+
compute_type_map[dt.CUDA_R_64F] = ct.COMPUTE_64F
|
|
90
|
+
compute_type_map[dt.CUDA_C_64F] = ct.COMPUTE_64F
|
|
91
|
+
return compute_type_map
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def create_compute_type_map():
|
|
95
|
+
"""
|
|
96
|
+
Map the data type name to the corresponding CUDA data type that's appropriate for
|
|
97
|
+
default compute type.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
ct = cublas.ComputeType
|
|
101
|
+
|
|
102
|
+
compute_type_map = {}
|
|
103
|
+
# FP4 compute types (https://docs.nvidia.com/cuda/cublas/index.html#id105)
|
|
104
|
+
compute_type_map["float4_e2m1fn_x2", "float4_e2m1fn_x2"] = ct.COMPUTE_32F
|
|
105
|
+
# FP8 compute types
|
|
106
|
+
compute_type_map["float8_e4m3fn", "float8_e5m2"] = ct.COMPUTE_32F
|
|
107
|
+
compute_type_map["float8_e5m2", "float8_e4m3fn"] = ct.COMPUTE_32F
|
|
108
|
+
compute_type_map["float8_e4m3fn", "float8_e4m3fn"] = ct.COMPUTE_32F
|
|
109
|
+
compute_type_map["bfloat16", "bfloat16"] = ct.COMPUTE_32F
|
|
110
|
+
compute_type_map["float16", "float16"] = ct.COMPUTE_32F
|
|
111
|
+
compute_type_map["float32", "float32"] = ct.COMPUTE_32F
|
|
112
|
+
compute_type_map["float64", "float64"] = ct.COMPUTE_64F
|
|
113
|
+
compute_type_map["complex32", "complex32"] = ct.COMPUTE_32F
|
|
114
|
+
compute_type_map["complex64", "complex64"] = ct.COMPUTE_32F
|
|
115
|
+
compute_type_map["complex128", "complex128"] = ct.COMPUTE_64F
|
|
116
|
+
|
|
117
|
+
return compute_type_map
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
CUBLAS_COMPUTE_TYPE_TO_NAME = {
|
|
121
|
+
cublas.ComputeType.COMPUTE_32F: ("float32", "complex64"),
|
|
122
|
+
cublas.ComputeType.COMPUTE_64F: ("float64", "complex128"),
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
NAMES_TO_DEFAULT_SCALE_TYPE = create_default_scale_type_map()
|
|
126
|
+
NAMES_TO_DEFAULT_COMPUTE_TYPE = create_compute_type_map()
|
|
127
|
+
COMPUTE_TYPE_TO_DEFAULT_SCALE_TYPE = {
|
|
128
|
+
"real": create_compute_type_to_scale_type_map(is_complex=False),
|
|
129
|
+
"complex": create_compute_type_to_scale_type_map(is_complex=True),
|
|
130
|
+
}
|
|
131
|
+
SCALE_TYPE_TO_DEFAULT_COMPUTE_TYPE = create_scale_type_to_compute_type_map()
|
|
132
|
+
|
|
133
|
+
SUPPORTED_TYPES = [
|
|
134
|
+
"float4_e2m1fn_x2", # FP4 (supported on SM 10.0+)
|
|
135
|
+
"float8_e4m3fn",
|
|
136
|
+
"float8_e5m2",
|
|
137
|
+
"bfloat16",
|
|
138
|
+
"float16",
|
|
139
|
+
"float32",
|
|
140
|
+
"float64",
|
|
141
|
+
"complex32",
|
|
142
|
+
"complex64",
|
|
143
|
+
"complex128",
|
|
144
|
+
]
|