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,194 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Interface to seamlessly use tensors (or ndarray-like objects) from different libraries.
7
+ """
8
+
9
+ from __future__ import annotations # allows typehint of class methods to return the self class
10
+
11
+ from abc import ABC, abstractmethod
12
+ from collections.abc import Callable, Sequence
13
+ from types import ModuleType
14
+ from typing import Any, Generic, Literal, Protocol, TypeVar
15
+
16
+ from . import typemaps
17
+ from .ndbuffer import ndbuffer
18
+ from .package_ifc import StreamHolder
19
+
20
+
21
+ class AnyTensor(Protocol):
22
+ """Any supported external tensor object such as NumPy, CuPy, and PyTorch arrays."""
23
+
24
+ # This empty protocol class is just a placeholder to make type checking more helpful.
25
+ # Since the class is empty, it doesn't assume anything is true about the implementation
26
+ # classes. Used to type hint any object that TensorHolder knows how to wrap.
27
+ pass
28
+
29
+
30
+ """
31
+ A generic type for the third-party Tensor which a given TensorHolder implementation wraps
32
+ around.
33
+ """
34
+ Tensor = TypeVar("Tensor")
35
+
36
+
37
+ class TensorHolder(ABC, Generic[Tensor]):
38
+ """
39
+ A simple wrapper type for tensors to make the API package-agnostic.
40
+
41
+ Methods of a TensorHolder should always return a TensorHolder instead of a Tensor (one
42
+ of the wrapped classes) in order to prevent implementation details from the various
43
+ Tensor implementations from leaking into nvmath-python.
44
+
45
+ Tensors from the user should be immediately wrapped with a TensorHolder and should
46
+ remain wrapped until just before returning to the user.
47
+ """
48
+
49
+ name: str
50
+ module: ModuleType
51
+ name_to_dtype: dict[str, Any]
52
+
53
+ def __init__(self, tensor: Tensor):
54
+ self.tensor: Tensor = tensor
55
+
56
+ @property
57
+ @abstractmethod
58
+ def data_ptr(self) -> int:
59
+ raise NotImplementedError
60
+
61
+ @property
62
+ @abstractmethod
63
+ def device(self) -> Literal["cuda"] | Literal["cpu"]:
64
+ """The type of the device which stores the tensor."""
65
+ raise NotImplementedError
66
+
67
+ @property
68
+ @abstractmethod
69
+ def device_id(self) -> int | Literal["cpu"]:
70
+ """The device ordinal of the device storing the tensor."""
71
+ raise NotImplementedError
72
+
73
+ @property
74
+ @abstractmethod
75
+ def dtype(self) -> str:
76
+ """Name of the data type"""
77
+ raise NotImplementedError
78
+
79
+ @property
80
+ @abstractmethod
81
+ def itemsize(self) -> int:
82
+ """The size of the data type in bytes."""
83
+ raise NotImplementedError
84
+
85
+ @classmethod
86
+ @abstractmethod
87
+ def empty(cls, shape: Sequence[int], device_id: int | Literal["cpu"], **context: Any) -> TensorHolder[Tensor]:
88
+ """Create an empty TensorHolder of the specified shape and data type."""
89
+ raise NotImplementedError
90
+
91
+ @property
92
+ @abstractmethod
93
+ def shape(self) -> Sequence[int]:
94
+ """The extent of each dimension in number of elements."""
95
+ raise NotImplementedError
96
+
97
+ @property
98
+ @abstractmethod
99
+ def size(self) -> int:
100
+ """The total number of elements in the tensor."""
101
+ raise NotImplementedError
102
+
103
+ @property
104
+ @abstractmethod
105
+ def strides(self) -> Sequence[int]:
106
+ """The stride of each dimension in number of elements."""
107
+ raise NotImplementedError
108
+
109
+ @abstractmethod
110
+ def to(self, device_id: int | Literal["cpu"], stream_holder: StreamHolder | None) -> TensorHolder:
111
+ """Copy the TensorHolder to a different device.
112
+
113
+ No copy is performed if the TensorHolder is already on the requested device.
114
+ """
115
+ raise NotImplementedError
116
+
117
+ @abstractmethod
118
+ def asndbuffer(self) -> ndbuffer.NDBuffer:
119
+ """Wraps the package tensor as a ndbuffer.NDBuffer object."""
120
+ raise NotImplementedError
121
+
122
+ @abstractmethod
123
+ def copy_(self, src: TensorHolder, stream_holder: StreamHolder | None) -> None:
124
+ """Overwrite self.tensor (in-place) with a copy of src."""
125
+ raise NotImplementedError
126
+
127
+ @staticmethod
128
+ def create_name_dtype_map(conversion_function: Callable[[str], Any], exception_type: type[Exception]) -> dict[str, Any]:
129
+ """
130
+ Create a map between CUDA data type names and the corresponding package dtypes for
131
+ supported data types.
132
+ """
133
+ names = typemaps.NAME_TO_DATA_TYPE.keys()
134
+ name_to_dtype = {}
135
+ for name in names:
136
+ try:
137
+ name_to_dtype[name] = conversion_function(name)
138
+ except exception_type:
139
+ pass
140
+ return name_to_dtype
141
+
142
+ @abstractmethod
143
+ def istensor(self) -> bool:
144
+ """Return whether self.tensor is the expected type."""
145
+ raise NotImplementedError
146
+
147
+ @abstractmethod
148
+ def reshape(self, shape: Sequence[int], *, copy: bool | None = None) -> TensorHolder[Tensor]:
149
+ """Reshapes tensor without changing its data.
150
+
151
+ Args:
152
+ shape: a new shape compatible with the original shape.
153
+
154
+ copy (Optional[bool]): whether or not to copy the input tensor. If True, the
155
+ function must always copy. If False, the function must never copy. If None,
156
+ the function must avoid copying, if possible, and may copy otherwise.
157
+ """
158
+ raise NotImplementedError
159
+
160
+ @abstractmethod
161
+ def memory_buffer(self) -> TensorHolder[Tensor]:
162
+ """Creates a view of the memory buffer as a 1D tensor."""
163
+ raise NotImplementedError
164
+
165
+ @abstractmethod
166
+ def memory_buffer_to_tensor(self, shape, strides) -> TensorHolder[Tensor]:
167
+ """
168
+ Creates a N-D tensor view of the memory buffer according to the specified
169
+ shape and strides.
170
+ """
171
+ raise NotImplementedError
172
+
173
+ def _broadcast_to(self, shape: Sequence[int]) -> TensorHolder[Tensor]:
174
+ """Returns a view of the tensor broadcast to the desired shape.
175
+
176
+ .. deprecated:: 0.8.0
177
+ This method is private, and should not be used. It will be removed in the
178
+ future once NDBuffer supports broadcasting-aware copy.
179
+
180
+ Like reshape, but raises an error if the tensor is not broadcastable to the desired
181
+ shape.
182
+
183
+ Args:
184
+ shape: a new shape compatible with the original shape.
185
+ """
186
+ raise NotImplementedError
187
+
188
+ @property
189
+ def is_conjugate(self) -> bool:
190
+ """Return True when self.tensor has a no-op conjugation flag enabled.
191
+
192
+ The default implementation always returns False.
193
+ """
194
+ return False
@@ -0,0 +1,241 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Interface to seamlessly use Cupy ndarray objects.
7
+ """
8
+
9
+ __all__ = ["CupyTensor", "HostTensor"]
10
+
11
+ from collections.abc import Sequence
12
+
13
+ import cupy
14
+ import numpy as np
15
+
16
+ from nvmath.internal.memory import _MemoryPointer
17
+
18
+ from . import utils
19
+ from .ndbuffer import ndbuffer, package_utils
20
+ from .package_ifc import StreamHolder
21
+ from .tensor_ifc import TensorHolder
22
+ from .tensor_ifc_ndbuffer import NDBufferTensor
23
+
24
+
25
+ class HostTensor(NDBufferTensor):
26
+ """
27
+ Wraps ndbuffer with data residing on the host.
28
+ It serves as a host counterpart for CupyTensor.
29
+ """
30
+
31
+ name = "cupy_host"
32
+ device_tensor_class: type["CupyTensor"] # set once CupyTensor is defined
33
+
34
+ def __init__(self, tensor):
35
+ super().__init__(tensor)
36
+
37
+ @classmethod
38
+ def create_host_from(cls, tensor: TensorHolder, stream_holder: StreamHolder):
39
+ src_nd = tensor.asndbuffer()
40
+ # empty_like (and not empty_numpy_like) is used as we don't need
41
+ # full-fledged numpy array (with proper layout)
42
+ dst_nd = ndbuffer.empty_like(src_nd, device_id=ndbuffer.CPU_DEVICE_ID)
43
+ ndbuffer.copy_into(dst_nd, src_nd, stream_holder)
44
+ return cls(dst_nd)
45
+
46
+ def to(self, device_id, stream_holder):
47
+ if device_id == "cpu":
48
+ return self
49
+ elif isinstance(device_id, int):
50
+ return self.device_tensor_class.create_from_host(self, device_id, stream_holder)
51
+ else:
52
+ raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
53
+
54
+
55
+ class _CupyAllocatorAdapter:
56
+ def allocate(self, size, stream):
57
+ # we accept the stream, because the ndbuffer.empty_like
58
+ # passes it to the allocator, but we don't use it:
59
+ # cupy.cuda.alloc does not accept the stream, we make sure to set
60
+ # the correct current stream when calling ndbuffer.empty_like
61
+ alloc = cupy.cuda.alloc(size)
62
+ # Once we require cuda.core >= 0.5.0,
63
+ # use Buffer.from_handle(alloc.ptr, owner=alloc)
64
+ return _MemoryPointer.from_handle(alloc.ptr, alloc)
65
+
66
+
67
+ _cupy_allocator = _CupyAllocatorAdapter()
68
+
69
+
70
+ class CupyTensor(TensorHolder[cupy.ndarray]):
71
+ """
72
+ TensorHolder for cupy ndarrays.
73
+ """
74
+
75
+ name = "cupy"
76
+ module = cupy
77
+ name_to_dtype = TensorHolder.create_name_dtype_map(
78
+ conversion_function=lambda name: np.dtype(name), exception_type=TypeError
79
+ )
80
+ host_tensor_class = HostTensor
81
+
82
+ def __init__(self, tensor):
83
+ super().__init__(tensor)
84
+
85
+ @property
86
+ def data_ptr(self):
87
+ return self.tensor.data.ptr
88
+
89
+ @property
90
+ def device(self):
91
+ return "cuda"
92
+
93
+ @property
94
+ def device_id(self):
95
+ return self.tensor.device.id
96
+
97
+ @property
98
+ def dtype(self):
99
+ """Name of the data type"""
100
+ return self.tensor.dtype.name
101
+
102
+ @property
103
+ def itemsize(self):
104
+ return self.tensor.itemsize
105
+
106
+ @property
107
+ def shape(self):
108
+ return tuple(self.tensor.shape)
109
+
110
+ @property
111
+ def size(self):
112
+ return self.tensor.size
113
+
114
+ @property
115
+ def strides(self):
116
+ return tuple(stride_in_bytes // self.tensor.itemsize for stride_in_bytes in self.tensor.strides)
117
+
118
+ @classmethod
119
+ def empty(
120
+ cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
121
+ ):
122
+ """
123
+ Create an empty tensor of the specified shape and data type.
124
+
125
+ Note, that the strides, if specified, MUST correspond to a dense (possibly permuted)
126
+ tensor, otherwise the created tensor may be corrupted.
127
+ """
128
+ assert isinstance(device_id, int), "Internal Error: Cupy tensors must be allocated with an integer device_id."
129
+ dtype = CupyTensor.name_to_dtype[dtype]
130
+
131
+ # When using the strides, we need an explicit allocation (see below).
132
+ # If the strides are simple enough, we can still avoid this overhead.
133
+ order = "C"
134
+ if strides is not None:
135
+ if len(strides) == 1 and strides[0] == 1:
136
+ strides = None
137
+ elif len(strides) == 2:
138
+ if strides[0] == 1 and strides[1] == shape[0]:
139
+ strides = None
140
+ order = "F"
141
+ elif strides[0] == shape[1] and strides[1] == 1:
142
+ strides = None
143
+
144
+ assert isinstance(stream_holder, StreamHolder), "Internal Error: CupyTensors must be allocated on a stream."
145
+ with utils.device_ctx(device_id), stream_holder.ctx:
146
+ if strides:
147
+ # need an explicit allocation due to cupy/cupy#7818
148
+ size = dtype.itemsize
149
+ for s in shape:
150
+ size = size * s
151
+ ptr = cupy.cuda.alloc(size)
152
+ # when strides is not None, it should be of unit counts not bytes
153
+ strides = tuple(s * dtype.itemsize for s in strides)
154
+ tensor = cupy.ndarray(shape, dtype=dtype, strides=strides, memptr=ptr)
155
+ else:
156
+ tensor = cupy.ndarray(shape, dtype=dtype, order=order)
157
+
158
+ return cls(tensor)
159
+
160
+ @classmethod
161
+ def create_from_host(cls, tensor: TensorHolder, device_id: int, stream_holder: StreamHolder):
162
+ with utils.device_ctx(device_id), stream_holder.ctx:
163
+ src_nd = tensor.asndbuffer()
164
+ dst_nd = ndbuffer.empty_like(
165
+ src_nd,
166
+ device_id=device_id,
167
+ stream=stream_holder,
168
+ device_memory_pool=_cupy_allocator,
169
+ )
170
+ ndbuffer.copy_into(dst_nd, src_nd, stream_holder)
171
+ dst = cupy.ndarray(dst_nd.shape, dtype=dst_nd.dtype_name, strides=dst_nd.strides_in_bytes, memptr=dst_nd.data.owner)
172
+ return cls(dst)
173
+
174
+ def asndbuffer(self):
175
+ return package_utils.wrap_cupy_array(self.tensor)
176
+
177
+ def to(self, device_id, stream_holder):
178
+ if device_id == "cpu":
179
+ with utils.device_ctx(self.device_id):
180
+ return self.host_tensor_class.create_host_from(self, stream_holder)
181
+ elif device_id == self.device_id:
182
+ return self
183
+ elif isinstance(device_id, int):
184
+ raise ValueError(f"Unsupported copy between different devices {self.device_id} and {device_id}.")
185
+ raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
186
+
187
+ def copy_(self, src, stream_holder):
188
+ """
189
+ Inplace copy of src (copy the data from src into self).
190
+ """
191
+ with utils.device_ctx(self.device_id):
192
+ ndbuffer.copy_into(self.asndbuffer(), src._broadcast_to(self.shape).asndbuffer(), stream_holder)
193
+
194
+ def istensor(self):
195
+ """
196
+ Check if the object is ndarray-like.
197
+ """
198
+ return isinstance(self.tensor, cupy.ndarray)
199
+
200
+ def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
201
+ if copy:
202
+ raise NotImplementedError("reshape with copy=True not implemented")
203
+ if copy is False:
204
+ try:
205
+ reshaped_tensor = self.tensor.view()
206
+ reshaped_tensor.shape = shape
207
+ except AttributeError as e:
208
+ raise ValueError(
209
+ f"Could not reshape cupy array without copy: current shape={self.shape}, new shape={shape}"
210
+ ) from e
211
+ else:
212
+ reshaped_tensor = self.tensor.reshape(shape)
213
+ return self.__class__(reshaped_tensor)
214
+
215
+ def memory_buffer(self):
216
+ """Creates a view of the memory buffer as a 1D tensor."""
217
+ m = cupy.cuda.UnownedMemory(self.data_ptr, self.size * self.itemsize, owner=self.tensor, device_id=self.device_id)
218
+ p = cupy.cuda.MemoryPointer(m, 0)
219
+ # TODO: ensure tensor is dense for now, and later support linear
220
+ # memory with constant stride.
221
+ t = cupy.ndarray(shape=(self.size,), dtype=self.dtype, memptr=p)
222
+ return CupyTensor(t)
223
+
224
+ def memory_buffer_to_tensor(self, shape, strides):
225
+ """
226
+ Creates a N-D tensor view of the memory buffer according to the specified
227
+ shape and strides.
228
+ """
229
+ assert len(self.shape) == 1, "Internal error."
230
+ m = cupy.cuda.UnownedMemory(self.data_ptr, self.size * self.itemsize, owner=self.tensor)
231
+ p = cupy.cuda.MemoryPointer(m, 0)
232
+ strides = [s * self.itemsize for s in strides]
233
+ t = cupy.ndarray(shape=shape, dtype=self.dtype, memptr=p, strides=strides)
234
+ return CupyTensor(t)
235
+
236
+ def _broadcast_to(self, shape):
237
+ reshaped_tensor = cupy.broadcast_to(self.tensor, shape)
238
+ return self.__class__(reshaped_tensor)
239
+
240
+
241
+ HostTensor.device_tensor_class = CupyTensor
@@ -0,0 +1,153 @@
1
+ # Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ TensorHolder implementation that adapts ndbuffer for use with
7
+ the tensor_ifc interface. The class is meant for internal use only
8
+ (e.g. for internal operands of host APIs), but the NDBufferTensor
9
+ or underlying ndbuffer should never be returned to the user, because
10
+ 1. the ndbuffer is opaque, i.e. it missies most of typical tensor functionality, and
11
+ 2. we make no guarantees about the ndbuffer's API stability.
12
+ """
13
+
14
+ __all__ = ["NDBufferTensor"]
15
+
16
+ from collections.abc import Sequence
17
+
18
+ from . import typemaps, utils
19
+ from .ndbuffer import ndbuffer
20
+ from .package_ifc import StreamHolder
21
+ from .tensor_ifc import TensorHolder
22
+
23
+
24
+ class NDBufferTensor(TensorHolder[ndbuffer.NDBuffer]):
25
+ """
26
+ TensorHolder for ndbuffer ndarrays.
27
+ """
28
+
29
+ name = "ndbuffer"
30
+ module = ndbuffer
31
+ name_to_dtype = TensorHolder.create_name_dtype_map(conversion_function=lambda name: name, exception_type=TypeError)
32
+
33
+ def __init__(self, tensor):
34
+ super().__init__(tensor)
35
+
36
+ @property
37
+ def data_ptr(self):
38
+ return self.tensor.data_ptr
39
+
40
+ @property
41
+ def device(self):
42
+ return self.tensor.device
43
+
44
+ @property
45
+ def device_id(self):
46
+ return self.tensor.device_id
47
+
48
+ @property
49
+ def dtype(self):
50
+ """Name of the data type"""
51
+ return self.tensor.dtype_name
52
+
53
+ @property
54
+ def itemsize(self):
55
+ return self.tensor.itemsize
56
+
57
+ @property
58
+ def shape(self):
59
+ return self.tensor.shape
60
+
61
+ @property
62
+ def size(self):
63
+ return self.tensor.size
64
+
65
+ @property
66
+ def strides(self):
67
+ return self.tensor.strides
68
+
69
+ @classmethod
70
+ def empty(
71
+ cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
72
+ ):
73
+ """
74
+ Create an empty tensor of the specified shape and data type.
75
+
76
+ Note, that the strides, if specified, MUST correspond to a dense (possibly permuted)
77
+ tensor, otherwise the created tensor may be corrupted.
78
+ """
79
+ itemsize = typemaps.NAME_TO_ITEM_SIZE[dtype]
80
+ if device_id == "cpu":
81
+ tensor = ndbuffer.empty(
82
+ shape, ndbuffer.CPU_DEVICE_ID, dtype, itemsize, strides=strides, stream=stream_holder, **context
83
+ )
84
+ else:
85
+ assert isinstance(device_id, int), "Internal Error: Cuda tensors must be allocated with an integer device_id."
86
+ with utils.device_ctx(device_id):
87
+ tensor = ndbuffer.empty(shape, device_id, dtype, itemsize, strides=strides, stream=stream_holder, **context)
88
+ return cls(tensor)
89
+
90
+ def asndbuffer(self):
91
+ return self.tensor
92
+
93
+ def to(self, device_id, stream_holder):
94
+ src_device_id = self.tensor.device_id
95
+ if src_device_id == device_id:
96
+ return self
97
+
98
+ if stream_holder is None:
99
+ raise ValueError("Stream holder is required for h2d/d2h transfers.")
100
+
101
+ if device_id == "cpu":
102
+ with utils.device_ctx(src_device_id):
103
+ tensor = ndbuffer.empty_like(self.tensor, device_id=ndbuffer.CPU_DEVICE_ID, stream=stream_holder)
104
+ ndbuffer.copy_into(tensor, self.tensor, stream_holder)
105
+ else:
106
+ with utils.device_ctx(device_id):
107
+ tensor = ndbuffer.empty_like(self.tensor, device_id=device_id, stream=stream_holder)
108
+ ndbuffer.copy_into(tensor, self.tensor, stream_holder)
109
+
110
+ return NDBufferTensor(tensor)
111
+
112
+ def copy_(self, src, stream_holder):
113
+ """
114
+ Inplace copy of src (copy the data from src into self).
115
+ """
116
+ device_id = self.tensor.device_id
117
+ src_nd = src._broadcast_to(self.shape).asndbuffer()
118
+ if device_id == "cpu":
119
+ device_id = src_nd.device_id
120
+ if device_id == "cpu":
121
+ ndbuffer.copy_into(self.tensor, src_nd, stream_holder)
122
+ else:
123
+ with utils.device_ctx(device_id):
124
+ ndbuffer.copy_into(self.tensor, src_nd, stream_holder)
125
+
126
+ def istensor(self):
127
+ """
128
+ Check if the object is ndarray-like.
129
+ """
130
+ return isinstance(self.tensor, ndbuffer.NDBuffer)
131
+
132
+ def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
133
+ if copy:
134
+ raise NotImplementedError("Reshape with copy is not supported for ndbuffer")
135
+ return self.__class__(ndbuffer.reshaped_view(self.tensor, shape))
136
+
137
+ def memory_buffer(self):
138
+ """Creates a view of the memory buffer as a 1D tensor."""
139
+ raise NotImplementedError
140
+
141
+ def memory_buffer_to_tensor(self, shape, strides):
142
+ """
143
+ Creates a N-D tensor view of the memory buffer according to the specified
144
+ shape and strides.
145
+ """
146
+ raise NotImplementedError
147
+
148
+ def _broadcast_to(self, shape):
149
+ if self.tensor.shape == shape:
150
+ return self
151
+ raise NotImplementedError(
152
+ f"_broadcast_to is not supported for ndbuffer. Current shape: {self.tensor.shape}, requested shape: {shape}."
153
+ )