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,422 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
This module implements converters for the Universal Sparse Tensor (UST).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = []
|
|
10
|
+
|
|
11
|
+
from collections.abc import Sequence
|
|
12
|
+
|
|
13
|
+
# from numba import njit
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
from nvmath.internal import utils
|
|
17
|
+
from nvmath.internal.tensor_wrapper import wrap_operand
|
|
18
|
+
|
|
19
|
+
from ._utils import LevelMap, np_enveloping_type, resolve_stream, stream_context
|
|
20
|
+
from .tensor_format import Add, LevelExpr, LevelFormat, Subtract, is_unique
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TensorDecomposer:
|
|
24
|
+
"""
|
|
25
|
+
A class that traverses a Universal Sparse Tensor and calls a functor for every
|
|
26
|
+
stored element. The traversal can be used for conversions and debugging but may
|
|
27
|
+
not necessarily provide the most efficient way of implementing a traversal.
|
|
28
|
+
Also see set_kernel and run_kernel.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
tensor: the UST tensor for traversal
|
|
32
|
+
functor: a function of the form `def visit(dims, val)`
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, tensor, functor):
|
|
36
|
+
self._tensor = tensor
|
|
37
|
+
self._functor = functor
|
|
38
|
+
self._flist = list(tensor.tensor_format.levels.items())
|
|
39
|
+
self._lvls = [0] * tensor.num_levels # pre-populate
|
|
40
|
+
|
|
41
|
+
def run(self, stream=None):
|
|
42
|
+
# We're going to repeatedly access single items of the tensor, so it's
|
|
43
|
+
# more efficient to copy to CPU first.
|
|
44
|
+
if self._tensor.device_id != "cpu":
|
|
45
|
+
stream_holder = resolve_stream(stream, self._tensor)
|
|
46
|
+
self._tensor = self._tensor._to("cpu", stream_holder)
|
|
47
|
+
self._iterate(0, 0, None)
|
|
48
|
+
|
|
49
|
+
def _iterate(self, idx, p, lasta):
|
|
50
|
+
# All levels exhausted?
|
|
51
|
+
if idx == self._tensor.num_levels:
|
|
52
|
+
assert lasta is None # consumed add/sub in range
|
|
53
|
+
val = self._tensor._val.tensor
|
|
54
|
+
self._functor(self._tensor.tensor_format.lvl2dim(self._lvls), val[p].item())
|
|
55
|
+
return
|
|
56
|
+
# Inspect level.
|
|
57
|
+
k, v = self._flist[idx]
|
|
58
|
+
if isinstance(v, Sequence):
|
|
59
|
+
fmt, prop = v
|
|
60
|
+
else:
|
|
61
|
+
fmt, prop = v, None
|
|
62
|
+
# Handle level format.
|
|
63
|
+
if fmt in (LevelFormat.DENSE, LevelFormat.BATCH):
|
|
64
|
+
sz = self._tensor.levels[idx]
|
|
65
|
+
for i in range(sz):
|
|
66
|
+
self._lvls[idx] = i
|
|
67
|
+
self._iterate(idx + 1, p * sz + i, lasta)
|
|
68
|
+
elif fmt == LevelFormat.COMPRESSED:
|
|
69
|
+
if isinstance(k, LevelExpr) and isinstance(k.operator, (Add, Subtract)):
|
|
70
|
+
assert lasta is None # no add/sub nesting
|
|
71
|
+
lasta = idx # record last add/sub
|
|
72
|
+
pos = self._tensor._pos[idx].tensor
|
|
73
|
+
crd = self._tensor._crd[idx].tensor
|
|
74
|
+
assert pos.ndim == crd.ndim
|
|
75
|
+
adjust = 0
|
|
76
|
+
if pos.ndim > 1:
|
|
77
|
+
# This only happens for prior BATCH. Correct the higher-dimensions in
|
|
78
|
+
# both pos and crd buffers and adjust position by #nnz per batch.
|
|
79
|
+
assert pos.ndim == idx
|
|
80
|
+
for i in range(idx - 1):
|
|
81
|
+
assert self._flist[i][1] == LevelFormat.BATCH
|
|
82
|
+
pos = pos[self._lvls[i]]
|
|
83
|
+
crd = crd[self._lvls[i]]
|
|
84
|
+
adjust = pos[-1].item() * (p - self._lvls[idx - 1]) // self._tensor.levels[idx - 1]
|
|
85
|
+
p = self._lvls[idx - 1]
|
|
86
|
+
lo = pos[p].item()
|
|
87
|
+
hi = pos[p + 1].item()
|
|
88
|
+
for i in range(lo, hi):
|
|
89
|
+
self._lvls[idx] = crd[i].item()
|
|
90
|
+
self._iterate(idx + 1, i + adjust, lasta)
|
|
91
|
+
elif fmt == LevelFormat.SINGLETON:
|
|
92
|
+
crd = self._tensor._crd[idx].tensor
|
|
93
|
+
assert crd.ndim == 1
|
|
94
|
+
self._lvls[idx] = crd[p].item()
|
|
95
|
+
self._iterate(idx + 1, p, lasta)
|
|
96
|
+
elif fmt == LevelFormat.RANGE:
|
|
97
|
+
assert lasta is not None # single add/sub-range relation
|
|
98
|
+
add, _ = self._flist[lasta]
|
|
99
|
+
isI = k == add.expression2
|
|
100
|
+
di = self._tensor.tensor_format.dimensions.index(k)
|
|
101
|
+
dj = self._tensor.tensor_format.dimensions.index(add.expression1 if isI else add.expression2)
|
|
102
|
+
szi = self._tensor.extents[di]
|
|
103
|
+
szj = self._tensor.extents[dj]
|
|
104
|
+
lsz = self._lvls[lasta]
|
|
105
|
+
if isinstance(add.operator, Add):
|
|
106
|
+
off = lsz
|
|
107
|
+
lo = max(0, off - szj + 1)
|
|
108
|
+
hi = min(szi, off + 1)
|
|
109
|
+
else:
|
|
110
|
+
off = -lsz if isI else lsz
|
|
111
|
+
lo = max(0, off)
|
|
112
|
+
hi = min(szi, szj + off)
|
|
113
|
+
for i in range(lo, hi):
|
|
114
|
+
self._lvls[idx] = i
|
|
115
|
+
self._iterate(idx + 1, p * szi + i, None)
|
|
116
|
+
elif fmt == LevelFormat.DELTA:
|
|
117
|
+
assert is_unique(prop)
|
|
118
|
+
pos = self._tensor._pos[idx].tensor
|
|
119
|
+
crd = self._tensor._crd[idx].tensor
|
|
120
|
+
assert pos.ndim == 1 and crd.ndim == 1
|
|
121
|
+
corig = 0
|
|
122
|
+
lo = pos[p].item()
|
|
123
|
+
hi = pos[p + 1].item()
|
|
124
|
+
for i in range(lo, hi):
|
|
125
|
+
corig += crd[i].item()
|
|
126
|
+
self._lvls[idx] = corig
|
|
127
|
+
self._iterate(idx + 1, i, lasta)
|
|
128
|
+
corig += 1
|
|
129
|
+
elif fmt == LevelFormat.STRUCTURED:
|
|
130
|
+
assert isinstance(prop, int) # n is the property
|
|
131
|
+
crd = self._tensor._crd[idx].tensor
|
|
132
|
+
assert crd.ndim == 1
|
|
133
|
+
lo = p * prop
|
|
134
|
+
hi = lo + prop
|
|
135
|
+
for i in range(lo, hi):
|
|
136
|
+
self._lvls[idx] = crd[i].item()
|
|
137
|
+
self._iterate(idx + 1, i, lasta)
|
|
138
|
+
else:
|
|
139
|
+
raise AssertionError(f"Unsupported: {fmt}")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class TensorComposer:
|
|
143
|
+
"""
|
|
144
|
+
A class to build a Universal Sparse Tensor from a coordinate list. This is a convenience
|
|
145
|
+
class for composing UST objects, expected to run on the host, and does not necessarily
|
|
146
|
+
provide the most efficient way of building a UST. Since the builder takes unordered
|
|
147
|
+
dimension indices together with values, it can also be function as intermediate step
|
|
148
|
+
for tensor format conversions.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
source: source tensor
|
|
152
|
+
target: target tensor
|
|
153
|
+
indices: a 2-dim array of shape (dim,nse) with dimension indices (on CPU)
|
|
154
|
+
values: a 1-dim array of shape (nse,) with the stored numerical values (on CPU)
|
|
155
|
+
is_sorted: whether coordinate list is lexicographically sorted
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
def __init__(self, source, target, indices, values, is_sorted=False):
|
|
159
|
+
assert len(indices.shape) == 2 and len(values.shape) == 1, "Internal error."
|
|
160
|
+
fmt = target.tensor_format
|
|
161
|
+
dim, nse = indices.shape
|
|
162
|
+
assert dim == fmt.num_dimensions and nse == values.shape[0]
|
|
163
|
+
lvl = fmt.num_levels
|
|
164
|
+
# Translate dimension indices to level indices.
|
|
165
|
+
if not fmt.is_identity:
|
|
166
|
+
lindices = np.zeros((lvl, nse), dtype=indices.dtype)
|
|
167
|
+
for i in range(nse):
|
|
168
|
+
lindices[:, i] = fmt.dim2lvl(indices[:, i])
|
|
169
|
+
indices = lindices
|
|
170
|
+
is_sorted = False
|
|
171
|
+
# Apply lexicographical sort on level indices.
|
|
172
|
+
if not is_sorted:
|
|
173
|
+
sorted_indices = np.lexsort(indices[::-1])
|
|
174
|
+
indices = indices[:, sorted_indices]
|
|
175
|
+
values = values[sorted_indices]
|
|
176
|
+
# Bookkeeping.
|
|
177
|
+
self._source = source
|
|
178
|
+
self._target = target
|
|
179
|
+
self._lvl = lvl
|
|
180
|
+
self._flist = list(fmt.levels.values())
|
|
181
|
+
self._indices = indices
|
|
182
|
+
self._values = values
|
|
183
|
+
self._pos_sz = np.zeros((lvl,), dtype=indices.dtype)
|
|
184
|
+
self._crd_sz = np.zeros((lvl,), dtype=indices.dtype)
|
|
185
|
+
self._val_sz = 0
|
|
186
|
+
|
|
187
|
+
def run(self, stream=None):
|
|
188
|
+
dim, nse = self._indices.shape
|
|
189
|
+
|
|
190
|
+
# Scan data to find sizes. Note that for some forms (like COO and CSR), all sizes
|
|
191
|
+
# can easily be computed deterministically without a first scan. For simplicity,
|
|
192
|
+
# we use the scan for both analysis and insertion, however.
|
|
193
|
+
self._insert_builder(0, lo=0, hi=nse, is_insert=False)
|
|
194
|
+
|
|
195
|
+
# Pre-allocate and reset sizes.
|
|
196
|
+
package = self._source._dense_tensorholder_type
|
|
197
|
+
device_id = self._source.device_id # no device migration in convert()
|
|
198
|
+
stream_holder = resolve_stream(stream, self._source)
|
|
199
|
+
self._pos = LevelMap()
|
|
200
|
+
self._crd = LevelMap()
|
|
201
|
+
for idx in range(self._lvl):
|
|
202
|
+
self._pos[idx] = utils.create_empty_tensor(
|
|
203
|
+
package,
|
|
204
|
+
extents=(self._pos_sz[idx],),
|
|
205
|
+
dtype=self._target.index_type,
|
|
206
|
+
device_id=device_id,
|
|
207
|
+
stream_holder=stream_holder,
|
|
208
|
+
verify_strides=False,
|
|
209
|
+
)
|
|
210
|
+
self._pos_sz[idx] = 0
|
|
211
|
+
self._crd[idx] = utils.create_empty_tensor(
|
|
212
|
+
package,
|
|
213
|
+
extents=(self._crd_sz[idx],),
|
|
214
|
+
dtype=self._target.index_type,
|
|
215
|
+
device_id=device_id,
|
|
216
|
+
stream_holder=stream_holder,
|
|
217
|
+
verify_strides=False,
|
|
218
|
+
)
|
|
219
|
+
self._crd_sz[idx] = 0
|
|
220
|
+
self._val = utils.create_empty_tensor(
|
|
221
|
+
package,
|
|
222
|
+
extents=(self._val_sz,),
|
|
223
|
+
dtype=self._target.dtype,
|
|
224
|
+
device_id=device_id,
|
|
225
|
+
stream_holder=stream_holder,
|
|
226
|
+
verify_strides=False,
|
|
227
|
+
)
|
|
228
|
+
self._val_sz = 0
|
|
229
|
+
|
|
230
|
+
# Scan to perform the actual insertion.
|
|
231
|
+
with stream_context(stream_holder):
|
|
232
|
+
self._insert_builder(0, lo=0, hi=nse, is_insert=True)
|
|
233
|
+
return (self._pos, self._crd, self._val)
|
|
234
|
+
|
|
235
|
+
def _insert_builder(self, idx, lo, hi, is_insert):
|
|
236
|
+
# All levels exhausted?
|
|
237
|
+
if idx == self._lvl:
|
|
238
|
+
assert lo < hi
|
|
239
|
+
self._append_val(self._values[lo].item(), 1, is_insert)
|
|
240
|
+
return
|
|
241
|
+
# Handle segments.
|
|
242
|
+
fmt = self._get_format(idx)
|
|
243
|
+
rng = hi - lo
|
|
244
|
+
full = 0
|
|
245
|
+
while lo < hi:
|
|
246
|
+
# Find segment.
|
|
247
|
+
crd = self._indices[idx][lo]
|
|
248
|
+
seg = lo + 1
|
|
249
|
+
if is_unique(self._get_prop(idx)):
|
|
250
|
+
while seg < hi and self._indices[idx][seg] == crd:
|
|
251
|
+
seg += 1
|
|
252
|
+
# Handle level format.
|
|
253
|
+
if fmt in (LevelFormat.DENSE, LevelFormat.RANGE):
|
|
254
|
+
assert crd >= full
|
|
255
|
+
if crd > full:
|
|
256
|
+
self._segment_builder(idx + 1, 0, crd - full, is_insert)
|
|
257
|
+
elif fmt in (LevelFormat.COMPRESSED, LevelFormat.SINGLETON):
|
|
258
|
+
self._append_crd(idx, crd, 1, is_insert)
|
|
259
|
+
elif fmt == LevelFormat.DELTA:
|
|
260
|
+
d = self._get_prop(idx)
|
|
261
|
+
assert isinstance(d, int)
|
|
262
|
+
mDelta = (1 << d) - 1
|
|
263
|
+
delta = crd - full
|
|
264
|
+
while delta > mDelta:
|
|
265
|
+
self._append_crd(idx, mDelta, 1, is_insert)
|
|
266
|
+
self._append_val(0, 1, is_insert)
|
|
267
|
+
delta -= mDelta + 1
|
|
268
|
+
self._append_crd(idx, delta, 1, is_insert)
|
|
269
|
+
elif fmt == LevelFormat.STRUCTURED:
|
|
270
|
+
# Pre-correction of N:M strip.
|
|
271
|
+
n = self._get_prop(idx)
|
|
272
|
+
if rng > n:
|
|
273
|
+
raise AssertionError(f"Not structured: more than {n} nonzero elements in a strip")
|
|
274
|
+
while rng < n and full < crd:
|
|
275
|
+
self._append_crd(idx, full, 1, is_insert)
|
|
276
|
+
self._append_val(0, 1, is_insert)
|
|
277
|
+
rng += 1
|
|
278
|
+
full += 1
|
|
279
|
+
self._append_crd(idx, crd, 1, is_insert) # strip insertion
|
|
280
|
+
else:
|
|
281
|
+
# TODO: BATCH
|
|
282
|
+
raise NotImplementedError(f"Unsupported: {fmt}")
|
|
283
|
+
full = crd + 1
|
|
284
|
+
self._insert_builder(idx + 1, lo, seg, is_insert)
|
|
285
|
+
lo = seg # next segment
|
|
286
|
+
# Post-correction of N:M strip.
|
|
287
|
+
if fmt == LevelFormat.STRUCTURED:
|
|
288
|
+
n = self._get_prop(idx)
|
|
289
|
+
if rng > n:
|
|
290
|
+
raise AssertionError(f"Not structured: more than {n} nonzero elements in a strip")
|
|
291
|
+
while rng < n:
|
|
292
|
+
self._append_crd(idx, full, 1, is_insert)
|
|
293
|
+
self._append_val(0, 1, is_insert)
|
|
294
|
+
rng += 1
|
|
295
|
+
full += 1
|
|
296
|
+
# Done with segments.
|
|
297
|
+
self._segment_builder(idx, full, 1, is_insert)
|
|
298
|
+
|
|
299
|
+
def _segment_builder(self, idx, full, repeat, is_insert):
|
|
300
|
+
# All levels exhausted?
|
|
301
|
+
if idx == self._lvl:
|
|
302
|
+
self._append_val(0, repeat, is_insert)
|
|
303
|
+
return
|
|
304
|
+
# Handle level format.
|
|
305
|
+
fmt = self._get_format(idx)
|
|
306
|
+
if fmt in (LevelFormat.DENSE, LevelFormat.RANGE):
|
|
307
|
+
sz = self._target.levels[idx]
|
|
308
|
+
assert sz >= full
|
|
309
|
+
self._segment_builder(idx + 1, 0, repeat * (sz - full), is_insert)
|
|
310
|
+
elif fmt in (LevelFormat.COMPRESSED, LevelFormat.DELTA):
|
|
311
|
+
self._append_pos(idx, self._crd_sz[idx], repeat, is_insert)
|
|
312
|
+
elif fmt == LevelFormat.SINGLETON:
|
|
313
|
+
# TODO: ELL
|
|
314
|
+
pass # nothing to do for singleton
|
|
315
|
+
elif fmt == LevelFormat.STRUCTURED:
|
|
316
|
+
# Correction for all N:M strips that were completely missed.
|
|
317
|
+
if full == 0:
|
|
318
|
+
n = self._get_prop(idx)
|
|
319
|
+
for _r in range(repeat):
|
|
320
|
+
for c in range(n):
|
|
321
|
+
self._append_crd(idx, c, 1, is_insert)
|
|
322
|
+
self._append_val(0, 1, is_insert)
|
|
323
|
+
else:
|
|
324
|
+
# TODO: BATCH
|
|
325
|
+
raise NotImplementedError(f"Unsupported: {fmt}")
|
|
326
|
+
|
|
327
|
+
def _append_pos(self, idx, pos, repeat, is_insert):
|
|
328
|
+
if self._pos_sz[idx] == 0: # append initial 0 at start
|
|
329
|
+
if is_insert:
|
|
330
|
+
self._pos[idx].tensor[0] = 0
|
|
331
|
+
self._pos_sz[idx] = 1
|
|
332
|
+
if is_insert:
|
|
333
|
+
start = self._pos_sz[idx]
|
|
334
|
+
self._pos[idx].tensor[start : start + repeat] = pos
|
|
335
|
+
self._pos_sz[idx] += repeat
|
|
336
|
+
|
|
337
|
+
def _append_crd(self, idx, crd, repeat, is_insert):
|
|
338
|
+
if is_insert:
|
|
339
|
+
start = self._crd_sz[idx]
|
|
340
|
+
self._crd[idx].tensor[start : start + repeat] = crd
|
|
341
|
+
self._crd_sz[idx] += repeat
|
|
342
|
+
|
|
343
|
+
def _append_val(self, val, repeat, is_insert):
|
|
344
|
+
if is_insert:
|
|
345
|
+
start = self._val_sz
|
|
346
|
+
self._val.tensor[start : start + repeat] = val
|
|
347
|
+
self._val_sz += repeat
|
|
348
|
+
|
|
349
|
+
def _get_format(self, idx):
|
|
350
|
+
f = self._flist[idx]
|
|
351
|
+
return f[0] if isinstance(f, tuple) else f
|
|
352
|
+
|
|
353
|
+
def _get_prop(self, idx):
|
|
354
|
+
f = self._flist[idx]
|
|
355
|
+
return f[1] if isinstance(f, tuple) else None
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class TensorConverter:
|
|
359
|
+
"""
|
|
360
|
+
Converts a tensor from one format to another (using the [de]composer). The tensor
|
|
361
|
+
converter reduces the O(n^2) conversion problem into a O(n) problem by using a
|
|
362
|
+
[de]composer that converts to an intermediate coordinate list on the CPU first.
|
|
363
|
+
This class is provided to enable conversions between any UST formats. However,
|
|
364
|
+
this does not necessarily provide the most efficient way of implementing a
|
|
365
|
+
conversion. Fast paths (or library dispatches) can be used for efficiency.
|
|
366
|
+
|
|
367
|
+
CSR\\ //CSR
|
|
368
|
+
CSC \\ // CSC
|
|
369
|
+
UST ... > COO < ... UST
|
|
370
|
+
ELL // on \\ ELL
|
|
371
|
+
DIA// CPU \\DIA
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
source: source tensor
|
|
375
|
+
target: target tensor (partially constructed)
|
|
376
|
+
"""
|
|
377
|
+
|
|
378
|
+
def __init__(self, source, target):
|
|
379
|
+
dim = source.num_dimensions
|
|
380
|
+
nse = source.nse
|
|
381
|
+
# Set fields.
|
|
382
|
+
self._source = source
|
|
383
|
+
self._target = target
|
|
384
|
+
self._indices = np.empty((dim, nse), dtype=target.index_type)
|
|
385
|
+
container_tp = np_enveloping_type(source.dtype)
|
|
386
|
+
self._values = np.empty((nse,), dtype=container_tp)
|
|
387
|
+
self._pos = 0
|
|
388
|
+
|
|
389
|
+
def run(self, stream=None):
|
|
390
|
+
# Intermediate COO is sorted if source format is sorted
|
|
391
|
+
# and uses an identity mapping. This may skip sorted
|
|
392
|
+
# if the target format has the same properties.
|
|
393
|
+
sformat = self._source.tensor_format
|
|
394
|
+
is_sorted = sformat.is_ordered and sformat.is_identity
|
|
395
|
+
|
|
396
|
+
# Run the decomposer and composer.
|
|
397
|
+
TensorDecomposer(self._source, self._visit).run(stream=stream)
|
|
398
|
+
pos, crd, val = TensorComposer(
|
|
399
|
+
self._source,
|
|
400
|
+
self._target,
|
|
401
|
+
self._indices[:, : self._pos],
|
|
402
|
+
self._values[: self._pos],
|
|
403
|
+
is_sorted,
|
|
404
|
+
).run(stream=stream)
|
|
405
|
+
|
|
406
|
+
# Set directly (converter knows about UST conventions).
|
|
407
|
+
for idx in range(self._target.num_levels):
|
|
408
|
+
p = pos.get(idx)
|
|
409
|
+
if p is not None:
|
|
410
|
+
self._target._pos[idx] = wrap_operand(p)
|
|
411
|
+
c = crd.get(idx)
|
|
412
|
+
if c is not None:
|
|
413
|
+
self._target._crd[idx] = wrap_operand(c)
|
|
414
|
+
self._target._val = wrap_operand(val)
|
|
415
|
+
|
|
416
|
+
def _visit(self, dims, val):
|
|
417
|
+
if val == 0:
|
|
418
|
+
return # drop zeros (e.g. from dense or padding)
|
|
419
|
+
pos = self._pos
|
|
420
|
+
self._pos += 1
|
|
421
|
+
self._indices[:, pos] = dims[:]
|
|
422
|
+
self._values[pos] = val
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
This module defines C++ source code used by the UST.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = []
|
|
10
|
+
|
|
11
|
+
prolog_decl = """
|
|
12
|
+
extern "C" __device__ CTP prolog_a(CTP);
|
|
13
|
+
extern "C" __device__ CTP prolog_b(CTP);
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
prolog_a_impl = """
|
|
17
|
+
extern "C" __device__
|
|
18
|
+
CTP prolog_a(CTP a) {
|
|
19
|
+
return a;
|
|
20
|
+
}
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
prolog_b_impl = """
|
|
24
|
+
extern "C" __device__
|
|
25
|
+
CTP prolog_b(CTP b) {
|
|
26
|
+
return b;
|
|
27
|
+
}
|
|
28
|
+
"""
|