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,266 @@
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 CSC tensors from different libraries.
7
+ """
8
+
9
+ from __future__ import annotations # allows typehint of class methods to return the self class
10
+
11
+ __all__ = ["CSCTensorHolder"]
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 CSCTensor which a CSCTensorHolder implementation wraps
25
+ around.
26
+ """
27
+ CSCTensor = TypeVar("CSCTensor")
28
+
29
+
30
+ class CSCTensorHolder(SparseTensorHolder):
31
+ """
32
+ A simple wrapper type for CSC 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 = "CSC"
41
+
42
+ def __init__(self, ccol_indices, row_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.
58
+ if not isinstance(ccol_indices, TensorHolder):
59
+ ccol_indices = tensor_wrapper.wrap_operand(ccol_indices)
60
+
61
+ if not isinstance(row_indices, TensorHolder):
62
+ row_indices = tensor_wrapper.wrap_operand(row_indices)
63
+
64
+ if not isinstance(values, TensorHolder):
65
+ values = tensor_wrapper.wrap_operand(values)
66
+
67
+ # The wrapped constituent dense tensors.
68
+ self._ccol_indices = ccol_indices
69
+ self._row_indices = row_indices
70
+ self._values = values
71
+
72
+ # Ensure constituent dense tensors are all on the same device.
73
+ device_ids = {d.device_id for d in (self._ccol_indices, self._row_indices, self._values)}
74
+ message = f"Internal error: the arrays defining the sparse format aren't on the same device {device_ids}."
75
+ assert len(device_ids) == 1, message
76
+ self._device_id = device_ids.pop()
77
+
78
+ self._device = self._values.device
79
+
80
+ # Capture the native tensor package for use in reset_unchecked().
81
+ self.tensor_package = infer_object_package(self.tensor)
82
+
83
+ # The tensor holder type for the dense constituent tensors (take from values, since
84
+ # all constituent tensors have the same type).
85
+ self._dense_tensorholder_type = values.__class__
86
+
87
+ @classmethod
88
+ def create_from_tensor(cls, tensor, *, attr_name_map=None):
89
+ assert attr_name_map is not None, "Internal error."
90
+
91
+ # tensor is the native tensor.
92
+ # For UST, the buffers will be CuPy ndarrays.
93
+ ccol_indices = attr_name_map["ccol_indices"](tensor)
94
+ row_indices = attr_name_map["row_indices"](tensor)
95
+ values = attr_name_map["values"](tensor)
96
+ return CSCTensorHolder(ccol_indices, row_indices, values, attr_name_map=attr_name_map, tensor=tensor)
97
+
98
+ @property
99
+ def attr_name_map(self):
100
+ return self._attr_name_map
101
+
102
+ @property
103
+ def device(self):
104
+ return self._device
105
+
106
+ @property
107
+ def device_id(self):
108
+ return self._device_id
109
+
110
+ @property
111
+ def dtype(self):
112
+ return self._values.dtype
113
+
114
+ @property
115
+ def index_type(self):
116
+ return self._ccol_indices.dtype
117
+
118
+ @property
119
+ def format_name(self) -> str:
120
+ return CSCTensorHolder._format_name
121
+
122
+ @property
123
+ def num_dimensions(self):
124
+ return len(self._shape)
125
+
126
+ @property
127
+ def shape(self):
128
+ return self._shape
129
+
130
+ @property
131
+ def ccol_indices(self) -> TensorHolder:
132
+ """The TensorHolder object wrapping the ccol_indices array."""
133
+ return self._ccol_indices
134
+
135
+ @property
136
+ def row_indices(self) -> TensorHolder:
137
+ """The TensorHolder object wrapping the row_indices array."""
138
+ return self._row_indices
139
+
140
+ @property
141
+ def values(self) -> TensorHolder:
142
+ """The TensorHolder object wrapping the values array."""
143
+ return self._values
144
+
145
+ def to(self, device_id: int | Literal["cpu"], stream_holder: StreamHolder | None):
146
+ """Copy the CSCTensor representation to a different device.
147
+
148
+ No copy is performed if the CSCTensor is already on the requested device.
149
+ """
150
+
151
+ target_ccol_indices = self.ccol_indices.to(device_id=device_id, stream_holder=stream_holder)
152
+ target_row_indices = self.row_indices.to(device_id=device_id, stream_holder=stream_holder)
153
+ target_values = self.values.to(device_id=device_id, stream_holder=stream_holder)
154
+
155
+ return CSCTensorHolder(
156
+ target_ccol_indices, target_row_indices, target_values, attr_name_map=self.attr_name_map, shape=self.shape
157
+ )
158
+
159
+ def copy_(self, src, stream_holder: StreamHolder | None) -> None:
160
+ """Overwrite self.tensor (in-place) with a copy of src (CSCTensor)."""
161
+
162
+ self.ccol_indices.copy_(src=src.ccol_indices, stream_holder=stream_holder)
163
+ self.row_indices.copy_(src=src.row_indices, stream_holder=stream_holder)
164
+ self.values.copy_(src=src.values, stream_holder=stream_holder)
165
+
166
+ def to_ust(self, *, stream):
167
+ from nvmath.sparse.ust.tensor import Tensor
168
+ from nvmath.sparse.ust.tensor_format import NamedFormats
169
+
170
+ wrapped = self
171
+ tensor = wrapped.tensor
172
+ if not (wrapped.attr_name_map["is_coalesced"](tensor) and wrapped.attr_name_map["has_sorted_indices"](tensor)):
173
+ raise ValueError(
174
+ "The CSC tensor is not coalesced (metadata sorted with duplicates removed). \
175
+ To coalesce, use the operation provided by your sparse tensor library: `coalesce()`, `sum_duplicates()`, ..."
176
+ )
177
+
178
+ if not (
179
+ is_contiguous_and_dense(wrapped.ccol_indices.shape, wrapped.ccol_indices.strides)
180
+ and is_contiguous_and_dense(wrapped.row_indices.shape, wrapped.row_indices.strides)
181
+ and is_contiguous_and_dense(wrapped.values.shape, wrapped.values.strides)
182
+ ):
183
+ raise ValueError(
184
+ "The sparse tensor representation (ccol_indices(), row_indices(), and values() tensors) must be \
185
+ dense and contiguous."
186
+ )
187
+
188
+ values = wrapped.values.memory_buffer() # Typed memory viewed as a 1-D tensor.
189
+
190
+ num_dim = self.num_dimensions
191
+ num_sparse_dim = self.attr_name_map["num_sparse_dim"](tensor)
192
+ num_dense_dim = self.attr_name_map["num_dense_dim"](tensor)
193
+ num_batch_dim = num_dim - num_sparse_dim - num_dense_dim
194
+ tensor_format = NamedFormats.CSCd(num_batch_dim, num_dense_dim)
195
+
196
+ # Check if the batch axes are in C-order for all component dense arrays.
197
+ if not (
198
+ check_monotonic_strides(wrapped.ccol_indices.strides[:num_batch_dim], reverse=True)
199
+ and check_monotonic_strides(wrapped.row_indices.strides[:num_batch_dim], reverse=True)
200
+ and check_monotonic_strides(wrapped.values.strides[:num_batch_dim], reverse=True)
201
+ ):
202
+ raise ValueError(
203
+ "The batch dimensions in the sparse tensor representation (ccol_indices(), row_indices(), \
204
+ and values() tensors) must use the C-layout."
205
+ )
206
+
207
+ # Create the UST.
208
+ ust = Tensor(tensor.shape, tensor_format=tensor_format, index_type=wrapped.index_type, dtype=wrapped.dtype)
209
+
210
+ ust._pos[num_batch_dim + 1] = wrapped.ccol_indices
211
+ ust._crd[num_batch_dim + 1] = wrapped.row_indices
212
+ ust._val = values
213
+
214
+ return ust
215
+
216
+ def to_package(self):
217
+ """
218
+ This will create a sparse tensor for the original package from which this
219
+ interface was created.
220
+ """
221
+ create_csc = self.attr_name_map["sparse_format_helper"].create_csc
222
+ return create_csc(self.shape, self.ccol_indices, self.row_indices, self.values)
223
+
224
+ def release(self):
225
+ """
226
+ This method will release the wrapped tensor and any format-specific data
227
+ by setting them to None.
228
+ """
229
+ # The tensor reference.
230
+ self.tensor = None
231
+
232
+ # Format-specific data.
233
+ self._ccol_indices = None
234
+ self._row_indices = None
235
+ self._values = None
236
+
237
+ def reset_unchecked(self, tensor):
238
+ """
239
+ This method will reset the wrapped tensor to the specified one, and update
240
+ any format-specific data accordingly. It assumes that all attributes
241
+ like the device, shape, etc are consistent between the existing and new tensor.
242
+
243
+ Args:
244
+ tensor: The native tensor to wrap.
245
+ """
246
+ # Update the tensor reference.
247
+ self.tensor = tensor
248
+
249
+ # Format-specific data.
250
+
251
+ if self.tensor_package == "nvmath":
252
+ # The data arrays are already wrapped.
253
+ self._ccol_indices = self._attr_name_map["ccol_indices"](tensor)
254
+ self._row_indices = self._attr_name_map["row_indices"](tensor)
255
+ self._values = self._attr_name_map["values"](tensor)
256
+ else:
257
+ wrapper = self._dense_tensorholder_type
258
+
259
+ ccol_indices = self._attr_name_map["ccol_indices"](tensor)
260
+ self._ccol_indices = wrapper(ccol_indices)
261
+
262
+ row_indices = self._attr_name_map["row_indices"](tensor)
263
+ self._row_indices = wrapper(row_indices)
264
+
265
+ values = self._attr_name_map["values"](tensor)
266
+ self._values = wrapper(values)
@@ -0,0 +1,266 @@
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 CSR tensors from different libraries.
7
+ """
8
+
9
+ from __future__ import annotations # allows typehint of class methods to return the self class
10
+
11
+ __all__ = ["CSRTensorHolder"]
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 CSRTensor which a CSRTensorHolder implementation wraps
25
+ around.
26
+ """
27
+ CSRTensor = TypeVar("CSRTensor")
28
+
29
+
30
+ class CSRTensorHolder(SparseTensorHolder):
31
+ """
32
+ A simple wrapper type for CSR 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 = "CSR"
41
+
42
+ def __init__(self, crow_indices, col_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.
58
+ if not isinstance(crow_indices, TensorHolder):
59
+ crow_indices = tensor_wrapper.wrap_operand(crow_indices)
60
+
61
+ if not isinstance(col_indices, TensorHolder):
62
+ col_indices = tensor_wrapper.wrap_operand(col_indices)
63
+
64
+ if not isinstance(values, TensorHolder):
65
+ values = tensor_wrapper.wrap_operand(values)
66
+
67
+ # The wrapped constituent dense tensors.
68
+ self._crow_indices = crow_indices
69
+ self._col_indices = col_indices
70
+ self._values = values
71
+
72
+ # Ensure constituent dense tensors are all on the same device.
73
+ device_ids = {d.device_id for d in (self._crow_indices, self._col_indices, self._values)}
74
+ message = f"Internal error: the arrays defining the sparse format aren't on the same device {device_ids}."
75
+ assert len(device_ids) == 1, message
76
+ self._device_id = device_ids.pop()
77
+
78
+ self._device = self._values.device
79
+
80
+ # Capture the native tensor package for use in reset_unchecked().
81
+ self.tensor_package = infer_object_package(self.tensor)
82
+
83
+ # The tensor holder type for the dense constituent tensors (take from values, since
84
+ # all constituent tensors have the same type).
85
+ self._dense_tensorholder_type = values.__class__
86
+
87
+ @classmethod
88
+ def create_from_tensor(cls, tensor, *, attr_name_map=None):
89
+ assert attr_name_map is not None, "Internal error."
90
+
91
+ # tensor is the native tensor.
92
+ # For UST, the buffers will be CuPy ndarrays.
93
+ crow_indices = attr_name_map["crow_indices"](tensor)
94
+ col_indices = attr_name_map["col_indices"](tensor)
95
+ values = attr_name_map["values"](tensor)
96
+ return CSRTensorHolder(crow_indices, col_indices, values, attr_name_map=attr_name_map, tensor=tensor)
97
+
98
+ @property
99
+ def attr_name_map(self):
100
+ return self._attr_name_map
101
+
102
+ @property
103
+ def device(self):
104
+ return self._device
105
+
106
+ @property
107
+ def device_id(self):
108
+ return self._device_id
109
+
110
+ @property
111
+ def dtype(self):
112
+ return self._values.dtype
113
+
114
+ @property
115
+ def index_type(self):
116
+ return self._crow_indices.dtype
117
+
118
+ @property
119
+ def format_name(self) -> str:
120
+ return CSRTensorHolder._format_name
121
+
122
+ @property
123
+ def num_dimensions(self):
124
+ return len(self._shape)
125
+
126
+ @property
127
+ def shape(self):
128
+ return self._shape
129
+
130
+ @property
131
+ def crow_indices(self) -> TensorHolder:
132
+ """The TensorHolder object wrapping the crow_indices array."""
133
+ return self._crow_indices
134
+
135
+ @property
136
+ def col_indices(self) -> TensorHolder:
137
+ """The TensorHolder object wrapping the col_indices array."""
138
+ return self._col_indices
139
+
140
+ @property
141
+ def values(self) -> TensorHolder:
142
+ """The TensorHolder object wrapping the values array."""
143
+ return self._values
144
+
145
+ def to(self, device_id: int | Literal["cpu"], stream_holder: StreamHolder | None):
146
+ """Copy the CSRTensor representation to a different device.
147
+
148
+ No copy is performed if the CSRTensor is already on the requested device.
149
+ """
150
+
151
+ target_crow_indices = self.crow_indices.to(device_id=device_id, stream_holder=stream_holder)
152
+ target_col_indices = self.col_indices.to(device_id=device_id, stream_holder=stream_holder)
153
+ target_values = self.values.to(device_id=device_id, stream_holder=stream_holder)
154
+
155
+ return CSRTensorHolder(
156
+ target_crow_indices, target_col_indices, target_values, attr_name_map=self.attr_name_map, shape=self.shape
157
+ )
158
+
159
+ def copy_(self, src, stream_holder: StreamHolder | None) -> None:
160
+ """Overwrite self.tensor (in-place) with a copy of src (CSRTensor)."""
161
+
162
+ self.crow_indices.copy_(src=src.crow_indices, stream_holder=stream_holder)
163
+ self.col_indices.copy_(src=src.col_indices, stream_holder=stream_holder)
164
+ self.values.copy_(src=src.values, stream_holder=stream_holder)
165
+
166
+ def to_ust(self, *, stream):
167
+ from nvmath.sparse.ust.tensor import Tensor
168
+ from nvmath.sparse.ust.tensor_format import NamedFormats
169
+
170
+ wrapped = self
171
+ tensor = wrapped.tensor
172
+ if not (wrapped.attr_name_map["is_coalesced"](tensor) and wrapped.attr_name_map["has_sorted_indices"](tensor)):
173
+ raise ValueError(
174
+ "The CSR tensor is not coalesced (metadata sorted with duplicates removed). \
175
+ To coalesce, use the operation provided by your sparse tensor library: `coalesce()`, `sum_duplicates()`, ..."
176
+ )
177
+
178
+ if not (
179
+ is_contiguous_and_dense(wrapped.crow_indices.shape, wrapped.crow_indices.strides)
180
+ and is_contiguous_and_dense(wrapped.col_indices.shape, wrapped.col_indices.strides)
181
+ and is_contiguous_and_dense(wrapped.values.shape, wrapped.values.strides)
182
+ ):
183
+ raise ValueError(
184
+ "The sparse tensor representation (crow_indices(), col_indices(), and values() tensors) must be \
185
+ dense and contiguous."
186
+ )
187
+
188
+ values = wrapped.values.memory_buffer() # Typed memory viewed as a 1-D tensor.
189
+
190
+ num_dim = self.num_dimensions
191
+ num_sparse_dim = self.attr_name_map["num_sparse_dim"](tensor)
192
+ num_dense_dim = self.attr_name_map["num_dense_dim"](tensor)
193
+ num_batch_dim = num_dim - num_sparse_dim - num_dense_dim
194
+ tensor_format = NamedFormats.CSRd(num_batch_dim, num_dense_dim)
195
+
196
+ # Check if the batch axes are in C-order for all component dense arrays.
197
+ if not (
198
+ check_monotonic_strides(wrapped.crow_indices.strides[:num_batch_dim], reverse=True)
199
+ and check_monotonic_strides(wrapped.col_indices.strides[:num_batch_dim], reverse=True)
200
+ and check_monotonic_strides(wrapped.values.strides[:num_batch_dim], reverse=True)
201
+ ):
202
+ raise ValueError(
203
+ "The batch dimensions in the sparse tensor representation (crow_indices(), col_indices(), \
204
+ and values() tensors) must use the C-layout."
205
+ )
206
+
207
+ # Create the UST.
208
+ ust = Tensor(tensor.shape, tensor_format=tensor_format, index_type=wrapped.index_type, dtype=wrapped.dtype)
209
+
210
+ ust._pos[num_batch_dim + 1] = wrapped.crow_indices
211
+ ust._crd[num_batch_dim + 1] = wrapped.col_indices
212
+ ust._val = values
213
+
214
+ return ust
215
+
216
+ def to_package(self):
217
+ """
218
+ This will create a sparse tensor for the original package from which this
219
+ interface was created.
220
+ """
221
+ create_csr = self.attr_name_map["sparse_format_helper"].create_csr
222
+ return create_csr(self.shape, self.crow_indices, self.col_indices, self.values)
223
+
224
+ def release(self):
225
+ """
226
+ This method will release the wrapped tensor and any format-specific data
227
+ by setting them to None.
228
+ """
229
+ # The tensor reference.
230
+ self.tensor = None
231
+
232
+ # Format-specific data.
233
+ self._crow_indices = None
234
+ self._col_indices = None
235
+ self._values = None
236
+
237
+ def reset_unchecked(self, tensor):
238
+ """
239
+ This method will reset the wrapped tensor to the specified one, and update
240
+ any format-specific data accordingly. It assumes that all attributes
241
+ like the device, shape, etc are consistent between the existing and new tensor.
242
+
243
+ Args:
244
+ tensor: The native tensor to wrap.
245
+ """
246
+ # Update the tensor reference.
247
+ self.tensor = tensor
248
+
249
+ # Format-specific data.
250
+
251
+ if self.tensor_package == "nvmath":
252
+ # The data arrays are already wrapped.
253
+ self._crow_indices = self._attr_name_map["crow_indices"](tensor)
254
+ self._col_indices = self._attr_name_map["col_indices"](tensor)
255
+ self._values = self._attr_name_map["values"](tensor)
256
+ else:
257
+ wrapper = self._dense_tensorholder_type
258
+
259
+ crow_indices = self._attr_name_map["crow_indices"](tensor)
260
+ self._crow_indices = wrapper(crow_indices)
261
+
262
+ col_indices = self._attr_name_map["col_indices"](tensor)
263
+ self._col_indices = wrapper(col_indices)
264
+
265
+ values = self._attr_name_map["values"](tensor)
266
+ self._values = wrapper(values)