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,734 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Matrix multiplication function selection and matching for BLAS operations.
|
|
7
|
+
|
|
8
|
+
This module provides functionality to select and configure the appropriate BLAS matrix
|
|
9
|
+
multiplication functions based on matrix qualifiers, batch traits, and execution context.
|
|
10
|
+
It supports both CPU (NVPL) and GPU (cuBLAS) backends and handles various matrix types
|
|
11
|
+
including general, symmetric, hermitian, triangular, and diagonal matrices.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import typing
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
import nvmath.bindings.cublas as cublas
|
|
19
|
+
from nvmath._internal.templates import ExecutionCPU, ExecutionCUDA
|
|
20
|
+
from nvmath._internal.utils import LoggerLike
|
|
21
|
+
from nvmath.internal import tensor_wrapper, typemaps, utils
|
|
22
|
+
from nvmath.linalg._internal.batch import BatchTraits
|
|
23
|
+
from nvmath.linalg._internal.layout import BLASMMTraitsView
|
|
24
|
+
|
|
25
|
+
from .qualifiers import (
|
|
26
|
+
DiagonalMatrixQualifier,
|
|
27
|
+
GeneralMatrixQualifier,
|
|
28
|
+
HermitianMatrixQualifier,
|
|
29
|
+
MatrixQualifier,
|
|
30
|
+
SymmetricMatrixQualifier,
|
|
31
|
+
TriangularMatrixQualifier,
|
|
32
|
+
)
|
|
33
|
+
from .wrap import (
|
|
34
|
+
cublas_enum_mapper,
|
|
35
|
+
cublas_mm_function,
|
|
36
|
+
get_address_zeroth_element,
|
|
37
|
+
get_value_zeroth_element,
|
|
38
|
+
nvpl_enum_mapper,
|
|
39
|
+
nvpl_mm_function,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
"""A matmul function returned by this module."""
|
|
43
|
+
WrappedMMFunction: typing.TypeAlias = typing.Callable[
|
|
44
|
+
[
|
|
45
|
+
tensor_wrapper.TensorHolder,
|
|
46
|
+
tensor_wrapper.TensorHolder,
|
|
47
|
+
tensor_wrapper.TensorHolder,
|
|
48
|
+
np.ndarray,
|
|
49
|
+
np.ndarray,
|
|
50
|
+
utils.StreamHolder | None,
|
|
51
|
+
],
|
|
52
|
+
None,
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
"""A function which returns a BLAS implementation's matching matmul function."""
|
|
56
|
+
MMFunctionGetter: typing.TypeAlias = typing.Callable[
|
|
57
|
+
[
|
|
58
|
+
ExecutionCUDA | ExecutionCPU,
|
|
59
|
+
typemaps.cudaDataType,
|
|
60
|
+
str,
|
|
61
|
+
LoggerLike,
|
|
62
|
+
typing.Literal["", "stride", "group"],
|
|
63
|
+
],
|
|
64
|
+
typing.Callable,
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def select_blas_mm_function(
|
|
69
|
+
batch_traits: tuple[BatchTraits, BatchTraits, BatchTraits],
|
|
70
|
+
mm_traits: BLASMMTraitsView,
|
|
71
|
+
qualifiers: MatrixQualifier,
|
|
72
|
+
logger: LoggerLike,
|
|
73
|
+
execution: ExecutionCUDA | ExecutionCPU,
|
|
74
|
+
) -> tuple[WrappedMMFunction, str]:
|
|
75
|
+
"""Return a matrix multiplication function which matches the provided arguments."""
|
|
76
|
+
|
|
77
|
+
# At this level, we only select the appropriate library
|
|
78
|
+
match execution:
|
|
79
|
+
case ExecutionCPU():
|
|
80
|
+
mm_function_getter = nvpl_mm_function
|
|
81
|
+
mm_enum_mapper = nvpl_enum_mapper
|
|
82
|
+
# NOTE: the BLAS APIs take values for real alpha/beta, pointers for complex
|
|
83
|
+
if mm_traits.a_layout_traits.dtype.name.startswith("CUDA_C"):
|
|
84
|
+
mm_alpha_beta_picker = get_address_zeroth_element
|
|
85
|
+
else:
|
|
86
|
+
mm_alpha_beta_picker = get_value_zeroth_element
|
|
87
|
+
case ExecutionCUDA():
|
|
88
|
+
mm_function_getter = cublas_mm_function
|
|
89
|
+
mm_enum_mapper = cublas_enum_mapper
|
|
90
|
+
mm_alpha_beta_picker = get_address_zeroth_element
|
|
91
|
+
case _:
|
|
92
|
+
raise ValueError("Only ExectionCUDA and ExecutionCPU are supported.")
|
|
93
|
+
|
|
94
|
+
return _select_blas_mm_function_from_qualifiers(
|
|
95
|
+
batch_traits,
|
|
96
|
+
mm_traits,
|
|
97
|
+
qualifiers,
|
|
98
|
+
logger,
|
|
99
|
+
execution,
|
|
100
|
+
mm_function_getter,
|
|
101
|
+
mm_enum_mapper,
|
|
102
|
+
mm_alpha_beta_picker,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _select_blas_mm_function_from_qualifiers(
|
|
107
|
+
batch_traits: tuple[BatchTraits, BatchTraits, BatchTraits],
|
|
108
|
+
mm_traits: BLASMMTraitsView,
|
|
109
|
+
qualifiers: MatrixQualifier,
|
|
110
|
+
logger: LoggerLike,
|
|
111
|
+
execution: ExecutionCUDA | ExecutionCPU,
|
|
112
|
+
mm_function_getter: MMFunctionGetter,
|
|
113
|
+
mm_enum_mapper: typing.Callable,
|
|
114
|
+
mm_alpha_beta_picker: typing.Callable,
|
|
115
|
+
) -> tuple[WrappedMMFunction, str]:
|
|
116
|
+
"""Match and wrap a matrix multiplication function based on the provided arguments."""
|
|
117
|
+
# NOTE: The parameters of this function are only the operands that will be resettable by
|
|
118
|
+
# reset_operands(); the rest of the parameters should be unchanged by reset_operands.
|
|
119
|
+
# Therefore we can amortize the cost of those bits.
|
|
120
|
+
batchCount = max(b.count for b in batch_traits)
|
|
121
|
+
if batchCount >= 0 and GeneralMatrixQualifier.is_valid(qualifiers):
|
|
122
|
+
operationA = mm_traits.a_layout_traits.operation
|
|
123
|
+
operationB = mm_traits.b_layout_traits.operation
|
|
124
|
+
m, n, k = mm_traits.M, mm_traits.N, mm_traits.K
|
|
125
|
+
lda, ldb, ldc = mm_traits.a_layout_traits.ld, mm_traits.b_layout_traits.ld, mm_traits.c_layout_traits.ld
|
|
126
|
+
assert mm_traits.c_layout_traits.operation == cublas.Operation.N
|
|
127
|
+
strideA, strideB, strideC = (t.stride for t in batch_traits)
|
|
128
|
+
|
|
129
|
+
if mm_traits.is_swapped_AB:
|
|
130
|
+
strideA, strideB = strideB, strideA
|
|
131
|
+
|
|
132
|
+
operationA = mm_enum_mapper(operationA)
|
|
133
|
+
operationB = mm_enum_mapper(operationB)
|
|
134
|
+
|
|
135
|
+
func = mm_function_getter(
|
|
136
|
+
execution,
|
|
137
|
+
mm_traits.a_layout_traits.dtype,
|
|
138
|
+
GeneralMatrixQualifier.abbreviation,
|
|
139
|
+
logger,
|
|
140
|
+
"stride" if batchCount > 1 else "",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def wrapped(
|
|
144
|
+
A: tensor_wrapper.TensorHolder,
|
|
145
|
+
B: tensor_wrapper.TensorHolder,
|
|
146
|
+
C: tensor_wrapper.TensorHolder,
|
|
147
|
+
alpha: np.ndarray,
|
|
148
|
+
beta: np.ndarray,
|
|
149
|
+
stream_holder: utils.StreamHolder | None,
|
|
150
|
+
) -> None:
|
|
151
|
+
if mm_traits.is_swapped_AB:
|
|
152
|
+
A, B = B, A
|
|
153
|
+
logger.debug(
|
|
154
|
+
"Calling %s(operationA=%s, operationB=%s, m=%d, n=%d, k=%d, alpha=%s, lda=%d, strideA=%d, "
|
|
155
|
+
"ldb=%d, strideB=%d, beta=%s, ldc=%d, strideC=%d, batchCount=%d)",
|
|
156
|
+
func.__name__,
|
|
157
|
+
operationA,
|
|
158
|
+
operationB,
|
|
159
|
+
m,
|
|
160
|
+
n,
|
|
161
|
+
k,
|
|
162
|
+
alpha[0],
|
|
163
|
+
lda,
|
|
164
|
+
strideA,
|
|
165
|
+
ldb,
|
|
166
|
+
strideB,
|
|
167
|
+
beta[0],
|
|
168
|
+
ldc,
|
|
169
|
+
strideC,
|
|
170
|
+
batchCount,
|
|
171
|
+
)
|
|
172
|
+
if batchCount > 1:
|
|
173
|
+
func(
|
|
174
|
+
operationA,
|
|
175
|
+
operationB,
|
|
176
|
+
m,
|
|
177
|
+
n,
|
|
178
|
+
k,
|
|
179
|
+
mm_alpha_beta_picker(alpha),
|
|
180
|
+
A.data_ptr,
|
|
181
|
+
lda,
|
|
182
|
+
strideA,
|
|
183
|
+
B.data_ptr,
|
|
184
|
+
ldb,
|
|
185
|
+
strideB,
|
|
186
|
+
mm_alpha_beta_picker(beta),
|
|
187
|
+
C.data_ptr,
|
|
188
|
+
ldc,
|
|
189
|
+
strideC,
|
|
190
|
+
batchCount,
|
|
191
|
+
stream_holder=stream_holder,
|
|
192
|
+
)
|
|
193
|
+
else:
|
|
194
|
+
func(
|
|
195
|
+
operationA,
|
|
196
|
+
operationB,
|
|
197
|
+
m,
|
|
198
|
+
n,
|
|
199
|
+
k,
|
|
200
|
+
mm_alpha_beta_picker(alpha),
|
|
201
|
+
A.data_ptr,
|
|
202
|
+
lda,
|
|
203
|
+
B.data_ptr,
|
|
204
|
+
ldb,
|
|
205
|
+
mm_alpha_beta_picker(beta),
|
|
206
|
+
C.data_ptr,
|
|
207
|
+
ldc,
|
|
208
|
+
stream_holder=stream_holder,
|
|
209
|
+
)
|
|
210
|
+
elif (
|
|
211
|
+
batchCount >= 0
|
|
212
|
+
and GeneralMatrixQualifier.is_valid(qualifiers[2])
|
|
213
|
+
and (
|
|
214
|
+
(
|
|
215
|
+
(HermitianMatrixQualifier.is_valid(qualifiers[0]) or SymmetricMatrixQualifier.is_valid(qualifiers[0]))
|
|
216
|
+
and GeneralMatrixQualifier.is_valid(qualifiers[1])
|
|
217
|
+
)
|
|
218
|
+
or (
|
|
219
|
+
(HermitianMatrixQualifier.is_valid(qualifiers[1]) or SymmetricMatrixQualifier.is_valid(qualifiers[1]))
|
|
220
|
+
and GeneralMatrixQualifier.is_valid(qualifiers[0])
|
|
221
|
+
)
|
|
222
|
+
)
|
|
223
|
+
):
|
|
224
|
+
if HermitianMatrixQualifier.is_valid(qualifiers[0]) or SymmetricMatrixQualifier.is_valid(qualifiers[0]):
|
|
225
|
+
qualifierS = qualifiers[0]
|
|
226
|
+
# qualifierG = qualifiers[1]
|
|
227
|
+
# qualifierC = qualifiers[2]
|
|
228
|
+
traitsS = mm_traits.a_layout_traits
|
|
229
|
+
traitsG = mm_traits.b_layout_traits
|
|
230
|
+
traitsC = mm_traits.c_layout_traits
|
|
231
|
+
strideS = batch_traits[0].stride
|
|
232
|
+
strideG = batch_traits[1].stride
|
|
233
|
+
strideC = batch_traits[2].stride
|
|
234
|
+
is_left_side_symmetric = True
|
|
235
|
+
# Parameter A must always be the symmetric matrix, so if the user provided a
|
|
236
|
+
# SymmetricMatrixQualifier as qualifiers[1], we must move the corresponding
|
|
237
|
+
# matrix to the A input in the BLAS API.
|
|
238
|
+
swapABinputs = False
|
|
239
|
+
elif HermitianMatrixQualifier.is_valid(qualifiers[1]) or SymmetricMatrixQualifier.is_valid(qualifiers[1]):
|
|
240
|
+
# qualifierG = qualifiers[0]
|
|
241
|
+
qualifierS = qualifiers[1]
|
|
242
|
+
# qualifierC = qualifiers[2]
|
|
243
|
+
traitsS = mm_traits.b_layout_traits
|
|
244
|
+
traitsG = mm_traits.a_layout_traits
|
|
245
|
+
traitsC = mm_traits.c_layout_traits
|
|
246
|
+
strideS = batch_traits[1].stride
|
|
247
|
+
strideG = batch_traits[0].stride
|
|
248
|
+
strideC = batch_traits[2].stride
|
|
249
|
+
is_left_side_symmetric = False
|
|
250
|
+
swapABinputs = True
|
|
251
|
+
else:
|
|
252
|
+
raise ValueError("Internal Error: At least one must be a HermitianMatrixQualifier | SymmetricMatrixQualifier!")
|
|
253
|
+
|
|
254
|
+
if mm_traits.is_swapped_AB:
|
|
255
|
+
traitsS, traitsG = traitsG, traitsS
|
|
256
|
+
is_left_side_symmetric = not is_left_side_symmetric
|
|
257
|
+
|
|
258
|
+
func = mm_function_getter(
|
|
259
|
+
execution,
|
|
260
|
+
traitsS.dtype,
|
|
261
|
+
qualifierS["abbreviation"],
|
|
262
|
+
logger,
|
|
263
|
+
"stride" if batchCount > 1 else "",
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if traitsG.operation != cublas.Operation.N or traitsC.operation != cublas.Operation.N:
|
|
267
|
+
raise ValueError(
|
|
268
|
+
f"Operations on the non-hermitian/non-symmetric operands B,C are not supported for {func.__name__}"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if traitsS.operation == cublas.Operation.C and SymmetricMatrixQualifier.is_valid(qualifierS):
|
|
272
|
+
raise ValueError(f"Conjugate-Transpose on operand A is not supported for {func.__name__}")
|
|
273
|
+
|
|
274
|
+
if traitsS.operation == cublas.Operation.T and HermitianMatrixQualifier.is_valid(qualifierS):
|
|
275
|
+
raise ValueError(f"Transpose on operand A is not supported for {func.__name__}")
|
|
276
|
+
|
|
277
|
+
side = cublas.SideMode.LEFT if is_left_side_symmetric else cublas.SideMode.RIGHT
|
|
278
|
+
uplo = cublas.FillMode.LOWER if traitsS.is_lower else cublas.FillMode.UPPER
|
|
279
|
+
m, n = mm_traits.M, mm_traits.N
|
|
280
|
+
lda, ldb, ldc = traitsS.ld, traitsG.ld, traitsC.ld
|
|
281
|
+
|
|
282
|
+
side = mm_enum_mapper(side)
|
|
283
|
+
uplo = mm_enum_mapper(uplo)
|
|
284
|
+
|
|
285
|
+
def wrapped(
|
|
286
|
+
A: tensor_wrapper.TensorHolder,
|
|
287
|
+
B: tensor_wrapper.TensorHolder,
|
|
288
|
+
C: tensor_wrapper.TensorHolder,
|
|
289
|
+
alpha: np.ndarray,
|
|
290
|
+
beta: np.ndarray,
|
|
291
|
+
stream_holder: utils.StreamHolder | None,
|
|
292
|
+
) -> None:
|
|
293
|
+
if swapABinputs:
|
|
294
|
+
A, B = B, A
|
|
295
|
+
logger.debug(
|
|
296
|
+
"Calling %s(side=%s, uplo=%s, m=%d, n=%d, alpha=%s, lda=%d, strideA=%d, "
|
|
297
|
+
"ldb=%d, strideB=%d, beta=%s, ldc=%d, strideC=%d, batchCount=%d)",
|
|
298
|
+
func.__name__,
|
|
299
|
+
side,
|
|
300
|
+
uplo,
|
|
301
|
+
m,
|
|
302
|
+
n,
|
|
303
|
+
alpha[0],
|
|
304
|
+
lda,
|
|
305
|
+
strideS,
|
|
306
|
+
ldb,
|
|
307
|
+
strideG,
|
|
308
|
+
beta[0],
|
|
309
|
+
ldc,
|
|
310
|
+
strideC,
|
|
311
|
+
batchCount,
|
|
312
|
+
)
|
|
313
|
+
if batchCount > 1:
|
|
314
|
+
func(
|
|
315
|
+
side,
|
|
316
|
+
uplo,
|
|
317
|
+
m,
|
|
318
|
+
n,
|
|
319
|
+
mm_alpha_beta_picker(alpha),
|
|
320
|
+
A.data_ptr,
|
|
321
|
+
lda,
|
|
322
|
+
strideS,
|
|
323
|
+
B.data_ptr,
|
|
324
|
+
ldb,
|
|
325
|
+
strideG,
|
|
326
|
+
mm_alpha_beta_picker(beta),
|
|
327
|
+
C.data_ptr,
|
|
328
|
+
ldc,
|
|
329
|
+
strideC,
|
|
330
|
+
batchCount,
|
|
331
|
+
stream_holder=stream_holder,
|
|
332
|
+
)
|
|
333
|
+
else:
|
|
334
|
+
func(
|
|
335
|
+
side,
|
|
336
|
+
uplo,
|
|
337
|
+
m,
|
|
338
|
+
n,
|
|
339
|
+
mm_alpha_beta_picker(alpha),
|
|
340
|
+
A.data_ptr,
|
|
341
|
+
lda,
|
|
342
|
+
B.data_ptr,
|
|
343
|
+
ldb,
|
|
344
|
+
mm_alpha_beta_picker(beta),
|
|
345
|
+
C.data_ptr,
|
|
346
|
+
ldc,
|
|
347
|
+
stream_holder=stream_holder,
|
|
348
|
+
)
|
|
349
|
+
elif (
|
|
350
|
+
batchCount >= 0
|
|
351
|
+
and GeneralMatrixQualifier.is_valid(qualifiers[2])
|
|
352
|
+
and (
|
|
353
|
+
(TriangularMatrixQualifier.is_valid(qualifiers[0]) and GeneralMatrixQualifier.is_valid(qualifiers[1]))
|
|
354
|
+
or (TriangularMatrixQualifier.is_valid(qualifiers[1]) and GeneralMatrixQualifier.is_valid(qualifiers[0]))
|
|
355
|
+
)
|
|
356
|
+
):
|
|
357
|
+
func = mm_function_getter(
|
|
358
|
+
execution,
|
|
359
|
+
mm_traits.a_layout_traits.dtype,
|
|
360
|
+
TriangularMatrixQualifier.abbreviation,
|
|
361
|
+
logger,
|
|
362
|
+
"stride" if batchCount > 1 else "",
|
|
363
|
+
)
|
|
364
|
+
if TriangularMatrixQualifier.is_valid(qualifiers[0]):
|
|
365
|
+
qualifierT = qualifiers[0]
|
|
366
|
+
# qualifierG = qualifiers[1]
|
|
367
|
+
# qualifierC = qualifiers[2]
|
|
368
|
+
traitsT = mm_traits.a_layout_traits
|
|
369
|
+
traitsG = mm_traits.b_layout_traits
|
|
370
|
+
traitsC = mm_traits.c_layout_traits
|
|
371
|
+
strideT = batch_traits[0].stride
|
|
372
|
+
strideG = batch_traits[1].stride
|
|
373
|
+
strideC = batch_traits[2].stride
|
|
374
|
+
is_left_side_triangle = True
|
|
375
|
+
# Parameter A must always be the triangular matrix, so if the user provided a
|
|
376
|
+
# TriangularMatrixQualifier as qualifiers[1], we must move the corresponding
|
|
377
|
+
# matrix to the A input in the BLAS API.
|
|
378
|
+
swapABinputs = False
|
|
379
|
+
elif TriangularMatrixQualifier.is_valid(qualifiers[1]):
|
|
380
|
+
# qualifierG = qualifiers[0]
|
|
381
|
+
qualifierT = qualifiers[1]
|
|
382
|
+
# qualifierC = qualifiers[2]
|
|
383
|
+
traitsT = mm_traits.b_layout_traits
|
|
384
|
+
traitsG = mm_traits.a_layout_traits
|
|
385
|
+
traitsC = mm_traits.c_layout_traits
|
|
386
|
+
strideT = batch_traits[1].stride
|
|
387
|
+
strideG = batch_traits[0].stride
|
|
388
|
+
strideC = batch_traits[2].stride
|
|
389
|
+
is_left_side_triangle = False
|
|
390
|
+
swapABinputs = True
|
|
391
|
+
else:
|
|
392
|
+
raise ValueError("Internal Error: At least one must be a TriangularMatrixQualifier!")
|
|
393
|
+
|
|
394
|
+
if mm_traits.is_swapped_AB:
|
|
395
|
+
traitsT, traitsG = traitsG, traitsT
|
|
396
|
+
is_left_side_triangle = not is_left_side_triangle
|
|
397
|
+
|
|
398
|
+
if traitsG.operation != cublas.Operation.N or traitsC.operation != cublas.Operation.N:
|
|
399
|
+
raise ValueError(f"Operations on the non-triangular operands B,C are not supported for {func.__name__}")
|
|
400
|
+
|
|
401
|
+
side = cublas.SideMode.LEFT if is_left_side_triangle else cublas.SideMode.RIGHT
|
|
402
|
+
uplo = cublas.FillMode.LOWER if traitsT.is_lower else cublas.FillMode.UPPER
|
|
403
|
+
operation = traitsT.operation
|
|
404
|
+
diag = qualifierT["diag"]
|
|
405
|
+
m, n = mm_traits.M, mm_traits.N
|
|
406
|
+
lda, ldb, ldc = traitsT.ld, traitsG.ld, traitsC.ld
|
|
407
|
+
|
|
408
|
+
if (
|
|
409
|
+
mm_traits.a_layout_traits.dtype == typemaps.cudaDataType.CUDA_C_64F
|
|
410
|
+
and n >= 256
|
|
411
|
+
and m == 1
|
|
412
|
+
and side == cublas.SideMode.RIGHT
|
|
413
|
+
):
|
|
414
|
+
raise ValueError("This configuration is unsupported for CTK <13.")
|
|
415
|
+
|
|
416
|
+
side = mm_enum_mapper(side)
|
|
417
|
+
uplo = mm_enum_mapper(uplo)
|
|
418
|
+
operation = mm_enum_mapper(operation)
|
|
419
|
+
diag = mm_enum_mapper(diag)
|
|
420
|
+
|
|
421
|
+
def wrapped(
|
|
422
|
+
A: tensor_wrapper.TensorHolder,
|
|
423
|
+
B: tensor_wrapper.TensorHolder,
|
|
424
|
+
C: tensor_wrapper.TensorHolder,
|
|
425
|
+
alpha: np.ndarray,
|
|
426
|
+
beta: np.ndarray,
|
|
427
|
+
stream_holder: utils.StreamHolder | None,
|
|
428
|
+
) -> None:
|
|
429
|
+
if swapABinputs:
|
|
430
|
+
A, B = B, A
|
|
431
|
+
logger.debug(
|
|
432
|
+
"Calling %s(side=%s, uplo=%s, operation=%s, diag=%s, m=%d, n=%d, alpha=%s, lda=%d, strideA=%d, "
|
|
433
|
+
"ldb=%d, strideB=%d, ldc=%d, strideC=%d, batchCount=%d)",
|
|
434
|
+
func.__name__,
|
|
435
|
+
side,
|
|
436
|
+
uplo,
|
|
437
|
+
operation,
|
|
438
|
+
diag,
|
|
439
|
+
m,
|
|
440
|
+
n,
|
|
441
|
+
alpha[0],
|
|
442
|
+
lda,
|
|
443
|
+
strideT,
|
|
444
|
+
ldb,
|
|
445
|
+
strideG,
|
|
446
|
+
ldc,
|
|
447
|
+
strideC,
|
|
448
|
+
batchCount,
|
|
449
|
+
)
|
|
450
|
+
if batchCount > 1:
|
|
451
|
+
func(
|
|
452
|
+
side,
|
|
453
|
+
uplo,
|
|
454
|
+
operation,
|
|
455
|
+
diag,
|
|
456
|
+
m,
|
|
457
|
+
n,
|
|
458
|
+
mm_alpha_beta_picker(alpha),
|
|
459
|
+
A.data_ptr,
|
|
460
|
+
lda,
|
|
461
|
+
strideT,
|
|
462
|
+
B.data_ptr,
|
|
463
|
+
ldb,
|
|
464
|
+
strideG,
|
|
465
|
+
C.data_ptr,
|
|
466
|
+
ldc,
|
|
467
|
+
strideC,
|
|
468
|
+
batchCount,
|
|
469
|
+
stream_holder=stream_holder,
|
|
470
|
+
)
|
|
471
|
+
else:
|
|
472
|
+
func(
|
|
473
|
+
side,
|
|
474
|
+
uplo,
|
|
475
|
+
operation,
|
|
476
|
+
diag,
|
|
477
|
+
m,
|
|
478
|
+
n,
|
|
479
|
+
mm_alpha_beta_picker(alpha),
|
|
480
|
+
A.data_ptr,
|
|
481
|
+
lda,
|
|
482
|
+
B.data_ptr,
|
|
483
|
+
ldb,
|
|
484
|
+
C.data_ptr,
|
|
485
|
+
ldc,
|
|
486
|
+
stream_holder=stream_holder,
|
|
487
|
+
)
|
|
488
|
+
elif (
|
|
489
|
+
batchCount >= 0
|
|
490
|
+
and GeneralMatrixQualifier.is_valid(qualifiers[2])
|
|
491
|
+
and (
|
|
492
|
+
(DiagonalMatrixQualifier.is_valid(qualifiers[0]) and GeneralMatrixQualifier.is_valid(qualifiers[1]))
|
|
493
|
+
or (DiagonalMatrixQualifier.is_valid(qualifiers[1]) and GeneralMatrixQualifier.is_valid(qualifiers[0]))
|
|
494
|
+
)
|
|
495
|
+
):
|
|
496
|
+
func = mm_function_getter(
|
|
497
|
+
execution,
|
|
498
|
+
mm_traits.a_layout_traits.dtype,
|
|
499
|
+
DiagonalMatrixQualifier.abbreviation,
|
|
500
|
+
logger,
|
|
501
|
+
"stride" if batchCount > 1 else "",
|
|
502
|
+
)
|
|
503
|
+
if DiagonalMatrixQualifier.is_valid(qualifiers[0]):
|
|
504
|
+
qualifierX = qualifiers[0]
|
|
505
|
+
# qualifierG = qualifiers[1]
|
|
506
|
+
# qualifierC = qualifiers[2]
|
|
507
|
+
traitsX = mm_traits.a_layout_traits
|
|
508
|
+
traitsG = mm_traits.b_layout_traits
|
|
509
|
+
traitsC = mm_traits.c_layout_traits
|
|
510
|
+
strideX = batch_traits[0].stride
|
|
511
|
+
strideG = batch_traits[1].stride
|
|
512
|
+
strideC = batch_traits[2].stride
|
|
513
|
+
is_left_side_diagonal = True
|
|
514
|
+
# Parameter X must always be the diagonal matrix, so if the user provided a
|
|
515
|
+
# DiagonalMatrixQualifier as qualifiers[0], we must move the corresponding
|
|
516
|
+
# matrix to the X input in the BLAS API.
|
|
517
|
+
swapABinputs = True
|
|
518
|
+
elif DiagonalMatrixQualifier.is_valid(qualifiers[1]):
|
|
519
|
+
# qualifierG = qualifiers[0]
|
|
520
|
+
qualifierX = qualifiers[1]
|
|
521
|
+
# qualifierC = qualifiers[2]
|
|
522
|
+
traitsX = mm_traits.b_layout_traits
|
|
523
|
+
traitsG = mm_traits.a_layout_traits
|
|
524
|
+
traitsC = mm_traits.c_layout_traits
|
|
525
|
+
strideX = batch_traits[1].stride
|
|
526
|
+
strideG = batch_traits[0].stride
|
|
527
|
+
strideC = batch_traits[2].stride
|
|
528
|
+
is_left_side_diagonal = False
|
|
529
|
+
swapABinputs = False
|
|
530
|
+
else:
|
|
531
|
+
raise ValueError("Internal Error: At least one must be a DiagonalMatrixQualifier!")
|
|
532
|
+
|
|
533
|
+
if mm_traits.is_swapped_AB:
|
|
534
|
+
traitsX, traitsG = traitsG, traitsX
|
|
535
|
+
is_left_side_diagonal = not is_left_side_diagonal
|
|
536
|
+
|
|
537
|
+
if traitsG.operation != cublas.Operation.N or traitsC.operation != cublas.Operation.N:
|
|
538
|
+
raise ValueError(f"Operations on the non-diagonal operands A,C are not supported for {func.__name__}")
|
|
539
|
+
|
|
540
|
+
# Operation.T is allowed for diagonal matrix because the transpose is a no-op
|
|
541
|
+
if traitsX.operation == cublas.Operation.C:
|
|
542
|
+
raise ValueError(f"Conjugate-Transpose on operand X is not supported for {func.__name__}")
|
|
543
|
+
|
|
544
|
+
side = cublas.SideMode.LEFT if is_left_side_diagonal else cublas.SideMode.RIGHT
|
|
545
|
+
m, n = mm_traits.M, mm_traits.N
|
|
546
|
+
lda, ldc = traitsG.ld, traitsC.ld
|
|
547
|
+
incx = qualifierX["incx"] * max(traitsX.strides)
|
|
548
|
+
|
|
549
|
+
side = mm_enum_mapper(side)
|
|
550
|
+
|
|
551
|
+
def wrapped(
|
|
552
|
+
A: tensor_wrapper.TensorHolder,
|
|
553
|
+
B: tensor_wrapper.TensorHolder,
|
|
554
|
+
C: tensor_wrapper.TensorHolder,
|
|
555
|
+
alpha: np.ndarray,
|
|
556
|
+
beta: np.ndarray,
|
|
557
|
+
stream_holder: utils.StreamHolder | None,
|
|
558
|
+
) -> None:
|
|
559
|
+
if swapABinputs:
|
|
560
|
+
A, B = B, A
|
|
561
|
+
logger.debug(
|
|
562
|
+
"Calling %s(side=%s, m=%d, n=%d, lda=%d, strideA=%d, incx=%d, strideX=%d, ldc=%d, strideC=%d, batchCount=%d)",
|
|
563
|
+
func.__name__,
|
|
564
|
+
side,
|
|
565
|
+
m,
|
|
566
|
+
n,
|
|
567
|
+
lda,
|
|
568
|
+
strideG,
|
|
569
|
+
incx,
|
|
570
|
+
strideX,
|
|
571
|
+
ldc,
|
|
572
|
+
strideC,
|
|
573
|
+
batchCount,
|
|
574
|
+
)
|
|
575
|
+
if batchCount > 1:
|
|
576
|
+
func(
|
|
577
|
+
side,
|
|
578
|
+
m,
|
|
579
|
+
n,
|
|
580
|
+
A.data_ptr,
|
|
581
|
+
lda,
|
|
582
|
+
strideG,
|
|
583
|
+
B.data_ptr,
|
|
584
|
+
incx,
|
|
585
|
+
strideX,
|
|
586
|
+
C.data_ptr,
|
|
587
|
+
ldc,
|
|
588
|
+
strideC,
|
|
589
|
+
batchCount,
|
|
590
|
+
stream_holder=stream_holder,
|
|
591
|
+
)
|
|
592
|
+
else:
|
|
593
|
+
func(
|
|
594
|
+
side,
|
|
595
|
+
m,
|
|
596
|
+
n,
|
|
597
|
+
A.data_ptr,
|
|
598
|
+
lda,
|
|
599
|
+
B.data_ptr,
|
|
600
|
+
incx,
|
|
601
|
+
C.data_ptr,
|
|
602
|
+
ldc,
|
|
603
|
+
stream_holder=stream_holder,
|
|
604
|
+
)
|
|
605
|
+
else:
|
|
606
|
+
msg = f"No available generic matrix multiplication matches the provided matrices: {qualifiers}."
|
|
607
|
+
raise ValueError(msg)
|
|
608
|
+
|
|
609
|
+
return wrapped, func.__name__
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
def select_blas_group_mm_function(
|
|
613
|
+
batch_traits: list[BatchTraits],
|
|
614
|
+
mm_traits: list[BLASMMTraitsView],
|
|
615
|
+
qualifiers: list[MatrixQualifier],
|
|
616
|
+
logger: LoggerLike,
|
|
617
|
+
execution: ExecutionCUDA | ExecutionCPU,
|
|
618
|
+
) -> tuple[WrappedMMFunction, str]:
|
|
619
|
+
"""Return a matrix multiplication function which matches the provided arguments."""
|
|
620
|
+
|
|
621
|
+
# At this level, we only select the appropriate library
|
|
622
|
+
match execution:
|
|
623
|
+
case ExecutionCPU():
|
|
624
|
+
mm_function_getter = nvpl_mm_function
|
|
625
|
+
mm_enum_mapper = nvpl_enum_mapper
|
|
626
|
+
mm_alpha_beta_picker = get_address_zeroth_element
|
|
627
|
+
case ExecutionCUDA():
|
|
628
|
+
mm_function_getter = cublas_mm_function
|
|
629
|
+
mm_enum_mapper = cublas_enum_mapper
|
|
630
|
+
mm_alpha_beta_picker = get_address_zeroth_element
|
|
631
|
+
case _:
|
|
632
|
+
raise ValueError("Only ExecutionCUDA and ExecutionCPU are supported.")
|
|
633
|
+
|
|
634
|
+
return _select_blas_group_mm_function_from_qualifiers(
|
|
635
|
+
batch_traits,
|
|
636
|
+
mm_traits,
|
|
637
|
+
qualifiers,
|
|
638
|
+
logger,
|
|
639
|
+
execution,
|
|
640
|
+
mm_function_getter,
|
|
641
|
+
mm_enum_mapper,
|
|
642
|
+
mm_alpha_beta_picker,
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def _select_blas_group_mm_function_from_qualifiers(
|
|
647
|
+
batch_traits: list[BatchTraits],
|
|
648
|
+
mm_traits: list[BLASMMTraitsView],
|
|
649
|
+
qualifiers: list[MatrixQualifier],
|
|
650
|
+
logger: LoggerLike,
|
|
651
|
+
execution: ExecutionCUDA | ExecutionCPU,
|
|
652
|
+
mm_function_getter: MMFunctionGetter,
|
|
653
|
+
mm_enum_mapper: typing.Callable,
|
|
654
|
+
mm_alpha_beta_picker: typing.Callable,
|
|
655
|
+
) -> tuple[WrappedMMFunction, str]:
|
|
656
|
+
"""Match and wrap a matrix multiplication function based on the provided arguments."""
|
|
657
|
+
# NOTE: The parameters of this function are only the operands that will be resettable by
|
|
658
|
+
# reset_operands(); the rest of the parameters should be unchanged by reset_operands.
|
|
659
|
+
# Therefore we can amortize the cost of those bits.
|
|
660
|
+
group_count = len(mm_traits)
|
|
661
|
+
if all(GeneralMatrixQualifier.is_valid(q) for q in qualifiers):
|
|
662
|
+
# Allocate separate numpy arrays for each parameter
|
|
663
|
+
transa_array = np.array([mm_enum_mapper(m.a_layout_traits.operation) for m in mm_traits], dtype=np.intc)
|
|
664
|
+
transb_array = np.array([mm_enum_mapper(m.b_layout_traits.operation) for m in mm_traits], dtype=np.intc)
|
|
665
|
+
transc_array = np.array([mm_enum_mapper(m.c_layout_traits.operation) for m in mm_traits], dtype=np.intc)
|
|
666
|
+
assert np.all(transc_array == mm_enum_mapper(cublas.Operation.N))
|
|
667
|
+
# NOTE: Switch between LP64 and ILP64 here
|
|
668
|
+
integer_dtype = np.int32
|
|
669
|
+
# integer_dtype = np.int64
|
|
670
|
+
m_array = np.array([m.M for m in mm_traits], dtype=integer_dtype)
|
|
671
|
+
n_array = np.array([m.N for m in mm_traits], dtype=integer_dtype)
|
|
672
|
+
k_array = np.array([m.K for m in mm_traits], dtype=integer_dtype)
|
|
673
|
+
lda_array = np.array([m.a_layout_traits.ld for m in mm_traits], dtype=integer_dtype)
|
|
674
|
+
ldb_array = np.array([m.b_layout_traits.ld for m in mm_traits], dtype=integer_dtype)
|
|
675
|
+
ldc_array = np.array([m.c_layout_traits.ld for m in mm_traits], dtype=integer_dtype)
|
|
676
|
+
group_size_array = np.array([max(1, b.count) for b in batch_traits], dtype=integer_dtype)
|
|
677
|
+
|
|
678
|
+
func = mm_function_getter(
|
|
679
|
+
execution,
|
|
680
|
+
mm_traits[0].a_layout_traits.dtype,
|
|
681
|
+
GeneralMatrixQualifier.abbreviation,
|
|
682
|
+
logger,
|
|
683
|
+
"group",
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
def wrapped(
|
|
687
|
+
Aarray: tensor_wrapper.TensorHolder,
|
|
688
|
+
Barray: tensor_wrapper.TensorHolder,
|
|
689
|
+
Carray: tensor_wrapper.TensorHolder,
|
|
690
|
+
alpha_array: np.ndarray,
|
|
691
|
+
beta_array: np.ndarray,
|
|
692
|
+
stream_holder: utils.StreamHolder | None,
|
|
693
|
+
) -> None:
|
|
694
|
+
# A,B pointers are swapped in _execute()
|
|
695
|
+
logger.debug(
|
|
696
|
+
"Calling %s(operationA=%s, operationB=%s, m=%s, n=%s, k=%s, alpha=%s, lda=%s, "
|
|
697
|
+
"ldb=%s, beta=%s, ldc=%s, groupCount=%d, groupSize=%s)",
|
|
698
|
+
func.__name__,
|
|
699
|
+
transa_array,
|
|
700
|
+
transb_array,
|
|
701
|
+
m_array,
|
|
702
|
+
n_array,
|
|
703
|
+
k_array,
|
|
704
|
+
alpha_array,
|
|
705
|
+
lda_array,
|
|
706
|
+
ldb_array,
|
|
707
|
+
beta_array,
|
|
708
|
+
ldc_array,
|
|
709
|
+
group_count,
|
|
710
|
+
group_size_array,
|
|
711
|
+
)
|
|
712
|
+
func(
|
|
713
|
+
transa_array.ctypes.data,
|
|
714
|
+
transb_array.ctypes.data,
|
|
715
|
+
m_array.ctypes.data,
|
|
716
|
+
n_array.ctypes.data,
|
|
717
|
+
k_array.ctypes.data,
|
|
718
|
+
alpha_array.ctypes.data,
|
|
719
|
+
Aarray.data_ptr,
|
|
720
|
+
lda_array.ctypes.data,
|
|
721
|
+
Barray.data_ptr,
|
|
722
|
+
ldb_array.ctypes.data,
|
|
723
|
+
beta_array.ctypes.data,
|
|
724
|
+
Carray.data_ptr,
|
|
725
|
+
ldc_array.ctypes.data,
|
|
726
|
+
group_count,
|
|
727
|
+
group_size_array.ctypes.data,
|
|
728
|
+
stream_holder=stream_holder,
|
|
729
|
+
)
|
|
730
|
+
else:
|
|
731
|
+
msg = f"No available explicitly batched generic matrix multiplication matches the provided matrices: {qualifiers}."
|
|
732
|
+
raise ValueError(msg)
|
|
733
|
+
|
|
734
|
+
return wrapped, func.__name__
|