nvmath-python 0.9.0__cp314-cp314-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.
Files changed (309) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +45 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/attribute_ifc_factory.py +330 -0
  5. nvmath/_internal/layout.py +70 -0
  6. nvmath/_internal/templates.py +383 -0
  7. nvmath/_utils.py +150 -0
  8. nvmath/bindings/__init__.py +51 -0
  9. nvmath/bindings/_internal/__init__.pxd +0 -0
  10. nvmath/bindings/_internal/__init__.py +0 -0
  11. nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
  12. nvmath/bindings/_internal/cublas.pxd +530 -0
  13. nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
  14. nvmath/bindings/_internal/cublasLt.pxd +59 -0
  15. nvmath/bindings/_internal/cublasMp.pxd +52 -0
  16. nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
  17. nvmath/bindings/_internal/cudss.pxd +47 -0
  18. nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
  19. nvmath/bindings/_internal/cufft.pxd +70 -0
  20. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  21. nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
  22. nvmath/bindings/_internal/curand.pxd +42 -0
  23. nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
  24. nvmath/bindings/_internal/cusolver.pxd +15 -0
  25. nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/cusolverDn.pxd +406 -0
  27. nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/cusparse.pxd +277 -0
  29. nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
  30. nvmath/bindings/_internal/cusparseLt.pxd +48 -0
  31. nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
  32. nvmath/bindings/_internal/cutensor.pxd +58 -0
  33. nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
  34. nvmath/bindings/_internal/mathdx.pxd +116 -0
  35. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  36. nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
  37. nvmath/bindings/_internal/utils.pxd +179 -0
  38. nvmath/bindings/_internal/utils.pyi +10 -0
  39. nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
  40. nvmath/bindings/cublas.pxd +558 -0
  41. nvmath/bindings/cublas.pyi +746 -0
  42. nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
  43. nvmath/bindings/cublasLt.pxd +109 -0
  44. nvmath/bindings/cublasLt.pyi +1337 -0
  45. nvmath/bindings/cublasMp.pxd +85 -0
  46. nvmath/bindings/cublasMp.pyi +219 -0
  47. nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
  48. nvmath/bindings/cudss.pxd +86 -0
  49. nvmath/bindings/cudss.pyi +282 -0
  50. nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
  51. nvmath/bindings/cufft.pxd +118 -0
  52. nvmath/bindings/cufft.pyi +241 -0
  53. nvmath/bindings/cufftMp.pxd +124 -0
  54. nvmath/bindings/cufftMp.pyi +260 -0
  55. nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
  56. nvmath/bindings/curand.pxd +71 -0
  57. nvmath/bindings/curand.pyi +159 -0
  58. nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
  59. nvmath/bindings/cusolver.pxd +62 -0
  60. nvmath/bindings/cusolver.pyi +242 -0
  61. nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
  62. nvmath/bindings/cusolverDn.pxd +430 -0
  63. nvmath/bindings/cusolverDn.pyi +416 -0
  64. nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
  65. nvmath/bindings/cusparse.pxd +338 -0
  66. nvmath/bindings/cusparse.pyi +659 -0
  67. nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
  68. nvmath/bindings/cusparseLt.pxd +99 -0
  69. nvmath/bindings/cusparseLt.pyi +198 -0
  70. nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
  71. nvmath/bindings/cutensor.pxd +98 -0
  72. nvmath/bindings/cutensor.pyi +294 -0
  73. nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
  74. nvmath/bindings/cycublas.pxd +684 -0
  75. nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
  76. nvmath/bindings/cycublasLt.pxd +1055 -0
  77. nvmath/bindings/cycublasMp.pxd +183 -0
  78. nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
  79. nvmath/bindings/cycudss.pxd +224 -0
  80. nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
  81. nvmath/bindings/cycufft.pxd +326 -0
  82. nvmath/bindings/cycufftMp.pxd +334 -0
  83. nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
  84. nvmath/bindings/cycurand.pxd +146 -0
  85. nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
  86. nvmath/bindings/cycusolver.pxd +154 -0
  87. nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
  88. nvmath/bindings/cycusolverDn.pxd +446 -0
  89. nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
  90. nvmath/bindings/cycusparse.pxd +470 -0
  91. nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
  92. nvmath/bindings/cycusparseLt.pxd +150 -0
  93. nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
  94. nvmath/bindings/cycutensor.pxd +192 -0
  95. nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
  96. nvmath/bindings/cymathdx.pxd +552 -0
  97. nvmath/bindings/cynvshmem.pxd +126 -0
  98. nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
  99. nvmath/bindings/mathdx.pxd +182 -0
  100. nvmath/bindings/mathdx.pyi +1244 -0
  101. nvmath/bindings/nvpl/__init__.pxd +0 -0
  102. nvmath/bindings/nvpl/__init__.py +13 -0
  103. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  104. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  105. nvmath/bindings/nvpl/_internal/blas.cp314-win_amd64.pyd +0 -0
  106. nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
  107. nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
  108. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  109. nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
  110. nvmath/bindings/nvpl/blas.pxd +85 -0
  111. nvmath/bindings/nvpl/blas.pyi +122 -0
  112. nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
  113. nvmath/bindings/nvpl/cyblas.pxd +166 -0
  114. nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
  115. nvmath/bindings/nvpl/cyfft.pxd +92 -0
  116. nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
  117. nvmath/bindings/nvpl/fft.pxd +100 -0
  118. nvmath/bindings/nvpl/fft.pyi +100 -0
  119. nvmath/bindings/nvshmem.pxd +54 -0
  120. nvmath/bindings/nvshmem.pyi +179 -0
  121. nvmath/device/__init__.py +21 -0
  122. nvmath/device/_deprecated.py +33 -0
  123. nvmath/device/common.py +313 -0
  124. nvmath/device/common_backend.py +131 -0
  125. nvmath/device/common_cuda.py +201 -0
  126. nvmath/device/common_numba.py +310 -0
  127. nvmath/device/common_opaque_tensor.py +201 -0
  128. nvmath/device/cublasdx.py +1805 -0
  129. nvmath/device/cublasdx_backend.py +807 -0
  130. nvmath/device/cublasdx_numba.py +1612 -0
  131. nvmath/device/cufftdx.py +510 -0
  132. nvmath/device/cufftdx_backend.py +196 -0
  133. nvmath/device/cufftdx_numba.py +196 -0
  134. nvmath/device/curand_kernel.py +9147 -0
  135. nvmath/device/cusolverdx.py +2690 -0
  136. nvmath/device/cusolverdx_backend.py +440 -0
  137. nvmath/device/cusolverdx_numba.py +1624 -0
  138. nvmath/device/llvm_array.py +29 -0
  139. nvmath/device/random.py +445 -0
  140. nvmath/device/random_helpers.py +23 -0
  141. nvmath/device/random_states.py +187 -0
  142. nvmath/device/types.py +147 -0
  143. nvmath/device/vector_types_numba.py +203 -0
  144. nvmath/distributed/__init__.py +205 -0
  145. nvmath/distributed/_internal/__init__.py +0 -0
  146. nvmath/distributed/_internal/nvshmem.py +302 -0
  147. nvmath/distributed/_internal/tensor_ifc.py +67 -0
  148. nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
  149. nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
  150. nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
  151. nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
  152. nvmath/distributed/_internal/tensor_wrapper.py +78 -0
  153. nvmath/distributed/_utils.py +167 -0
  154. nvmath/distributed/distribution.py +770 -0
  155. nvmath/distributed/fft/__init__.py +7 -0
  156. nvmath/distributed/fft/_configuration.py +79 -0
  157. nvmath/distributed/fft/fft.py +2801 -0
  158. nvmath/distributed/linalg/__init__.py +12 -0
  159. nvmath/distributed/linalg/_internal/__init__.py +3 -0
  160. nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -0
  161. nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
  162. nvmath/distributed/linalg/advanced/__init__.py +8 -0
  163. nvmath/distributed/linalg/advanced/_configuration.py +166 -0
  164. nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
  165. nvmath/distributed/process_group.py +408 -0
  166. nvmath/distributed/reshape/__init__.py +6 -0
  167. nvmath/distributed/reshape/_configuration.py +39 -0
  168. nvmath/distributed/reshape/reshape.py +1256 -0
  169. nvmath/fft/__init__.py +7 -0
  170. nvmath/fft/_configuration.py +208 -0
  171. nvmath/fft/_exec_utils.py +109 -0
  172. nvmath/fft/_helpers.py +237 -0
  173. nvmath/fft/fft.py +2903 -0
  174. nvmath/internal/__init__.pxd +3 -0
  175. nvmath/internal/__init__.py +10 -0
  176. nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
  177. nvmath/internal/_bindings.pxd +12 -0
  178. nvmath/internal/_device_utils.py +54 -0
  179. nvmath/internal/enum_utils.py +142 -0
  180. nvmath/internal/formatters.py +87 -0
  181. nvmath/internal/mem_limit.py +51 -0
  182. nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
  183. nvmath/internal/memory.pxd +10 -0
  184. nvmath/internal/memory.pyi +46 -0
  185. nvmath/internal/ndbuffer/__init__.pxd +3 -0
  186. nvmath/internal/ndbuffer/__init__.py +7 -0
  187. nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
  188. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
  189. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
  190. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
  191. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +240 -0
  192. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
  193. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
  194. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
  195. nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
  196. nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
  197. nvmath/internal/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
  198. nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
  199. nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
  200. nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
  201. nvmath/internal/ndbuffer/data_layout.pxd +72 -0
  202. nvmath/internal/ndbuffer/data_layout.pyi +23 -0
  203. nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
  204. nvmath/internal/ndbuffer/jit.pxd +7 -0
  205. nvmath/internal/ndbuffer/jit.pyi +6 -0
  206. nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
  207. nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
  208. nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
  209. nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
  210. nvmath/internal/ndbuffer/package_utils.pxd +11 -0
  211. nvmath/internal/ndbuffer/package_utils.pyi +12 -0
  212. nvmath/internal/package_ifc.py +147 -0
  213. nvmath/internal/package_ifc_cuda.py +49 -0
  214. nvmath/internal/package_ifc_cupy.py +49 -0
  215. nvmath/internal/package_ifc_torch.py +31 -0
  216. nvmath/internal/package_wrapper.py +14 -0
  217. nvmath/internal/tensor_ifc.py +194 -0
  218. nvmath/internal/tensor_ifc_cupy.py +241 -0
  219. nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
  220. nvmath/internal/tensor_ifc_numpy.py +183 -0
  221. nvmath/internal/tensor_ifc_torch.py +176 -0
  222. nvmath/internal/tensor_wrapper.py +157 -0
  223. nvmath/internal/typemaps.py +162 -0
  224. nvmath/internal/utils.py +771 -0
  225. nvmath/linalg/__init__.py +46 -0
  226. nvmath/linalg/_internal/__init__.py +3 -0
  227. nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
  228. nvmath/linalg/_internal/algo_config_ifc.py +43 -0
  229. nvmath/linalg/_internal/batch.py +217 -0
  230. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  231. nvmath/linalg/_internal/epilog_protocol.py +766 -0
  232. nvmath/linalg/_internal/layout.py +624 -0
  233. nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
  234. nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
  235. nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
  236. nvmath/linalg/_internal/typemaps.py +144 -0
  237. nvmath/linalg/_internal/utils.py +134 -0
  238. nvmath/linalg/advanced/__init__.py +8 -0
  239. nvmath/linalg/advanced/_algorithmmod.py +149 -0
  240. nvmath/linalg/advanced/_configuration.py +349 -0
  241. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  242. nvmath/linalg/advanced/helpers/matmul.py +1348 -0
  243. nvmath/linalg/advanced/matmulmod.py +3937 -0
  244. nvmath/linalg/generic/__init__.py +43 -0
  245. nvmath/linalg/generic/_configuration/__init__.py +37 -0
  246. nvmath/linalg/generic/_configuration/layout.py +263 -0
  247. nvmath/linalg/generic/_configuration/match.py +609 -0
  248. nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
  249. nvmath/linalg/generic/_configuration/wrap.py +217 -0
  250. nvmath/linalg/generic/_dtype.py +15 -0
  251. nvmath/linalg/generic/matmulmod.py +1060 -0
  252. nvmath/memory.py +282 -0
  253. nvmath/sparse/__init__.py +38 -0
  254. nvmath/sparse/_internal/__init__.py +21 -0
  255. nvmath/sparse/_internal/common_utils.py +144 -0
  256. nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
  257. nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
  258. nvmath/sparse/_internal/cudss_utils.py +445 -0
  259. nvmath/sparse/_internal/cusparse_utils.py +382 -0
  260. nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
  261. nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
  262. nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
  263. nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
  264. nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
  265. nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
  266. nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
  267. nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
  268. nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
  269. nvmath/sparse/_internal/utils.py +56 -0
  270. nvmath/sparse/advanced/__init__.py +7 -0
  271. nvmath/sparse/advanced/_configuration.py +230 -0
  272. nvmath/sparse/advanced/direct_solver.py +1884 -0
  273. nvmath/sparse/generic/__init__.py +7 -0
  274. nvmath/sparse/generic/_configuration.py +129 -0
  275. nvmath/sparse/generic/_helpers.py +137 -0
  276. nvmath/sparse/generic/_thunks.py +21 -0
  277. nvmath/sparse/generic/matmulmod.py +2426 -0
  278. nvmath/sparse/ust/__init__.py +7 -0
  279. nvmath/sparse/ust/_converters.py +378 -0
  280. nvmath/sparse/ust/_drawer.py +552 -0
  281. nvmath/sparse/ust/_emitter.py +553 -0
  282. nvmath/sparse/ust/_jit.py +212 -0
  283. nvmath/sparse/ust/_kernel.py +346 -0
  284. nvmath/sparse/ust/_semiring.py +71 -0
  285. nvmath/sparse/ust/_utils.py +102 -0
  286. nvmath/sparse/ust/interfaces/__init__.py +0 -0
  287. nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
  288. nvmath/sparse/ust/semiring_ops.py +71 -0
  289. nvmath/sparse/ust/tensor.py +1027 -0
  290. nvmath/sparse/ust/tensor_drawer.py +552 -0
  291. nvmath/sparse/ust/tensor_emitter.py +558 -0
  292. nvmath/sparse/ust/tensor_format.py +935 -0
  293. nvmath/sparse/ust/tensor_jit.py +212 -0
  294. nvmath/sparse/ust/tensor_kernel.py +348 -0
  295. nvmath/sparse/ust/tensor_utils.py +380 -0
  296. nvmath/tensor/__init__.py +6 -0
  297. nvmath/tensor/_configuration.py +95 -0
  298. nvmath/tensor/_internal/__init__.py +3 -0
  299. nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
  300. nvmath/tensor/_internal/cutensor_utils.py +162 -0
  301. nvmath/tensor/_internal/data.py +43 -0
  302. nvmath/tensor/_internal/einsum_parser.py +444 -0
  303. nvmath/tensor/_internal/typemaps.py +96 -0
  304. nvmath/tensor/contract.py +1861 -0
  305. nvmath_python-0.9.0.dist-info/METADATA +127 -0
  306. nvmath_python-0.9.0.dist-info/RECORD +309 -0
  307. nvmath_python-0.9.0.dist-info/WHEEL +5 -0
  308. nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
  309. nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from . import interfaces as interfaces
6
+ from .tensor import * # noqa: F403
7
+ from .tensor_format import * # noqa: F403
@@ -0,0 +1,378 @@
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
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):
42
+ self._iterate(0, 0, None)
43
+
44
+ def _iterate(self, idx, p, lasta):
45
+ # All levels exhausted?
46
+ if idx == self._tensor.num_levels:
47
+ assert lasta is None # consumed add/sub in range
48
+ val = self._tensor.val.tensor
49
+ self._functor(self._tensor.tensor_format.lvl2dim(self._lvls), val[p].item())
50
+ return
51
+ # Inspect level.
52
+ k, v = self._flist[idx]
53
+ if isinstance(v, Sequence):
54
+ fmt, prop = v
55
+ else:
56
+ fmt, prop = v, None
57
+ # Handle level format.
58
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH:
59
+ sz = self._tensor.levels[idx]
60
+ for i in range(sz):
61
+ self._lvls[idx] = i
62
+ self._iterate(idx + 1, p * sz + i, lasta)
63
+ elif fmt == LevelFormat.COMPRESSED:
64
+ if isinstance(k, LevelExpr) and isinstance(k.operator, (Add, Subtract)):
65
+ assert lasta is None # no add/sub nesting
66
+ lasta = idx # record last add/sub
67
+ pos = self._tensor.pos(idx).tensor
68
+ crd = self._tensor.crd(idx).tensor
69
+ assert pos.ndim == crd.ndim
70
+ adjust = 0
71
+ if pos.ndim > 1:
72
+ # This only happens for prior BATCH. Correct the higher-dimensions in
73
+ # both pos and crd buffers and adjust position by #nnz per batch.
74
+ assert pos.ndim == idx
75
+ for i in range(idx - 1):
76
+ assert self._flist[i][1] == LevelFormat.BATCH
77
+ pos = pos[self._lvls[i]]
78
+ crd = crd[self._lvls[i]]
79
+ adjust = pos[-1].item() * (p - self._lvls[idx - 1]) // self._tensor.levels[idx - 1]
80
+ p = self._lvls[idx - 1]
81
+ lo = pos[p].item()
82
+ hi = pos[p + 1].item()
83
+ for i in range(lo, hi):
84
+ self._lvls[idx] = crd[i].item()
85
+ self._iterate(idx + 1, i + adjust, lasta)
86
+ elif fmt == LevelFormat.SINGLETON:
87
+ crd = self._tensor.crd(idx).tensor
88
+ assert crd.ndim == 1
89
+ self._lvls[idx] = crd[p].item()
90
+ self._iterate(idx + 1, p, lasta)
91
+ elif fmt == LevelFormat.RANGE:
92
+ assert lasta is not None # single add/sub-range relation
93
+ add, _ = self._flist[lasta]
94
+ isI = k == add.expression2
95
+ di = self._tensor.tensor_format.dimensions.index(k)
96
+ dj = self._tensor.tensor_format.dimensions.index(add.expression1 if isI else add.expression2)
97
+ szi = self._tensor.extents[di]
98
+ szj = self._tensor.extents[dj]
99
+ lsz = self._lvls[lasta]
100
+ if isinstance(add.operator, Add):
101
+ off = lsz
102
+ lo = max(0, off - szj + 1)
103
+ hi = min(szi, off + 1)
104
+ else:
105
+ off = -lsz if isI else lsz
106
+ lo = max(0, off)
107
+ hi = min(szi, szj + off)
108
+ for i in range(lo, hi):
109
+ self._lvls[idx] = i
110
+ self._iterate(idx + 1, p * szi + i, None)
111
+ elif fmt == LevelFormat.DELTA:
112
+ assert is_unique(prop)
113
+ pos = self._tensor.pos(idx).tensor
114
+ crd = self._tensor.crd(idx).tensor
115
+ assert pos.ndim == 1 and crd.ndim == 1
116
+ corig = 0
117
+ lo = pos[p].item()
118
+ hi = pos[p + 1].item()
119
+ for i in range(lo, hi):
120
+ corig += crd[i].item()
121
+ self._lvls[idx] = corig
122
+ self._iterate(idx + 1, i, lasta)
123
+ corig += 1
124
+ else:
125
+ raise AssertionError(f"Unsupported: {fmt}")
126
+
127
+
128
+ class TensorComposer:
129
+ """
130
+ A class to build a Universal Sparse Tensor from a coordinate list. This is a convenience
131
+ class for composing UST objects, expected to run on the host, and does not necessarily
132
+ provide the most efficient way of building a UST. Since the builder takes unordered
133
+ dimension indices together with values, it can also be function as intermediate step
134
+ for tensor format conversions.
135
+
136
+ Args:
137
+ source: source tensor
138
+ target: target tensor
139
+ indices: a 2-dim array of shape (dim,nse) with dimension indices (on CPU)
140
+ values: a 1-dim array of shape (nse,) with the stored numerical values (on CPU)
141
+ is_sorted: whether coordinate list is lexicographically sorted
142
+ """
143
+
144
+ def __init__(self, source, target, indices, values, is_sorted=False):
145
+ assert len(indices.shape) == 2 and len(values.shape) == 1, "Internal error."
146
+ fmt = target.tensor_format
147
+ dim, nse = indices.shape
148
+ assert dim == fmt.num_dimensions and nse == values.shape[0]
149
+ lvl = fmt.num_levels
150
+ # Translate dimension indices to level indices.
151
+ if not fmt.is_identity:
152
+ lindices = np.zeros((lvl, nse), dtype=indices.dtype)
153
+ for i in range(nse):
154
+ lindices[:, i] = fmt.dim2lvl(indices[:, i])
155
+ indices = lindices
156
+ is_sorted = False
157
+ # Apply lexicographical sort on level indices.
158
+ if not is_sorted:
159
+ sorted_indices = np.lexsort(indices[::-1])
160
+ indices = indices[:, sorted_indices]
161
+ values = values[sorted_indices]
162
+ # Bookkeeping.
163
+ self._source = source
164
+ self._target = target
165
+ self._lvl = lvl
166
+ self._flist = list(fmt.levels.values())
167
+ self._indices = indices
168
+ self._values = values
169
+ self._pos_sz = np.zeros((lvl,), dtype=indices.dtype)
170
+ self._crd_sz = np.zeros((lvl,), dtype=indices.dtype)
171
+ self._val_sz = 0
172
+
173
+ def run(self, stream=None):
174
+ dim, nse = self._indices.shape
175
+
176
+ # Scan data to find sizes. Note that for some forms (like COO and CSR), all sizes
177
+ # can easily be computed deterministically without a first scan. For simplicity,
178
+ # we use the scan for both analysis and insertion, however.
179
+ self._insert_builder(0, lo=0, hi=nse, is_insert=False)
180
+
181
+ # Pre-allocate and reset sizes.
182
+ package = self._source._dense_tensorholder_type
183
+ device_id = self._source.device_id # no device migration in convert()
184
+ stream_holder = None
185
+ if device_id != "cpu":
186
+ stream_holder = utils.get_or_create_stream(device_id, stream, package.name)
187
+ self._pos = LevelMap()
188
+ self._crd = LevelMap()
189
+ for idx in range(self._lvl):
190
+ self._pos[idx] = utils.create_empty_tensor(
191
+ package,
192
+ extents=(self._pos_sz[idx],),
193
+ dtype=self._target.index_type,
194
+ device_id=device_id,
195
+ stream_holder=stream_holder,
196
+ verify_strides=False,
197
+ )
198
+ self._pos_sz[idx] = 0
199
+ self._crd[idx] = utils.create_empty_tensor(
200
+ package,
201
+ extents=(self._crd_sz[idx],),
202
+ dtype=self._target.index_type,
203
+ device_id=device_id,
204
+ stream_holder=stream_holder,
205
+ verify_strides=False,
206
+ )
207
+ self._crd_sz[idx] = 0
208
+ self._val = utils.create_empty_tensor(
209
+ package,
210
+ extents=(self._val_sz,),
211
+ dtype=self._target.dtype,
212
+ device_id=device_id,
213
+ stream_holder=stream_holder,
214
+ verify_strides=False,
215
+ )
216
+ self._val_sz = 0
217
+
218
+ # Scan to perform the actual insertion.
219
+ self._insert_builder(0, lo=0, hi=nse, is_insert=True)
220
+ return (self._pos, self._crd, self._val)
221
+
222
+ def _insert_builder(self, idx, lo, hi, is_insert):
223
+ # All levels exhausted?
224
+ if idx == self._lvl:
225
+ assert lo < hi
226
+ self._append_val(self._values[lo].item(), 1, is_insert)
227
+ return
228
+ # Handle segments.
229
+ full = 0
230
+ while lo < hi:
231
+ # Find segment.
232
+ crd = self._indices[idx][lo]
233
+ seg = lo + 1
234
+ if is_unique(self._get_prop(idx)):
235
+ while seg < hi and self._indices[idx][seg] == crd:
236
+ seg += 1
237
+ # Handle level format.
238
+ fmt = self._get_format(idx)
239
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.RANGE:
240
+ assert crd >= full
241
+ if crd > full:
242
+ self._segment_builder(idx + 1, 0, crd - full, is_insert)
243
+ elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.SINGLETON:
244
+ self._append_crd(idx, crd, 1, is_insert)
245
+ elif fmt == LevelFormat.DELTA:
246
+ d = self._get_prop(idx)
247
+ assert isinstance(d, int)
248
+ mDelta = (1 << d) - 1
249
+ delta = crd - full
250
+ while delta > mDelta:
251
+ self._append_crd(idx, mDelta, 1, is_insert)
252
+ self._append_val(0, 1, is_insert)
253
+ delta -= mDelta + 1
254
+ self._append_crd(idx, delta, 1, is_insert)
255
+ else:
256
+ # TODO: BATCH
257
+ raise NotImplementedError(f"Unsupported: {fmt}")
258
+ full = crd + 1
259
+ self._insert_builder(idx + 1, lo, seg, is_insert)
260
+ lo = seg # next segment
261
+ # Done with segments.
262
+ self._segment_builder(idx, full, 1, is_insert)
263
+
264
+ def _segment_builder(self, idx, full, repeat, is_insert):
265
+ # All levels exhausted?
266
+ if idx == self._lvl:
267
+ self._append_val(0, repeat, is_insert)
268
+ return
269
+ # Handle level format.
270
+ fmt = self._get_format(idx)
271
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.RANGE:
272
+ sz = self._target.levels[idx]
273
+ assert sz >= full
274
+ self._segment_builder(idx + 1, 0, repeat * (sz - full), is_insert)
275
+ elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.DELTA:
276
+ self._append_pos(idx, self._crd_sz[idx], repeat, is_insert)
277
+ elif fmt == LevelFormat.SINGLETON:
278
+ pass # nothing to do for singleton
279
+ else:
280
+ # TODO: BATCH
281
+ raise NotImplementedError(f"Unsupported: {fmt}")
282
+
283
+ def _append_pos(self, idx, pos, repeat, is_insert):
284
+ if self._pos_sz[idx] == 0: # append initial 0 at start
285
+ if is_insert:
286
+ self._pos[idx].tensor[0] = 0
287
+ self._pos_sz[idx] = 1
288
+ if is_insert:
289
+ start = self._pos_sz[idx]
290
+ self._pos[idx].tensor[start : start + repeat] = pos
291
+ self._pos_sz[idx] += repeat
292
+
293
+ def _append_crd(self, idx, crd, repeat, is_insert):
294
+ if is_insert:
295
+ start = self._crd_sz[idx]
296
+ self._crd[idx].tensor[start : start + repeat] = crd
297
+ self._crd_sz[idx] += repeat
298
+
299
+ def _append_val(self, val, repeat, is_insert):
300
+ if is_insert:
301
+ start = self._val_sz
302
+ self._val.tensor[start : start + repeat] = val
303
+ self._val_sz += repeat
304
+
305
+ def _get_format(self, idx):
306
+ f = self._flist[idx]
307
+ return f[0] if isinstance(f, tuple) else f
308
+
309
+ def _get_prop(self, idx):
310
+ f = self._flist[idx]
311
+ return f[1] if isinstance(f, tuple) else None
312
+
313
+
314
+ class TensorConverter:
315
+ """
316
+ Converts a tensor from one format to another (using the [de]composer). The tensor
317
+ converter reduces the O(n^2) conversion problem into a O(n) problem by using a
318
+ [de]composer that converts to an intermediate coordinate list on the CPU first.
319
+ This class is provided to enable conversions between any UST formats. However,
320
+ this does not necessarily provide the most efficient way of implementing a
321
+ conversion. Fast paths (or library dispatches) can be used for efficiency.
322
+
323
+ CSR\\ //CSR
324
+ CSC \\ // CSC
325
+ UST ... > COO < ... UST
326
+ ELL // on \\ ELL
327
+ DIA// CPU \\DIA
328
+
329
+ Args:
330
+ source: source tensor
331
+ target: target tensor (partially constructed)
332
+ """
333
+
334
+ def __init__(self, source, target):
335
+ dim = source.num_dimensions
336
+ nse = source.nse
337
+ # Set fields.
338
+ self._source = source
339
+ self._target = target
340
+ self._indices = np.empty((dim, nse), dtype=target.index_type)
341
+ container_tp = np_enveloping_type(source.dtype)
342
+ self._values = np.empty((nse,), dtype=container_tp)
343
+ self._pos = 0
344
+
345
+ def run(self, stream=None):
346
+ # Intermediate COO is sorted if source format is sorted
347
+ # and uses an identity mapping. This may skip sorted
348
+ # if the target format has the same properties.
349
+ sformat = self._source.tensor_format
350
+ is_sorted = sformat.is_ordered and sformat.is_identity
351
+
352
+ # Run the decomposer and composer.
353
+ TensorDecomposer(self._source, self._visit).run()
354
+ pos, crd, val = TensorComposer(
355
+ self._source,
356
+ self._target,
357
+ self._indices[:, : self._pos],
358
+ self._values[: self._pos],
359
+ is_sorted,
360
+ ).run(stream=stream)
361
+
362
+ # Set directly (converter knows about UST conventions).
363
+ for idx in range(self._target.num_levels):
364
+ p = pos.get(idx)
365
+ if p is not None:
366
+ self._target._pos[idx] = wrap_operand(p)
367
+ c = crd.get(idx)
368
+ if c is not None:
369
+ self._target._crd[idx] = wrap_operand(c)
370
+ self._target._val = wrap_operand(val)
371
+
372
+ def _visit(self, dims, val):
373
+ if val == 0:
374
+ return # drop zeros (e.g. from dense or padding)
375
+ pos = self._pos
376
+ self._pos += 1
377
+ self._indices[:, pos] = dims[:]
378
+ self._values[pos] = val