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,382 @@
|
|
|
1
|
+
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
|
|
7
|
+
from nvmath.bindings import cusparse
|
|
8
|
+
from nvmath.bindings._internal.utils import FunctionNotFoundError
|
|
9
|
+
from nvmath.internal.typemaps import NAME_TO_DATA_TYPE
|
|
10
|
+
|
|
11
|
+
COMPATIBLE_SP_DN_PACKAGES = {("scipy", "numpy"), ("cupyx", "cupy"), ("torch", "torch"), ("nvmath", "nvmath")}
|
|
12
|
+
|
|
13
|
+
SUPPORTED_NAMED_FORMATS = {"BSR", "CSR", "CSC", "COO"}
|
|
14
|
+
|
|
15
|
+
INDEX_TYPE_MAP = {
|
|
16
|
+
"int32": cusparse.IndexType.INDEX_32I,
|
|
17
|
+
"int64": cusparse.IndexType.INDEX_64I,
|
|
18
|
+
"uint16": cusparse.IndexType.INDEX_16U,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
ORDER_TYPE_MAP = {"left": cusparse.Order.COL, "right": cusparse.Order.ROW}
|
|
22
|
+
|
|
23
|
+
# The index base is always 0.
|
|
24
|
+
BASE = 0
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SparseIfc(ABC):
|
|
28
|
+
"""
|
|
29
|
+
Abstract base to create and update sparse matrix descriptors.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def create(self):
|
|
34
|
+
"""
|
|
35
|
+
Create a cuSPARSE matrix descriptor.
|
|
36
|
+
"""
|
|
37
|
+
raise NotImplementedError
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def update(self, new_operand):
|
|
41
|
+
"""
|
|
42
|
+
Update the pointers in the sparse matrix descriptor.
|
|
43
|
+
"""
|
|
44
|
+
raise NotImplementedError
|
|
45
|
+
|
|
46
|
+
# Destructor is not dependent on sparse or dense, so no abstraction is needed.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class COOIfc(SparseIfc):
|
|
50
|
+
"""
|
|
51
|
+
Create and update sparse COO matrix descriptor.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, operand, layout_traits):
|
|
55
|
+
"""
|
|
56
|
+
The operand must be a wrapped sparse tensor.
|
|
57
|
+
"""
|
|
58
|
+
if layout_traits.batch_count != 1 or len(operand.indices) != 2:
|
|
59
|
+
raise NotImplementedError("Non-uniform batched COO matrices are not supported by cuSPARSE.")
|
|
60
|
+
self.values_size = operand.values.size
|
|
61
|
+
self.index_type = operand.index_type
|
|
62
|
+
self.dtype = operand.dtype
|
|
63
|
+
self.layout_traits = layout_traits
|
|
64
|
+
self.descriptor = None
|
|
65
|
+
# Updatable attributes
|
|
66
|
+
self.row_indices_data_ptr = operand.indices[0].data_ptr
|
|
67
|
+
self.col_indices_data_ptr = operand.indices[1].data_ptr
|
|
68
|
+
self.values_data_ptr = operand.values.data_ptr
|
|
69
|
+
|
|
70
|
+
def create(self):
|
|
71
|
+
"""
|
|
72
|
+
Create a cuSPARSE COO matrix descriptor.
|
|
73
|
+
"""
|
|
74
|
+
t = self.layout_traits
|
|
75
|
+
shape, nnz = t.mm_shape, self.values_size
|
|
76
|
+
|
|
77
|
+
if self.index_type not in INDEX_TYPE_MAP:
|
|
78
|
+
raise TypeError(f"The index type {self.index_type} is not in the supported types: {INDEX_TYPE_MAP.keys()}.")
|
|
79
|
+
|
|
80
|
+
index_type, value_type = INDEX_TYPE_MAP[self.index_type], NAME_TO_DATA_TYPE[self.dtype]
|
|
81
|
+
|
|
82
|
+
self.descriptor = cusparse.create_coo(
|
|
83
|
+
*shape,
|
|
84
|
+
nnz,
|
|
85
|
+
self.row_indices_data_ptr,
|
|
86
|
+
self.col_indices_data_ptr,
|
|
87
|
+
self.values_data_ptr,
|
|
88
|
+
index_type,
|
|
89
|
+
BASE,
|
|
90
|
+
value_type,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return self.descriptor
|
|
94
|
+
|
|
95
|
+
def update(self, new_operand):
|
|
96
|
+
"""
|
|
97
|
+
Update the pointers in the sparse matrix descriptor.
|
|
98
|
+
"""
|
|
99
|
+
self.row_indices_data_ptr = row_ptr = new_operand.indices[0].data_ptr
|
|
100
|
+
self.col_indices_data_ptr = col_ptr = new_operand.indices[1].data_ptr
|
|
101
|
+
self.values_data_ptr = values_data_ptr = new_operand.values.data_ptr
|
|
102
|
+
cusparse.coo_set_pointers(self.descriptor, row_ptr, col_ptr, values_data_ptr)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class CSRIfc(SparseIfc):
|
|
106
|
+
"""
|
|
107
|
+
Create and update sparse CSR matrix descriptor.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
# TODO: take logger to log debug messages.
|
|
111
|
+
def __init__(self, operand, layout_traits):
|
|
112
|
+
"""
|
|
113
|
+
The operand must be a wrapped sparse tensor.
|
|
114
|
+
"""
|
|
115
|
+
self.values_size = operand.values.size
|
|
116
|
+
self.crow_indices_size = operand.crow_indices.size
|
|
117
|
+
self.index_type = operand.index_type
|
|
118
|
+
self.dtype = operand.dtype
|
|
119
|
+
self.layout_traits = layout_traits
|
|
120
|
+
self.descriptor = None
|
|
121
|
+
# Updatable attributes
|
|
122
|
+
self.crow_indices_data_ptr = operand.crow_indices.data_ptr
|
|
123
|
+
self.col_indices_data_ptr = operand.col_indices.data_ptr
|
|
124
|
+
self.values_data_ptr = operand.values.data_ptr
|
|
125
|
+
|
|
126
|
+
def create(self):
|
|
127
|
+
"""
|
|
128
|
+
Create a cuSPARSE CSR matrix descriptor.
|
|
129
|
+
"""
|
|
130
|
+
t = self.layout_traits
|
|
131
|
+
|
|
132
|
+
if t.batch_broadcast:
|
|
133
|
+
shape, nnz = t.mm_shape, self.values_size
|
|
134
|
+
else:
|
|
135
|
+
assert self.values_size % t.batch_count == 0, "Internal error."
|
|
136
|
+
shape, nnz = t.mm_shape, self.values_size // t.batch_count
|
|
137
|
+
|
|
138
|
+
if self.index_type not in INDEX_TYPE_MAP:
|
|
139
|
+
raise TypeError(f"The index type {self.index_type} is not in the supported types: {INDEX_TYPE_MAP.keys()}.")
|
|
140
|
+
|
|
141
|
+
index_type, value_type = INDEX_TYPE_MAP[self.index_type], NAME_TO_DATA_TYPE[self.dtype]
|
|
142
|
+
|
|
143
|
+
self.descriptor = cusparse.create_csr(
|
|
144
|
+
*shape,
|
|
145
|
+
nnz,
|
|
146
|
+
self.crow_indices_data_ptr,
|
|
147
|
+
self.col_indices_data_ptr,
|
|
148
|
+
self.values_data_ptr,
|
|
149
|
+
index_type,
|
|
150
|
+
index_type,
|
|
151
|
+
BASE,
|
|
152
|
+
value_type,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# Handle batching.
|
|
156
|
+
if t.batch_count > 1:
|
|
157
|
+
if t.batch_broadcast:
|
|
158
|
+
crow_indices_batch_offset = 0
|
|
159
|
+
values_batch_offset = 0
|
|
160
|
+
else:
|
|
161
|
+
assert self.crow_indices_size % t.batch_count == 0, "Internal error."
|
|
162
|
+
crow_indices_batch_offset = self.crow_indices_size // t.batch_count
|
|
163
|
+
|
|
164
|
+
assert self.values_size % t.batch_count == 0, "Internal error."
|
|
165
|
+
values_batch_offset = self.values_size // t.batch_count
|
|
166
|
+
|
|
167
|
+
cusparse.csr_set_strided_batch(self.descriptor, t.batch_count, crow_indices_batch_offset, values_batch_offset)
|
|
168
|
+
|
|
169
|
+
return self.descriptor
|
|
170
|
+
|
|
171
|
+
def update(self, new_operand):
|
|
172
|
+
"""
|
|
173
|
+
Update the pointers in the sparse matrix descriptor.
|
|
174
|
+
"""
|
|
175
|
+
self.crow_indices_data_ptr = new_operand.crow_indices.data_ptr
|
|
176
|
+
self.col_indices_data_ptr = new_operand.col_indices.data_ptr
|
|
177
|
+
self.values_data_ptr = new_operand.values.data_ptr
|
|
178
|
+
cusparse.csr_set_pointers(self.descriptor, self.crow_indices_data_ptr, self.col_indices_data_ptr, self.values_data_ptr)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class BSRIfc(SparseIfc):
|
|
182
|
+
"""
|
|
183
|
+
Create and update sparse BSR matrix descriptor.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
# TODO: take logger to log debug messages.
|
|
187
|
+
def __init__(self, operand, layout_traits):
|
|
188
|
+
"""
|
|
189
|
+
The operand must be a wrapped sparse tensor.
|
|
190
|
+
"""
|
|
191
|
+
self.block_size = operand.block_size
|
|
192
|
+
self.values_size = operand.values.size
|
|
193
|
+
self.crow_indices_size = operand.crow_indices.size
|
|
194
|
+
self.col_indices_size = operand.col_indices.size
|
|
195
|
+
self.index_type = operand.index_type
|
|
196
|
+
self.dtype = operand.dtype
|
|
197
|
+
self.block_order = ORDER_TYPE_MAP[operand.block_order]
|
|
198
|
+
self.layout_traits = layout_traits
|
|
199
|
+
self.descriptor = None
|
|
200
|
+
# Updatable attributes
|
|
201
|
+
self.crow_indices_data_ptr = operand.crow_indices.data_ptr
|
|
202
|
+
self.col_indices_data_ptr = operand.col_indices.data_ptr
|
|
203
|
+
self.values_data_ptr = operand.values.data_ptr
|
|
204
|
+
|
|
205
|
+
def create(self):
|
|
206
|
+
"""
|
|
207
|
+
Create a cuSPARSE BSR matrix descriptor.
|
|
208
|
+
"""
|
|
209
|
+
t = self.layout_traits
|
|
210
|
+
b0, b1 = self.block_size
|
|
211
|
+
|
|
212
|
+
# TODO: more elegant way of getting the number of non-zero blocks.
|
|
213
|
+
if t.batch_broadcast:
|
|
214
|
+
shape, bnnz = t.mm_shape, self.values_size // (b0 * b1)
|
|
215
|
+
else:
|
|
216
|
+
assert self.values_size % t.batch_count == 0, "Internal error."
|
|
217
|
+
shape, bnnz = t.mm_shape, self.values_size // (t.batch_count * b0 * b1)
|
|
218
|
+
|
|
219
|
+
assert shape[0] % b0 == 0 and shape[1] % b1 == 0, "Internal error."
|
|
220
|
+
shape_in_blocks = shape[0] // b0, shape[1] // b1
|
|
221
|
+
|
|
222
|
+
if self.index_type not in INDEX_TYPE_MAP:
|
|
223
|
+
raise TypeError(f"The index type {self.index_type} is not in the supported types: {INDEX_TYPE_MAP.keys()}.")
|
|
224
|
+
|
|
225
|
+
index_type, value_type = INDEX_TYPE_MAP[self.index_type], NAME_TO_DATA_TYPE[self.dtype]
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
self.descriptor = cusparse.create_bsr(
|
|
229
|
+
*shape_in_blocks,
|
|
230
|
+
bnnz,
|
|
231
|
+
b0,
|
|
232
|
+
b1,
|
|
233
|
+
self.crow_indices_data_ptr,
|
|
234
|
+
self.col_indices_data_ptr,
|
|
235
|
+
self.values_data_ptr,
|
|
236
|
+
index_type,
|
|
237
|
+
index_type,
|
|
238
|
+
BASE,
|
|
239
|
+
value_type,
|
|
240
|
+
self.block_order,
|
|
241
|
+
)
|
|
242
|
+
except FunctionNotFoundError as e:
|
|
243
|
+
raise RuntimeError("BSR is not supported by the installed cuSPARSE library.") from e
|
|
244
|
+
|
|
245
|
+
# Handle batching.
|
|
246
|
+
if t.batch_count > 1:
|
|
247
|
+
if t.batch_broadcast:
|
|
248
|
+
crow_indices_batch_offset = 0
|
|
249
|
+
col_indices_batch_offset = 0
|
|
250
|
+
values_batch_offset = 0
|
|
251
|
+
else:
|
|
252
|
+
assert self.crow_indices_size % t.batch_count == 0, "Internal error."
|
|
253
|
+
crow_indices_batch_offset = self.crow_indices_size // t.batch_count
|
|
254
|
+
|
|
255
|
+
assert self.col_indices_size % t.batch_count == 0, "Internal error."
|
|
256
|
+
col_indices_batch_offset = self.col_indices_size // t.batch_count
|
|
257
|
+
|
|
258
|
+
assert self.values_size % t.batch_count == 0, "Internal error."
|
|
259
|
+
values_batch_offset = self.values_size // t.batch_count
|
|
260
|
+
|
|
261
|
+
cusparse.bsr_set_strided_batch(
|
|
262
|
+
self.descriptor, t.batch_count, crow_indices_batch_offset, col_indices_batch_offset, values_batch_offset
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
return self.descriptor
|
|
266
|
+
|
|
267
|
+
def update(self, new_operand):
|
|
268
|
+
"""
|
|
269
|
+
Update the pointers in the sparse matrix descriptor.
|
|
270
|
+
"""
|
|
271
|
+
self.crow_indices_data_ptr = new_operand.crow_indices.data_ptr
|
|
272
|
+
self.col_indices_data_ptr = new_operand.col_indices.data_ptr
|
|
273
|
+
self.values_data_ptr = new_operand.values.data_ptr
|
|
274
|
+
|
|
275
|
+
# There is no API currently to just update the pointers so we've to create a new
|
|
276
|
+
# descriptor.
|
|
277
|
+
if self.descriptor is not None:
|
|
278
|
+
cusparse.destroy_sp_mat(self.descriptor)
|
|
279
|
+
self.create()
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class CSCIfc(SparseIfc):
|
|
283
|
+
"""
|
|
284
|
+
Create and update sparse CSC matrix descriptor.
|
|
285
|
+
"""
|
|
286
|
+
|
|
287
|
+
# TODO: take logger to log debug messages.
|
|
288
|
+
def __init__(self, operand, layout_traits):
|
|
289
|
+
"""
|
|
290
|
+
The operand must be a wrapped sparse tensor.
|
|
291
|
+
"""
|
|
292
|
+
self.values_size = operand.values.size
|
|
293
|
+
self.index_type = operand.index_type
|
|
294
|
+
self.dtype = operand.dtype
|
|
295
|
+
self.layout_traits = layout_traits
|
|
296
|
+
self.descriptor = None
|
|
297
|
+
|
|
298
|
+
# Updatable attributes
|
|
299
|
+
self.ccol_indices_data_ptr = operand.ccol_indices.data_ptr
|
|
300
|
+
self.row_indices_data_ptr = operand.row_indices.data_ptr
|
|
301
|
+
self.values_data_ptr = operand.values.data_ptr
|
|
302
|
+
|
|
303
|
+
def create(self):
|
|
304
|
+
"""
|
|
305
|
+
Create a cuSPARSE CSC matrix descriptor.
|
|
306
|
+
"""
|
|
307
|
+
t = self.layout_traits
|
|
308
|
+
|
|
309
|
+
if t.batch_broadcast:
|
|
310
|
+
shape, nnz = t.mm_shape, self.values_size
|
|
311
|
+
else:
|
|
312
|
+
assert self.values_size % t.batch_count == 0, "Internal error."
|
|
313
|
+
shape, nnz = t.mm_shape, self.values_size // t.batch_count
|
|
314
|
+
|
|
315
|
+
if self.index_type not in INDEX_TYPE_MAP:
|
|
316
|
+
raise TypeError(f"The index type {self.index_type} is not in the supported types: {INDEX_TYPE_MAP.keys()}.")
|
|
317
|
+
|
|
318
|
+
index_type, value_type = INDEX_TYPE_MAP[self.index_type], NAME_TO_DATA_TYPE[self.dtype]
|
|
319
|
+
|
|
320
|
+
self.descriptor = cusparse.create_csc(
|
|
321
|
+
*shape,
|
|
322
|
+
nnz,
|
|
323
|
+
self.ccol_indices_data_ptr,
|
|
324
|
+
self.row_indices_data_ptr,
|
|
325
|
+
self.values_data_ptr,
|
|
326
|
+
index_type,
|
|
327
|
+
index_type,
|
|
328
|
+
BASE,
|
|
329
|
+
value_type,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
# Handle batching.
|
|
333
|
+
if t.batch_count > 1:
|
|
334
|
+
raise NotImplementedError("The cuSPARSE library doesn't currently support batched CSC matrices.")
|
|
335
|
+
|
|
336
|
+
return self.descriptor
|
|
337
|
+
|
|
338
|
+
def update(self, new_operand):
|
|
339
|
+
"""
|
|
340
|
+
Update the pointers in the sparse matrix descriptor.
|
|
341
|
+
"""
|
|
342
|
+
self.ccol_indices_data_ptr = ccol_indices_data_ptr = new_operand.ccol_indices.data_ptr
|
|
343
|
+
self.row_indices_data_ptr = row_indices_data_ptr = new_operand.row_indices.data_ptr
|
|
344
|
+
self.values_data_ptr = values_data_ptr = new_operand.values.data_ptr
|
|
345
|
+
cusparse.csc_set_pointers(self.descriptor, ccol_indices_data_ptr, row_indices_data_ptr, values_data_ptr)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class DenseMatrixIfc:
|
|
349
|
+
"""
|
|
350
|
+
Create and update dense matrix descriptors.
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
def __init__(self, operand, layout_traits):
|
|
354
|
+
"""
|
|
355
|
+
The operand must be a wrapped dense tensor.
|
|
356
|
+
"""
|
|
357
|
+
self.dtype = operand.dtype
|
|
358
|
+
self.layout_traits = layout_traits
|
|
359
|
+
self.descriptor = None
|
|
360
|
+
# Updatable attributes
|
|
361
|
+
self.data_ptr = operand.data_ptr
|
|
362
|
+
|
|
363
|
+
def create(self):
|
|
364
|
+
"""
|
|
365
|
+
Create a cuSPARSE dense matrix descriptor.
|
|
366
|
+
"""
|
|
367
|
+
|
|
368
|
+
t = self.layout_traits
|
|
369
|
+
|
|
370
|
+
self.descriptor = cusparse.create_dn_mat(*t.mm_shape, t.ld, self.data_ptr, NAME_TO_DATA_TYPE[self.dtype], t.order)
|
|
371
|
+
|
|
372
|
+
if t.batch_count > 1:
|
|
373
|
+
cusparse.dn_mat_set_strided_batch(self.descriptor, t.batch_count, t.batch_offset)
|
|
374
|
+
|
|
375
|
+
return self.descriptor
|
|
376
|
+
|
|
377
|
+
def update(self, new_operand):
|
|
378
|
+
"""
|
|
379
|
+
Update the pointers in the dense matrix descriptor.
|
|
380
|
+
"""
|
|
381
|
+
self.data_ptr = data_ptr = new_operand.data_ptr
|
|
382
|
+
cusparse.dn_mat_set_values(self.descriptor, data_ptr)
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface to seamlessly use BSC tensors from different libraries.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations # allows typehint of class methods to return the self class
|
|
10
|
+
|
|
11
|
+
__all__ = ["BSCTensorHolder"]
|
|
12
|
+
|
|
13
|
+
from typing import Literal, TypeVar
|
|
14
|
+
|
|
15
|
+
from nvmath._internal.layout import check_monotonic_strides, is_contiguous_and_dense
|
|
16
|
+
from nvmath.internal import tensor_wrapper
|
|
17
|
+
from nvmath.internal.package_ifc import StreamHolder
|
|
18
|
+
from nvmath.internal.tensor_ifc import TensorHolder
|
|
19
|
+
from nvmath.internal.utils import infer_object_package
|
|
20
|
+
|
|
21
|
+
from .sparse_tensor_ifc import SparseTensorHolder
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
A generic type for the third-party BSCTensor which a BSCTensorHolder implementation wraps
|
|
25
|
+
around.
|
|
26
|
+
"""
|
|
27
|
+
BSCTensor = TypeVar("BSCTensor")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BSCTensorHolder(SparseTensorHolder):
|
|
31
|
+
"""
|
|
32
|
+
A simple wrapper type for BSC sparse tensors to make the API package-agnostic. The
|
|
33
|
+
naming convention is sparse format name with the suffix "TensorHolder", which convention
|
|
34
|
+
is used in the sparse format helper.
|
|
35
|
+
|
|
36
|
+
Since the implementation is in terms of our dense tensor abstraction, package-specific
|
|
37
|
+
implementation is not needed.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
_format_name: str = "BSC"
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self, block_size, block_order, ccol_indices, row_indices, values, *, attr_name_map=None, shape=None, tensor=None
|
|
44
|
+
):
|
|
45
|
+
# tensor is the native tensor.
|
|
46
|
+
self.tensor = tensor
|
|
47
|
+
|
|
48
|
+
# The block size is a sequence of integers.
|
|
49
|
+
self._block_size = block_size
|
|
50
|
+
|
|
51
|
+
# The block order is "left" or "right".
|
|
52
|
+
self._block_order = block_order
|
|
53
|
+
|
|
54
|
+
# attr_name_map is the canonical attribute name to package attribute name map.
|
|
55
|
+
# It is set when constructing from a tensor, otherwise it is None.
|
|
56
|
+
self._attr_name_map = attr_name_map
|
|
57
|
+
|
|
58
|
+
assert (shape is not None) ^ (tensor is not None), "Internal error."
|
|
59
|
+
|
|
60
|
+
if shape is not None:
|
|
61
|
+
self._shape = shape
|
|
62
|
+
else:
|
|
63
|
+
self._shape = tuple(tensor.shape)
|
|
64
|
+
|
|
65
|
+
# Wrap constituent dense tensors, if required.
|
|
66
|
+
if not isinstance(ccol_indices, TensorHolder):
|
|
67
|
+
ccol_indices = tensor_wrapper.wrap_operand(ccol_indices)
|
|
68
|
+
|
|
69
|
+
if not isinstance(row_indices, TensorHolder):
|
|
70
|
+
row_indices = tensor_wrapper.wrap_operand(row_indices)
|
|
71
|
+
|
|
72
|
+
if not isinstance(values, TensorHolder):
|
|
73
|
+
values = tensor_wrapper.wrap_operand(values)
|
|
74
|
+
|
|
75
|
+
# The wrapped constituent dense tensors.
|
|
76
|
+
self._ccol_indices = ccol_indices
|
|
77
|
+
self._row_indices = row_indices
|
|
78
|
+
self._values = values
|
|
79
|
+
|
|
80
|
+
# Ensure constituent dense tensors are all on the same device.
|
|
81
|
+
device_ids = {d.device_id for d in (self._ccol_indices, self._row_indices, self._values)}
|
|
82
|
+
message = f"Internal error: the arrays defining the sparse format aren't on the same device {device_ids}."
|
|
83
|
+
assert len(device_ids) == 1, message
|
|
84
|
+
self._device_id = device_ids.pop()
|
|
85
|
+
|
|
86
|
+
self._device = self._values.device
|
|
87
|
+
|
|
88
|
+
# Capture the native tensor package for use in reset_unchecked().
|
|
89
|
+
self.tensor_package = infer_object_package(self.tensor)
|
|
90
|
+
|
|
91
|
+
# The tensor holder type for the dense constituent tensors (take from values, since
|
|
92
|
+
# all constituent tensors have the same type).
|
|
93
|
+
self._dense_tensorholder_type = values.__class__
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def create_from_tensor(cls, tensor, *, attr_name_map=None):
|
|
97
|
+
assert attr_name_map is not None, "Internal error."
|
|
98
|
+
|
|
99
|
+
# tensor is the native tensor.
|
|
100
|
+
# For UST, the buffers will be CuPy ndarrays.
|
|
101
|
+
block_size = attr_name_map["block_size"](tensor)
|
|
102
|
+
block_order = attr_name_map["block_order"](tensor)
|
|
103
|
+
ccol_indices = attr_name_map["ccol_indices"](tensor)
|
|
104
|
+
row_indices = attr_name_map["row_indices"](tensor)
|
|
105
|
+
values = attr_name_map["values"](tensor)
|
|
106
|
+
return BSCTensorHolder(
|
|
107
|
+
block_size, block_order, ccol_indices, row_indices, values, attr_name_map=attr_name_map, tensor=tensor
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def attr_name_map(self):
|
|
112
|
+
return self._attr_name_map
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def device(self):
|
|
116
|
+
return self._device
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def device_id(self):
|
|
120
|
+
return self._device_id
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def dtype(self):
|
|
124
|
+
return self._values.dtype
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def index_type(self):
|
|
128
|
+
return self._ccol_indices.dtype
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def format_name(self) -> str:
|
|
132
|
+
return BSCTensorHolder._format_name
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def num_dimensions(self):
|
|
136
|
+
return len(self._shape)
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def shape(self):
|
|
140
|
+
return self._shape
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def block_size(self):
|
|
144
|
+
return self._block_size
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def block_order(self):
|
|
148
|
+
return self._block_order
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def ccol_indices(self) -> TensorHolder:
|
|
152
|
+
"""The TensorHolder object wrapping the ccol_indices array."""
|
|
153
|
+
return self._ccol_indices
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def row_indices(self) -> TensorHolder:
|
|
157
|
+
"""The TensorHolder object wrapping the row_indices array."""
|
|
158
|
+
return self._row_indices
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def values(self) -> TensorHolder:
|
|
162
|
+
"""The TensorHolder object wrapping the values array."""
|
|
163
|
+
return self._values
|
|
164
|
+
|
|
165
|
+
def to(self, device_id: int | Literal["cpu"], stream_holder: StreamHolder | None):
|
|
166
|
+
"""Copy the BSCTensor representation to a different device.
|
|
167
|
+
|
|
168
|
+
No copy is performed if the BSCTensor is already on the requested device.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
if self.tensor_package == "nvmath":
|
|
172
|
+
return super().to(device_id=device_id, stream_holder=stream_holder)
|
|
173
|
+
|
|
174
|
+
target_ccol_indices = self.ccol_indices.to(device_id=device_id, stream_holder=stream_holder)
|
|
175
|
+
target_row_indices = self.row_indices.to(device_id=device_id, stream_holder=stream_holder)
|
|
176
|
+
target_values = self.values.to(device_id=device_id, stream_holder=stream_holder)
|
|
177
|
+
|
|
178
|
+
return BSCTensorHolder(
|
|
179
|
+
self.block_size,
|
|
180
|
+
self.block_order,
|
|
181
|
+
target_ccol_indices,
|
|
182
|
+
target_row_indices,
|
|
183
|
+
target_values,
|
|
184
|
+
attr_name_map=self.attr_name_map,
|
|
185
|
+
shape=self.shape,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
def copy_(self, src, stream_holder: StreamHolder | None) -> None:
|
|
189
|
+
"""Overwrite self.tensor (in-place) with a copy of src (BSCTensor)."""
|
|
190
|
+
|
|
191
|
+
self._block_size = src.block_size
|
|
192
|
+
self._block_order = src.block_order
|
|
193
|
+
self.ccol_indices.copy_(src=src.ccol_indices, stream_holder=stream_holder)
|
|
194
|
+
self.row_indices.copy_(src=src.row_indices, stream_holder=stream_holder)
|
|
195
|
+
self.values.copy_(src=src.values, stream_holder=stream_holder)
|
|
196
|
+
|
|
197
|
+
def to_ust(self, *, stream):
|
|
198
|
+
from nvmath.sparse.ust.tensor import Tensor
|
|
199
|
+
from nvmath.sparse.ust.tensor_format import NamedFormats
|
|
200
|
+
|
|
201
|
+
wrapped = self
|
|
202
|
+
tensor = wrapped.tensor
|
|
203
|
+
if not (wrapped.attr_name_map["is_coalesced"](tensor) and wrapped.attr_name_map["has_sorted_indices"](tensor)):
|
|
204
|
+
raise ValueError(
|
|
205
|
+
"The BSC tensor is not coalesced (metadata sorted with duplicates removed). \
|
|
206
|
+
To coalesce, use the operation provided by your sparse tensor library: `coalesce()`, `sum_duplicates()`, ..."
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
if not (
|
|
210
|
+
is_contiguous_and_dense(wrapped.ccol_indices.shape, wrapped.ccol_indices.strides)
|
|
211
|
+
and is_contiguous_and_dense(wrapped.row_indices.shape, wrapped.row_indices.strides)
|
|
212
|
+
and is_contiguous_and_dense(wrapped.values.shape, wrapped.values.strides)
|
|
213
|
+
):
|
|
214
|
+
raise ValueError(
|
|
215
|
+
"The sparse tensor representation (ccol_indices(), row_indices(), and values() tensors) must be \
|
|
216
|
+
dense and contiguous."
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
values = wrapped.values.memory_buffer() # Typed memory viewed as a 1-D tensor.
|
|
220
|
+
|
|
221
|
+
num_dim = self.num_dimensions
|
|
222
|
+
num_sparse_dim = self.attr_name_map["num_sparse_dim"](tensor)
|
|
223
|
+
num_dense_dim = self.attr_name_map["num_dense_dim"](tensor)
|
|
224
|
+
num_batch_dim = num_dim - num_sparse_dim - num_dense_dim
|
|
225
|
+
|
|
226
|
+
block_size = wrapped.block_size
|
|
227
|
+
tensor_format = (
|
|
228
|
+
NamedFormats.BSCLeftd(block_size, num_batch_dim, num_dense_dim)
|
|
229
|
+
if wrapped.block_order == "left"
|
|
230
|
+
else NamedFormats.BSCRightd(block_size, num_batch_dim, num_dense_dim)
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Check if the batch axes are in C-order for all component dense arrays.
|
|
234
|
+
if not (
|
|
235
|
+
check_monotonic_strides(wrapped.ccol_indices.strides[:num_batch_dim], reverse=True)
|
|
236
|
+
and check_monotonic_strides(wrapped.row_indices.strides[:num_batch_dim], reverse=True)
|
|
237
|
+
and check_monotonic_strides(wrapped.values.strides[:num_batch_dim], reverse=True)
|
|
238
|
+
):
|
|
239
|
+
raise ValueError(
|
|
240
|
+
"The batch dimensions in the sparse tensor representation (ccol_indices(), row_indices(), \
|
|
241
|
+
and values() tensors) must use the C-layout."
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Create the UST.
|
|
245
|
+
ust = Tensor(tensor.shape, tensor_format=tensor_format, index_type=wrapped.index_type, dtype=wrapped.dtype)
|
|
246
|
+
|
|
247
|
+
ust._pos[num_batch_dim + 1] = wrapped.ccol_indices
|
|
248
|
+
ust._crd[num_batch_dim + 1] = wrapped.row_indices
|
|
249
|
+
ust._val = values
|
|
250
|
+
|
|
251
|
+
return ust
|
|
252
|
+
|
|
253
|
+
def to_package(self):
|
|
254
|
+
"""
|
|
255
|
+
This will create a sparse tensor for the original package from which this
|
|
256
|
+
interface was created.
|
|
257
|
+
"""
|
|
258
|
+
create_bsc = self.attr_name_map["sparse_format_helper"].create_bsc
|
|
259
|
+
return create_bsc(self.shape, self.block_size, self.ccol_indices, self.row_indices, self.values)
|
|
260
|
+
|
|
261
|
+
def release(self):
|
|
262
|
+
"""
|
|
263
|
+
This method will release the wrapped tensor and any format-specific data
|
|
264
|
+
by setting them to None.
|
|
265
|
+
"""
|
|
266
|
+
# The tensor reference.
|
|
267
|
+
self.tensor = None
|
|
268
|
+
|
|
269
|
+
# Format-specific data.
|
|
270
|
+
self._ccol_indices = None
|
|
271
|
+
self._row_indices = None
|
|
272
|
+
self._values = None
|
|
273
|
+
|
|
274
|
+
def reset_unchecked(self, tensor):
|
|
275
|
+
"""
|
|
276
|
+
This method will reset the wrapped tensor to the specified one, and update
|
|
277
|
+
any format-specific data accordingly. It assumes that all attributes
|
|
278
|
+
like the device, shape, etc are consistent between the existing and new tensor.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
tensor: The native tensor to wrap.
|
|
282
|
+
"""
|
|
283
|
+
# Update the tensor reference.
|
|
284
|
+
self.tensor = tensor
|
|
285
|
+
|
|
286
|
+
# Format-specific data.
|
|
287
|
+
|
|
288
|
+
if self.tensor_package == "nvmath":
|
|
289
|
+
# The data arrays are already wrapped.
|
|
290
|
+
self._ccol_indices = self._attr_name_map["ccol_indices"](tensor)
|
|
291
|
+
self._row_indices = self._attr_name_map["row_indices"](tensor)
|
|
292
|
+
self._values = self._attr_name_map["values"](tensor)
|
|
293
|
+
else:
|
|
294
|
+
wrapper = self._dense_tensorholder_type
|
|
295
|
+
|
|
296
|
+
ccol_indices = self._attr_name_map["ccol_indices"](tensor)
|
|
297
|
+
self._ccol_indices = wrapper(ccol_indices)
|
|
298
|
+
|
|
299
|
+
row_indices = self._attr_name_map["row_indices"](tensor)
|
|
300
|
+
self._row_indices = wrapper(row_indices)
|
|
301
|
+
|
|
302
|
+
values = self._attr_name_map["values"](tensor)
|
|
303
|
+
self._values = wrapper(values)
|