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,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 BSR tensors from different libraries.
7
+ """
8
+
9
+ from __future__ import annotations # allows typehint of class methods to return the self class
10
+
11
+ __all__ = ["BSRTensorHolder"]
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 BSRTensor which a BSRTensorHolder implementation wraps
25
+ around.
26
+ """
27
+ BSRTensor = TypeVar("BSRTensor")
28
+
29
+
30
+ class BSRTensorHolder(SparseTensorHolder):
31
+ """
32
+ A simple wrapper type for BSR 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 = "BSR"
41
+
42
+ def __init__(
43
+ self, block_size, block_order, crow_indices, col_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(crow_indices, TensorHolder):
67
+ crow_indices = tensor_wrapper.wrap_operand(crow_indices)
68
+
69
+ if not isinstance(col_indices, TensorHolder):
70
+ col_indices = tensor_wrapper.wrap_operand(col_indices)
71
+
72
+ if not isinstance(values, TensorHolder):
73
+ values = tensor_wrapper.wrap_operand(values)
74
+
75
+ # The wrapped constituent dense tensors.
76
+ self._crow_indices = crow_indices
77
+ self._col_indices = col_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._crow_indices, self._col_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
+ crow_indices = attr_name_map["crow_indices"](tensor)
104
+ col_indices = attr_name_map["col_indices"](tensor)
105
+ values = attr_name_map["values"](tensor)
106
+ return BSRTensorHolder(
107
+ block_size, block_order, crow_indices, col_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._crow_indices.dtype
129
+
130
+ @property
131
+ def format_name(self) -> str:
132
+ return BSRTensorHolder._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 crow_indices(self) -> TensorHolder:
152
+ """The TensorHolder object wrapping the crow_indices array."""
153
+ return self._crow_indices
154
+
155
+ @property
156
+ def col_indices(self) -> TensorHolder:
157
+ """The TensorHolder object wrapping the col_indices array."""
158
+ return self._col_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 BSRTensor representation to a different device.
167
+
168
+ No copy is performed if the BSRTensor is already on the requested device.
169
+ """
170
+
171
+ target_crow_indices = self.crow_indices.to(device_id=device_id, stream_holder=stream_holder)
172
+ target_col_indices = self.col_indices.to(device_id=device_id, stream_holder=stream_holder)
173
+ target_values = self.values.to(device_id=device_id, stream_holder=stream_holder)
174
+
175
+ return BSRTensorHolder(
176
+ self.block_size,
177
+ self.block_order,
178
+ target_crow_indices,
179
+ target_col_indices,
180
+ target_values,
181
+ attr_name_map=self.attr_name_map,
182
+ shape=self.shape,
183
+ )
184
+
185
+ def copy_(self, src, stream_holder: StreamHolder | None) -> None:
186
+ """Overwrite self.tensor (in-place) with a copy of src (BSRTensor)."""
187
+
188
+ self._block_size = src.block_size
189
+ self._block_order = src.block_order
190
+ self.crow_indices.copy_(src=src.crow_indices, stream_holder=stream_holder)
191
+ self.col_indices.copy_(src=src.col_indices, stream_holder=stream_holder)
192
+ self.values.copy_(src=src.values, stream_holder=stream_holder)
193
+
194
+ def to_ust(self, *, stream):
195
+ from nvmath.sparse.ust.tensor import Tensor
196
+ from nvmath.sparse.ust.tensor_format import NamedFormats
197
+
198
+ wrapped = self
199
+ tensor = wrapped.tensor
200
+ if not (wrapped.attr_name_map["is_coalesced"](tensor) and wrapped.attr_name_map["has_sorted_indices"](tensor)):
201
+ raise ValueError(
202
+ "The BSR tensor is not coalesced (metadata sorted with duplicates removed). \
203
+ To coalesce, use the operation provided by your sparse tensor library: `coalesce()`, `sum_duplicates()`, ..."
204
+ )
205
+
206
+ if not (
207
+ is_contiguous_and_dense(wrapped.crow_indices.shape, wrapped.crow_indices.strides)
208
+ and is_contiguous_and_dense(wrapped.col_indices.shape, wrapped.col_indices.strides)
209
+ and is_contiguous_and_dense(wrapped.values.shape, wrapped.values.strides)
210
+ ):
211
+ raise ValueError(
212
+ "The sparse tensor representation (crow_indices(), col_indices(), and values() tensors) must be \
213
+ dense and contiguous."
214
+ )
215
+
216
+ values = wrapped.values.memory_buffer() # Typed memory viewed as a 1-D tensor.
217
+
218
+ num_dim = self.num_dimensions
219
+ num_sparse_dim = self.attr_name_map["num_sparse_dim"](tensor)
220
+ num_dense_dim = self.attr_name_map["num_dense_dim"](tensor)
221
+ num_batch_dim = num_dim - num_sparse_dim - num_dense_dim
222
+
223
+ if wrapped.block_order == "left" and num_batch_dim > 0:
224
+ raise ValueError("The 'left' block layout is not currently supported for batched BSR UST.")
225
+
226
+ block_size = wrapped.block_size
227
+ tensor_format = (
228
+ NamedFormats.BSRLeft(block_size)
229
+ if wrapped.block_order == "left"
230
+ else NamedFormats.BSRRightd(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.crow_indices.strides[:num_batch_dim], reverse=True)
236
+ and check_monotonic_strides(wrapped.col_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 (crow_indices(), col_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.crow_indices
248
+ ust._crd[num_batch_dim + 1] = wrapped.col_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_bsr = self.attr_name_map["sparse_format_helper"].create_bsr
259
+ return create_bsr(self.shape, self.block_size, self.crow_indices, self.col_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._crow_indices = None
271
+ self._col_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._crow_indices = self._attr_name_map["crow_indices"](tensor)
291
+ self._col_indices = self._attr_name_map["col_indices"](tensor)
292
+ self._values = self._attr_name_map["values"](tensor)
293
+ else:
294
+ wrapper = self._dense_tensorholder_type
295
+
296
+ crow_indices = self._attr_name_map["crow_indices"](tensor)
297
+ self._crow_indices = wrapper(crow_indices)
298
+
299
+ col_indices = self._attr_name_map["col_indices"](tensor)
300
+ self._col_indices = wrapper(col_indices)
301
+
302
+ values = self._attr_name_map["values"](tensor)
303
+ self._values = wrapper(values)
@@ -0,0 +1,254 @@
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 COO tensors from different libraries.
7
+ """
8
+
9
+ from __future__ import annotations # allows typehint of class methods to return the self class
10
+
11
+ __all__ = ["COOTensorHolder"]
12
+
13
+ from typing import Literal, TypeVar
14
+
15
+ from nvmath._internal.layout import 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 COOTensor which a COOTensorHolder implementation wraps
25
+ around.
26
+ """
27
+ COOTensor = TypeVar("COOTensor")
28
+
29
+
30
+ class COOTensorHolder(SparseTensorHolder):
31
+ """
32
+ A simple wrapper type for COO 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 = "COO"
41
+
42
+ def __init__(self, indices, values, *, attr_name_map=None, shape=None, tensor=None):
43
+ # tensor is the native tensor.
44
+ self.tensor = tensor
45
+
46
+ # attr_name_map is the canonical attribute name to package attribute name map.
47
+ # It is set when constructing from a tensor, otherwise it is None.
48
+ self._attr_name_map = attr_name_map
49
+
50
+ assert (shape is not None) ^ (tensor is not None), "Internal error."
51
+
52
+ if shape is not None:
53
+ self._shape = shape
54
+ else:
55
+ self._shape = tuple(tensor.shape)
56
+
57
+ # Wrap constituent dense tensors, if required. If it's a sequence, it will be
58
+ # a sequence of TensorHolder.
59
+ if not isinstance(indices, TensorHolder):
60
+ indices = [tensor_wrapper.wrap_operand(i) for i in indices]
61
+
62
+ if not isinstance(values, TensorHolder):
63
+ values = tensor_wrapper.wrap_operand(values)
64
+
65
+ # The wrapped constituent dense tensors.
66
+ self._indices = indices
67
+ self._values = values
68
+
69
+ # Ensure constituent dense tensors are all on the same device.
70
+ device_ids = {d.device_id for d in (*self._indices, self._values)}
71
+ message = f"Internal error: the arrays defining the sparse format aren't on the same device {device_ids}."
72
+ assert len(device_ids) == 1, message
73
+ self._device_id = device_ids.pop()
74
+
75
+ self._device = self._values.device
76
+
77
+ # Capture the native tensor package for use in reset_unchecked().
78
+ self.tensor_package = infer_object_package(self.tensor)
79
+
80
+ # The tensor holder type for the dense constituent tensors (take from values, since
81
+ # all constituent tensors have the same type).
82
+ self._dense_tensorholder_type = values.__class__
83
+
84
+ @classmethod
85
+ def create_from_tensor(cls, tensor, *, attr_name_map=None):
86
+ assert attr_name_map is not None, "Internal error."
87
+
88
+ # tensor is the native tensor.
89
+ # For UST, the buffers will be CuPy ndarrays.
90
+ indices = attr_name_map["indices"](tensor)
91
+ values = attr_name_map["values"](tensor)
92
+ return COOTensorHolder(indices, values, attr_name_map=attr_name_map, tensor=tensor)
93
+
94
+ @property
95
+ def attr_name_map(self):
96
+ return self._attr_name_map
97
+
98
+ @property
99
+ def device(self):
100
+ return self._device
101
+
102
+ @property
103
+ def device_id(self):
104
+ return self._device_id
105
+
106
+ @property
107
+ def dtype(self):
108
+ return self._values.dtype
109
+
110
+ @property
111
+ def index_type(self):
112
+ # TODO: check that all index arrays in the sequence have the same dtype.
113
+ return self._indices[0].dtype
114
+
115
+ @property
116
+ def format_name(self) -> str:
117
+ return COOTensorHolder._format_name
118
+
119
+ @property
120
+ def num_dimensions(self):
121
+ return len(self._shape)
122
+
123
+ @property
124
+ def shape(self):
125
+ return self._shape
126
+
127
+ @property
128
+ def indices(self):
129
+ """The TensorHolder object wrapping the indices array."""
130
+ return self._indices
131
+
132
+ @property
133
+ def values(self) -> TensorHolder:
134
+ """The TensorHolder object wrapping the values array."""
135
+ return self._values
136
+
137
+ def to(self, device_id: int | Literal["cpu"], stream_holder: StreamHolder | None):
138
+ """Copy the COOTensor representation to a different device.
139
+
140
+ No copy is performed if the COOTensor is already on the requested device.
141
+ """
142
+
143
+ target_indices = [i.to(device_id=device_id, stream_holder=stream_holder) for i in self.indices]
144
+ target_values = self.values.to(device_id=device_id, stream_holder=stream_holder)
145
+
146
+ return COOTensorHolder(target_indices, target_values, attr_name_map=self.attr_name_map, shape=self.shape)
147
+
148
+ def copy_(self, src, stream_holder: StreamHolder | None) -> None:
149
+ """Overwrite self.tensor (in-place) with a copy of src (COOTensor)."""
150
+
151
+ for c, component in enumerate(self.indices):
152
+ component.copy_(src=src.indices[c], stream_holder=stream_holder)
153
+ self.values.copy_(src=src.values, stream_holder=stream_holder)
154
+
155
+ def to_ust(self, *, stream):
156
+ from nvmath.sparse.ust.tensor import Tensor, _top_array
157
+ from nvmath.sparse.ust.tensor_format import NamedFormats
158
+
159
+ wrapped = self
160
+ tensor = wrapped.tensor
161
+ if not wrapped.attr_name_map["is_coalesced"](tensor):
162
+ raise ValueError(
163
+ "The COO tensor is not coalesced (metadata sorted with duplicates removed). \
164
+ To coalesce, use the operation provided by your sparse tensor library: `coalesce()`, `sum_duplicates()`, ..."
165
+ )
166
+
167
+ if not (
168
+ all(is_contiguous_and_dense(i.shape, i.strides) for i in self.indices)
169
+ and is_contiguous_and_dense(wrapped.values.shape, wrapped.values.strides)
170
+ ):
171
+ raise ValueError(
172
+ "The sparse tensor representation (indices() and values() tensors) must be \
173
+ dense and contiguous."
174
+ )
175
+
176
+ values = wrapped.values.memory_buffer() # Typed memory viewed as a 1-D tensor.
177
+
178
+ num_sparse_dim = self.attr_name_map["num_sparse_dim"](tensor)
179
+ num_dense_dim = self.attr_name_map["num_dense_dim"](tensor)
180
+ tensor_format = NamedFormats.COOd(num_sparse_dim, num_dense_dim)
181
+
182
+ # Check if the batch axes are in C-order for all component dense arrays.
183
+ if not all(i.strides == (1,) for i in wrapped.indices):
184
+ raise ValueError("The batch dimensions in the sparse tensor representation indices() must use the C-layout.")
185
+
186
+ # Create the UST.
187
+ ust = Tensor(tensor.shape, tensor_format=tensor_format, index_type=wrapped.index_type, dtype=wrapped.dtype)
188
+
189
+ dense_tensorholder_type = wrapped._dense_tensorholder_type
190
+ if wrapped.device_id == "cpu":
191
+ stream_holder = None
192
+ else:
193
+ from nvmath.internal import utils
194
+
195
+ stream_holder = utils.get_or_create_stream(wrapped.device_id, stream, dense_tensorholder_type.name)
196
+ ust._pos[0] = _top_array(
197
+ wrapped.indices[0].size,
198
+ dtype=wrapped.index_type,
199
+ device_id=wrapped.device_id,
200
+ dense_tensorholder_type=dense_tensorholder_type,
201
+ stream_holder=stream_holder,
202
+ )
203
+ for d in range(num_sparse_dim):
204
+ ust._crd[d] = wrapped.indices[d]
205
+ ust._val = values
206
+
207
+ return ust
208
+
209
+ def to_package(self):
210
+ """
211
+ This will create a sparse tensor for the original package from which this
212
+ interface was created.
213
+ """
214
+ create_coo = self.attr_name_map["sparse_format_helper"].create_coo
215
+ return create_coo(self.shape, self.indices, self.values)
216
+
217
+ def release(self):
218
+ """
219
+ This method will release the wrapped tensor and any format-specific data
220
+ by setting them to None.
221
+ """
222
+ # The tensor reference.
223
+ self.tensor = None
224
+
225
+ # Format-specific data.
226
+ self._indices = None
227
+ self._values = None
228
+
229
+ def reset_unchecked(self, tensor):
230
+ """
231
+ This method will reset the wrapped tensor to the specified one, and update
232
+ any format-specific data accordingly. It assumes that all attributes
233
+ like the device, shape, etc are consistent between the existing and new tensor.
234
+
235
+ Args:
236
+ tensor: The native tensor to wrap.
237
+ """
238
+ # Update the tensor reference.
239
+ self.tensor = tensor
240
+
241
+ # Format-specific data.
242
+
243
+ if self.tensor_package == "nvmath":
244
+ # The data arrays are already wrapped.
245
+ self._indices = self._attr_name_map["indices"](tensor)
246
+ self._values = self._attr_name_map["values"](tensor)
247
+ else:
248
+ wrapper = self._dense_tensorholder_type
249
+
250
+ indices = self._attr_name_map["indices"](tensor)
251
+ self._indices = [wrapper(i) for i in indices]
252
+
253
+ values = self._attr_name_map["values"](tensor)
254
+ self._values = wrapper(values)