nvmath-python 1.0.0__cp314-cp314t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) 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 +130 -0
  7. nvmath/_internal/threadsafe.py +106 -0
  8. nvmath/_internal/utils.py +43 -0
  9. nvmath/_internal/workspace.py +490 -0
  10. nvmath/_utils.py +147 -0
  11. nvmath/bindings/__init__.py +60 -0
  12. nvmath/bindings/_internal/__init__.pxd +0 -0
  13. nvmath/bindings/_internal/__init__.py +0 -0
  14. nvmath/bindings/_internal/common_types.pxd +31 -0
  15. nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
  16. nvmath/bindings/_internal/cublas.pxd +530 -0
  17. nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
  18. nvmath/bindings/_internal/cublasLt.pxd +59 -0
  19. nvmath/bindings/_internal/cublasMp.pxd +52 -0
  20. nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
  21. nvmath/bindings/_internal/cudss.pxd +54 -0
  22. nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
  23. nvmath/bindings/_internal/cufft.pxd +70 -0
  24. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  25. nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/curand.pxd +42 -0
  27. nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/cusolver.pxd +15 -0
  29. nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
  30. nvmath/bindings/_internal/cusolverDn.pxd +406 -0
  31. nvmath/bindings/_internal/cusolverMp.pxd +71 -0
  32. nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
  33. nvmath/bindings/_internal/cusolverSp.pxd +75 -0
  34. nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
  35. nvmath/bindings/_internal/cusparse.pxd +471 -0
  36. nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
  37. nvmath/bindings/_internal/cusparseLt.pxd +48 -0
  38. nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
  39. nvmath/bindings/_internal/cutensor.pxd +58 -0
  40. nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
  41. nvmath/bindings/_internal/mathdx.pxd +116 -0
  42. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  43. nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
  44. nvmath/bindings/_internal/utils.pxd +174 -0
  45. nvmath/bindings/_internal/utils.pyi +10 -0
  46. nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
  47. nvmath/bindings/cublas.pxd +558 -0
  48. nvmath/bindings/cublas.pyi +812 -0
  49. nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
  50. nvmath/bindings/cublasLt.pxd +109 -0
  51. nvmath/bindings/cublasLt.pyi +1461 -0
  52. nvmath/bindings/cublasMp.pxd +85 -0
  53. nvmath/bindings/cublasMp.pyi +267 -0
  54. nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
  55. nvmath/bindings/cudss.pxd +98 -0
  56. nvmath/bindings/cudss.pyi +443 -0
  57. nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
  58. nvmath/bindings/cufft.pxd +118 -0
  59. nvmath/bindings/cufft.pyi +301 -0
  60. nvmath/bindings/cufftMp.pxd +124 -0
  61. nvmath/bindings/cufftMp.pyi +326 -0
  62. nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
  63. nvmath/bindings/curand.pxd +71 -0
  64. nvmath/bindings/curand.pyi +189 -0
  65. nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
  66. nvmath/bindings/cusolver.pxd +62 -0
  67. nvmath/bindings/cusolver.pyi +320 -0
  68. nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
  69. nvmath/bindings/cusolverDn.pxd +430 -0
  70. nvmath/bindings/cusolverDn.pyi +422 -0
  71. nvmath/bindings/cusolverMp.pxd +98 -0
  72. nvmath/bindings/cusolverMp.pyi +114 -0
  73. nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
  74. nvmath/bindings/cusolverSp.pxd +95 -0
  75. nvmath/bindings/cusolverSp.pyi +70 -0
  76. nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
  77. nvmath/bindings/cusparse.pxd +546 -0
  78. nvmath/bindings/cusparse.pyi +1017 -0
  79. nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
  80. nvmath/bindings/cusparseLt.pxd +99 -0
  81. nvmath/bindings/cusparseLt.pyi +252 -0
  82. nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
  83. nvmath/bindings/cutensor.pxd +98 -0
  84. nvmath/bindings/cutensor.pyi +324 -0
  85. nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
  86. nvmath/bindings/cycublas.pxd +664 -0
  87. nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
  88. nvmath/bindings/cycublasLt.pxd +1045 -0
  89. nvmath/bindings/cycublasMp.pxd +171 -0
  90. nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
  91. nvmath/bindings/cycudss.pxd +277 -0
  92. nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
  93. nvmath/bindings/cycufft.pxd +333 -0
  94. nvmath/bindings/cycufftMp.pxd +342 -0
  95. nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
  96. nvmath/bindings/cycurand.pxd +141 -0
  97. nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
  98. nvmath/bindings/cycusolver.pxd +137 -0
  99. nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
  100. nvmath/bindings/cycusolverDn.pxd +443 -0
  101. nvmath/bindings/cycusolverMp.pxd +107 -0
  102. nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
  103. nvmath/bindings/cycusolverSp.pxd +93 -0
  104. nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
  105. nvmath/bindings/cycusparse.pxd +679 -0
  106. nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
  107. nvmath/bindings/cycusparseLt.pxd +135 -0
  108. nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
  109. nvmath/bindings/cycutensor.pxd +189 -0
  110. nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
  111. nvmath/bindings/cymathdx.pxd +552 -0
  112. nvmath/bindings/cynvshmem.pxd +118 -0
  113. nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
  114. nvmath/bindings/mathdx.pxd +182 -0
  115. nvmath/bindings/mathdx.pyi +1562 -0
  116. nvmath/bindings/nvpl/__init__.pxd +0 -0
  117. nvmath/bindings/nvpl/__init__.py +13 -0
  118. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  119. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  120. nvmath/bindings/nvpl/_internal/blas.cp314t-win_amd64.pyd +0 -0
  121. nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
  122. nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
  123. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  124. nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
  125. nvmath/bindings/nvpl/blas.pxd +131 -0
  126. nvmath/bindings/nvpl/blas.pyi +168 -0
  127. nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
  128. nvmath/bindings/nvpl/cyblas.pxd +280 -0
  129. nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
  130. nvmath/bindings/nvpl/cyfft.pxd +93 -0
  131. nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
  132. nvmath/bindings/nvpl/fft.pxd +100 -0
  133. nvmath/bindings/nvpl/fft.pyi +168 -0
  134. nvmath/bindings/nvshmem.pxd +54 -0
  135. nvmath/bindings/nvshmem.pyi +191 -0
  136. nvmath/device/__init__.py +38 -0
  137. nvmath/device/_deprecated.py +33 -0
  138. nvmath/device/common.py +315 -0
  139. nvmath/device/common_backend.py +131 -0
  140. nvmath/device/common_cuda.py +201 -0
  141. nvmath/device/common_numba.py +300 -0
  142. nvmath/device/common_numba_cuda_mlir.py +202 -0
  143. nvmath/device/common_opaque_tensor.py +201 -0
  144. nvmath/device/cublasdx.py +1606 -0
  145. nvmath/device/cublasdx_backend.py +860 -0
  146. nvmath/device/cublasdx_numba.py +1534 -0
  147. nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
  148. nvmath/device/cufftdx.py +373 -0
  149. nvmath/device/cufftdx_backend.py +220 -0
  150. nvmath/device/cufftdx_numba.py +140 -0
  151. nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
  152. nvmath/device/curand_kernel.py +9147 -0
  153. nvmath/device/cusolverdx.py +2708 -0
  154. nvmath/device/cusolverdx_backend.py +440 -0
  155. nvmath/device/cusolverdx_numba.py +567 -0
  156. nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
  157. nvmath/device/cusolverdx_overload_backend.py +1029 -0
  158. nvmath/device/llvm_array.py +29 -0
  159. nvmath/device/random.py +441 -0
  160. nvmath/device/random_helpers.py +23 -0
  161. nvmath/device/random_states.py +187 -0
  162. nvmath/device/types.py +138 -0
  163. nvmath/device/vector_types_numba.py +259 -0
  164. nvmath/distributed/__init__.py +200 -0
  165. nvmath/distributed/_internal/__init__.py +0 -0
  166. nvmath/distributed/_internal/nccl.py +86 -0
  167. nvmath/distributed/_internal/nvshmem.py +307 -0
  168. nvmath/distributed/_internal/symmetric_memory.py +35 -0
  169. nvmath/distributed/_internal/tensor_ifc.py +70 -0
  170. nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
  171. nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
  172. nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
  173. nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
  174. nvmath/distributed/_internal/tensor_wrapper.py +81 -0
  175. nvmath/distributed/_utils.py +167 -0
  176. nvmath/distributed/distribution/__init__.py +30 -0
  177. nvmath/distributed/distribution/_configuration.py +39 -0
  178. nvmath/distributed/distribution/distributions.py +1024 -0
  179. nvmath/distributed/distribution/redistribute.py +1284 -0
  180. nvmath/distributed/fft/__init__.py +7 -0
  181. nvmath/distributed/fft/_configuration.py +82 -0
  182. nvmath/distributed/fft/fft.py +2742 -0
  183. nvmath/distributed/linalg/__init__.py +22 -0
  184. nvmath/distributed/linalg/_internal/__init__.py +3 -0
  185. nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -0
  186. nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
  187. nvmath/distributed/linalg/advanced/__init__.py +8 -0
  188. nvmath/distributed/linalg/advanced/_configuration.py +171 -0
  189. nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
  190. nvmath/distributed/linalg/generic/__init__.py +8 -0
  191. nvmath/distributed/linalg/generic/_caching.py +66 -0
  192. nvmath/distributed/linalg/generic/_configuration.py +61 -0
  193. nvmath/distributed/linalg/generic/_factorization.py +172 -0
  194. nvmath/distributed/linalg/generic/_initialization.py +966 -0
  195. nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
  196. nvmath/distributed/linalg/generic/solvermod.py +1368 -0
  197. nvmath/distributed/process_group.py +408 -0
  198. nvmath/fft/__init__.py +7 -0
  199. nvmath/fft/_configuration.py +189 -0
  200. nvmath/fft/_exec_utils.py +82 -0
  201. nvmath/fft/_helpers.py +237 -0
  202. nvmath/fft/fft.py +3122 -0
  203. nvmath/internal/__init__.pxd +3 -0
  204. nvmath/internal/__init__.py +10 -0
  205. nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
  206. nvmath/internal/_bindings.pxd +18 -0
  207. nvmath/internal/_device_utils.py +45 -0
  208. nvmath/internal/_layout/__init__.pxd +3 -0
  209. nvmath/internal/_layout/__init__.py +7 -0
  210. nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
  211. nvmath/internal/_layout/_layout.pxd +1303 -0
  212. nvmath/internal/_layout/_layout.pyi +1145 -0
  213. nvmath/internal/enum_utils.py +142 -0
  214. nvmath/internal/formatters.py +87 -0
  215. nvmath/internal/mem_limit.py +51 -0
  216. nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
  217. nvmath/internal/memory.pxd +13 -0
  218. nvmath/internal/memory.pyi +50 -0
  219. nvmath/internal/ndbuffer/__init__.pxd +3 -0
  220. nvmath/internal/ndbuffer/__init__.py +9 -0
  221. nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
  222. nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
  223. nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
  224. nvmath/internal/ndbuffer/_jit.pxd +7 -0
  225. nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
  226. nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
  227. nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -0
  228. nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
  229. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
  230. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
  231. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
  232. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +242 -0
  233. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
  234. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
  235. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
  236. nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
  237. nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
  238. nvmath/internal/package_ifc.py +168 -0
  239. nvmath/internal/package_ifc_cuda.py +57 -0
  240. nvmath/internal/package_ifc_cupy.py +67 -0
  241. nvmath/internal/package_ifc_torch.py +69 -0
  242. nvmath/internal/package_wrapper.py +14 -0
  243. nvmath/internal/tensor_ifc.py +179 -0
  244. nvmath/internal/tensor_ifc_cupy.py +234 -0
  245. nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
  246. nvmath/internal/tensor_ifc_numpy.py +184 -0
  247. nvmath/internal/tensor_ifc_torch.py +178 -0
  248. nvmath/internal/tensor_wrapper.py +160 -0
  249. nvmath/internal/typemaps.py +113 -0
  250. nvmath/internal/utils.py +805 -0
  251. nvmath/linalg/__init__.py +56 -0
  252. nvmath/linalg/_internal/__init__.py +3 -0
  253. nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
  254. nvmath/linalg/_internal/algo_config_ifc.py +43 -0
  255. nvmath/linalg/_internal/batch.py +234 -0
  256. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  257. nvmath/linalg/_internal/epilog_protocol.py +766 -0
  258. nvmath/linalg/_internal/layout.py +624 -0
  259. nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
  260. nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
  261. nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
  262. nvmath/linalg/_internal/solver_utils.py +432 -0
  263. nvmath/linalg/_internal/typemaps.py +144 -0
  264. nvmath/linalg/_internal/utils.py +157 -0
  265. nvmath/linalg/advanced/__init__.py +8 -0
  266. nvmath/linalg/advanced/_algorithmmod.py +170 -0
  267. nvmath/linalg/advanced/_configuration.py +351 -0
  268. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  269. nvmath/linalg/advanced/helpers/matmul.py +1316 -0
  270. nvmath/linalg/advanced/matmulmod.py +3734 -0
  271. nvmath/linalg/generic/__init__.py +53 -0
  272. nvmath/linalg/generic/_configuration/__init__.py +39 -0
  273. nvmath/linalg/generic/_configuration/layout.py +263 -0
  274. nvmath/linalg/generic/_configuration/match.py +734 -0
  275. nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
  276. nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
  277. nvmath/linalg/generic/_configuration/wrap.py +217 -0
  278. nvmath/linalg/generic/_dtype.py +15 -0
  279. nvmath/linalg/generic/matmulmod.py +2094 -0
  280. nvmath/linalg/generic/solvermod.py +1301 -0
  281. nvmath/memory.py +279 -0
  282. nvmath/sparse/__init__.py +38 -0
  283. nvmath/sparse/_internal/__init__.py +21 -0
  284. nvmath/sparse/_internal/common_utils.py +147 -0
  285. nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
  286. nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
  287. nvmath/sparse/_internal/cudss_utils.py +506 -0
  288. nvmath/sparse/_internal/cusparse_utils.py +382 -0
  289. nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
  290. nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
  291. nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
  292. nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
  293. nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
  294. nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
  295. nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
  296. nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
  297. nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
  298. nvmath/sparse/_internal/utils.py +56 -0
  299. nvmath/sparse/advanced/__init__.py +7 -0
  300. nvmath/sparse/advanced/_configuration.py +227 -0
  301. nvmath/sparse/advanced/direct_solver.py +2069 -0
  302. nvmath/sparse/generic/__init__.py +7 -0
  303. nvmath/sparse/generic/_configuration.py +129 -0
  304. nvmath/sparse/generic/_helpers.py +137 -0
  305. nvmath/sparse/generic/_thunks.py +21 -0
  306. nvmath/sparse/generic/matmulmod.py +2353 -0
  307. nvmath/sparse/ust/__init__.py +7 -0
  308. nvmath/sparse/ust/_converters.py +422 -0
  309. nvmath/sparse/ust/_cpp.py +28 -0
  310. nvmath/sparse/ust/_drawer.py +565 -0
  311. nvmath/sparse/ust/_emitter.py +1033 -0
  312. nvmath/sparse/ust/_jit.py +188 -0
  313. nvmath/sparse/ust/_kernel.py +282 -0
  314. nvmath/sparse/ust/_utils.py +149 -0
  315. nvmath/sparse/ust/interfaces/__init__.py +0 -0
  316. nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
  317. nvmath/sparse/ust/tensor.py +1016 -0
  318. nvmath/sparse/ust/tensor_format.py +957 -0
  319. nvmath/tensor/__init__.py +6 -0
  320. nvmath/tensor/_configuration.py +120 -0
  321. nvmath/tensor/_internal/__init__.py +3 -0
  322. nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
  323. nvmath/tensor/_internal/cutensor_utils.py +230 -0
  324. nvmath/tensor/_internal/data.py +43 -0
  325. nvmath/tensor/_internal/einsum_parser.py +444 -0
  326. nvmath/tensor/_internal/typemaps.py +96 -0
  327. nvmath/tensor/contract.py +1900 -0
  328. nvmath_python-1.0.0.dist-info/METADATA +134 -0
  329. nvmath_python-1.0.0.dist-info/RECORD +332 -0
  330. nvmath_python-1.0.0.dist-info/WHEEL +5 -0
  331. nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
  332. nvmath_python-1.0.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,307 @@
1
+ # Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from __future__ import annotations
6
+
7
+ __all__ = [
8
+ "initialize",
9
+ "finalize",
10
+ "is_initialized",
11
+ "nvshmem_empty_dlpack",
12
+ "free",
13
+ "NvshmemMemoryManager",
14
+ "NvshmemNDBufferAllocator",
15
+ ]
16
+
17
+ import atexit
18
+ import logging
19
+ from typing import TYPE_CHECKING
20
+
21
+ import numpy as np
22
+ from cuda.core import Buffer, Device, MemoryResource, Stream
23
+
24
+ from nvmath import memory
25
+ from nvmath.bindings import nvshmem # type: ignore
26
+ from nvmath.distributed.process_group import ProcessGroup
27
+ from nvmath.internal.utils import device_ctx
28
+
29
+ from .symmetric_memory import calculate_symmetric_size
30
+
31
+ if TYPE_CHECKING:
32
+ from nvmath.distributed import DistributedContext
33
+
34
+ # Indicates if this module has initialized NVSHMEM
35
+ _nvshmem_initialized_here = False
36
+
37
+ _atexit_registered = False
38
+ _exiting = False
39
+
40
+
41
+ def initialize(device_id: int, process_group: ProcessGroup) -> None:
42
+ """Initialize NVSHMEM runtime if not initialized, otherwise do nothing.
43
+ NOTE: device_id must be set as the current device, and a CUDA context must have
44
+ been created for this device.
45
+ """
46
+
47
+ global _nvshmem_initialized_here
48
+
49
+ rank = process_group.rank
50
+ nranks = process_group.nranks
51
+
52
+ status = nvshmem.init_status()
53
+ if status > nvshmem.STATUS_IS_BOOTSTRAPPED:
54
+ # NVSHMEM is already initialized
55
+ # NOTE: We assume that the user has passed the same communicator and device_id
56
+ # on which NVSHMEM was initialized (we have no way of checking here).
57
+ assert nvshmem.n_pes() == nranks
58
+ return
59
+ elif status == nvshmem.STATUS_IS_BOOTSTRAPPED:
60
+ # A value of 0 indicates an initialization that is similar to when nvshmem_init
61
+ # is used.
62
+ nvshmem.hostlib_init_attr(0, 0)
63
+ assert nvshmem.n_pes() == nranks
64
+ # Sanity check, can eventually remove
65
+ assert nvshmem.init_status() > nvshmem.STATUS_IS_BOOTSTRAPPED
66
+ _nvshmem_initialized_here = True
67
+ return
68
+
69
+ attr = nvshmem.InitAttr()
70
+ unique_id = nvshmem.UniqueId()
71
+ # PE 0 queries the unique ID
72
+ if rank == 0:
73
+ nvshmem.get_uniqueid(unique_id.ptr)
74
+ # PE 0 broadcasts the unique ID
75
+ process_group.broadcast_buffer(unique_id._data.view(np.int8), root=0) # type: ignore[attr-defined]
76
+ nvshmem.set_attr_uniqueid_args(rank, nranks, unique_id.ptr, attr.ptr)
77
+ nvshmem.hostlib_init_attr(nvshmem.Flags.INIT_WITH_UNIQUEID, attr.ptr)
78
+
79
+ # sanity check
80
+ assert nvshmem.init_status() > nvshmem.STATUS_IS_BOOTSTRAPPED
81
+ _nvshmem_initialized_here = True
82
+ _register_atexit_maybe()
83
+
84
+
85
+ def _register_atexit_maybe() -> None:
86
+ global _atexit_registered
87
+ if not _atexit_registered:
88
+ atexit.register(_detect_exit)
89
+ _atexit_registered = True
90
+
91
+
92
+ def _detect_exit() -> None:
93
+ global _exiting
94
+ _exiting = True
95
+
96
+
97
+ def finalize(device_id: int) -> None:
98
+ """Finalize NVSHMEM runtime if initialized"""
99
+ global _nvshmem_initialized_here
100
+ if not _nvshmem_initialized_here or (nvshmem.init_status() < nvshmem.STATUS_IS_INITIALIZED):
101
+ return
102
+
103
+ with device_ctx(device_id):
104
+ nvshmem.hostlib_finalize()
105
+ _nvshmem_initialized_here = False
106
+
107
+
108
+ def is_initialized() -> bool:
109
+ return nvshmem.init_status() >= nvshmem.STATUS_IS_INITIALIZED
110
+
111
+
112
+ def _check_initialized():
113
+ if nvshmem.init_status() < nvshmem.STATUS_IS_INITIALIZED:
114
+ raise RuntimeError("NVSHMEM is not initialized. Please initialize nvmath.distributed with NVSHMEM backend")
115
+ _register_atexit_maybe()
116
+
117
+
118
+ # Keeps track of memory allocated with nvshmem_empty_dlpack. This is used to report memory
119
+ # leaks and double free errors. This functionality might be handled by nvshmem4py in the
120
+ # future. More precisely, how it works is that when a buffer allocated via
121
+ # nvshmem_empty_dlpack is garbage-collected and found to not have been freed explicitly
122
+ # with the `free` function in this module, we report it.
123
+ _resource_registry = {}
124
+
125
+
126
+ class _NvshmemResource(MemoryResource):
127
+ def __init__(self, device):
128
+ self.device = device
129
+
130
+ def allocate(self, size, *, stream=None) -> Buffer:
131
+ # NOTE: setting the device is left to the caller
132
+ ptr = nvshmem.malloc(size)
133
+ if ptr == 0 and size != 0:
134
+ raise MemoryError("nvshmem_malloc returned NULL")
135
+ self.freed = False
136
+ return Buffer.from_handle(ptr=ptr, size=size, mr=self)
137
+
138
+ def deallocate(self, ptr, size, stream=None, *, manual=False):
139
+ # `stream` must NOT be keyword-only: cuda.core < 1 calls deallocate with all
140
+ # arguments positionally (Buffer.close -> mr.deallocate(ptr, size, stream)).
141
+ # NOTE: setting the device is left to the caller
142
+ if not manual:
143
+ if self.freed:
144
+ return # this is fine
145
+ else:
146
+ # We can't call nvshmem_free when deallocate is triggered by the GC, since
147
+ # the GC has non-deterministic behavior and nvshmem_free is a collective
148
+ # call.
149
+ if not _exiting:
150
+ logging.error("Symmetric heap memory needs to be deallocated explicitly")
151
+ else:
152
+ logging.error(
153
+ "Symmetric heap memory was not deallocated explicitly (you may have "
154
+ "forgotten to clean up before exit, or an unrelated exception "
155
+ "crashed the program)"
156
+ )
157
+ return
158
+ if self.freed:
159
+ raise RuntimeError("This memory resource was already deallocated")
160
+ nvshmem.free(ptr)
161
+ self.freed = True
162
+
163
+ @property
164
+ def is_device_accessible(self) -> bool:
165
+ return True
166
+
167
+ @property
168
+ def is_host_accessible(self) -> bool:
169
+ return False
170
+
171
+ @property
172
+ def device_id(self) -> int:
173
+ return self.device.device_id
174
+
175
+
176
+ def nvshmem_empty_dlpack(
177
+ size: int,
178
+ device_id: int,
179
+ process_group: ProcessGroup,
180
+ make_symmetric: bool = False,
181
+ skip_symmetric_check: bool = False,
182
+ logger: logging.Logger | None = None,
183
+ ) -> Buffer:
184
+ """Return uninitialized DLPack buffer of given size in bytes, allocated using
185
+ nvshmem_malloc (which makes this a *collective* call). Note that the DLPack
186
+ buffer currently does not include any shape, dtype, or stride information.
187
+
188
+ IMPORTANT: device_id must be the one with which NVSHMEM was initialized, and
189
+ setting the device is left to the caller.
190
+
191
+ Args:
192
+ size: Number of bytes to allocate.
193
+
194
+ device_id: Device on which to allocate.
195
+
196
+ process_group: nvmath.distributed process group.
197
+
198
+ make_symmetric: Use ``make_symmetric=True`` to allocate the same size on every
199
+ process (padding the buffer to the maximum size given by all processes).
200
+
201
+ skip_symmetric_check: True if buffer is already known to be of the same size
202
+ on every process.
203
+ """
204
+
205
+ _check_initialized()
206
+
207
+ global _resource_registry
208
+
209
+ logger = logger if logger is not None else logging.getLogger()
210
+
211
+ size = calculate_symmetric_size(size, process_group, make_symmetric, skip_symmetric_check, logger)
212
+
213
+ mem = _NvshmemResource(Device(device_id))
214
+ mem_buffer = mem.allocate(size)
215
+ pointer = int(mem_buffer.handle)
216
+ assert pointer not in _resource_registry
217
+ _resource_registry[pointer] = (mem, size)
218
+ return mem_buffer
219
+
220
+
221
+ def free(pointer):
222
+ """This is a *collective* call (invokes nvshmem_free), used to free buffers
223
+ allocated with nvshmem_empty_dlpack.
224
+ Setting the device is left to the caller"""
225
+
226
+ _check_initialized()
227
+
228
+ global _resource_registry
229
+
230
+ try:
231
+ resource, size = _resource_registry.pop(pointer)
232
+ except KeyError as e:
233
+ raise RuntimeError(
234
+ "Unknown pointer to free. Possible causes:\n"
235
+ " - This memory was not allocated with nvmath.distributed helpers.\n"
236
+ " - This memory was already freed. Possible causes:\n"
237
+ " - Free was called multiple times on the same tensor.\n"
238
+ " - You have multiple tensors sharing the same symmetric memory buffer,\n"
239
+ " e.g. as a result of inplace operations, or tensor operations that\n"
240
+ " result in views such as slicing."
241
+ ) from e
242
+ resource.deallocate(pointer, size, manual=True)
243
+
244
+
245
+ class NvshmemMemoryManager(memory.BaseCUDAMemoryManager):
246
+ """
247
+ Nvshmem memory allocator.
248
+
249
+ Args:
250
+ device_id: The ID (int) of the device on which memory is to be allocated.
251
+ logger (logging.Logger): Python Logger object.
252
+ """
253
+
254
+ def __init__(self, device_id, logger):
255
+ """
256
+ __init__(device_id)
257
+ """
258
+ _check_initialized()
259
+ self.device_id = device_id
260
+ self.logger = logger
261
+
262
+ def memalloc(self, size):
263
+ """This is a *collective* call (invokes nvshmem_malloc)"""
264
+ mem = _NvshmemResource(Device(self.device_id))
265
+ mem_buffer = mem.allocate(size)
266
+ pointer = int(mem_buffer.handle)
267
+ assert pointer not in _resource_registry
268
+ _resource_registry[pointer] = (mem, size)
269
+
270
+ self.logger.debug(
271
+ f"NvshmemMemoryManager (allocate memory): size = {size}, pointer = {pointer}, device_id = {self.device_id}"
272
+ )
273
+
274
+ return SymmetricMemoryPointer(mem_buffer)
275
+
276
+
277
+ class NvshmemNDBufferAllocator:
278
+ __slots__ = ("ctx", "make_symmetric", "skip_symmetric_check")
279
+
280
+ def __init__(self, device_id: int, ctx: DistributedContext, make_symmetric: bool, skip_symmetric_check: bool):
281
+ assert ctx.device_id == device_id, (
282
+ "Internal error: attempting to allocate symmetric memory on a device not used "
283
+ "by the NVSHMEM runtime on this process"
284
+ )
285
+ self.ctx = ctx
286
+ self.make_symmetric = make_symmetric
287
+ self.skip_symmetric_check = skip_symmetric_check
288
+
289
+ def allocate(self, size: int, stream: Stream, logger: logging.Logger | None = None) -> Buffer:
290
+ return nvshmem_empty_dlpack(
291
+ size,
292
+ self.ctx.device_id,
293
+ self.ctx.process_group,
294
+ make_symmetric=self.make_symmetric,
295
+ skip_symmetric_check=self.skip_symmetric_check,
296
+ logger=logger,
297
+ )
298
+
299
+
300
+ class SymmetricMemoryPointer(memory.MemoryPointer):
301
+ def __init__(self, mem_buffer):
302
+ super().__init__(int(mem_buffer.handle), mem_buffer.size, finalizer=None)
303
+ self.mem_buffer = mem_buffer
304
+
305
+ def free(self):
306
+ """This is a *collective* call (invokes nvshmem_free)"""
307
+ free(self.device_ptr)
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ __all__ = ["calculate_symmetric_size"]
6
+
7
+ import numpy as np
8
+
9
+ from nvmath.distributed.process_group import ReductionOp
10
+
11
+
12
+ def calculate_symmetric_size(size, process_group, make_symmetric, skip_symmetric_check, logger):
13
+ if make_symmetric and skip_symmetric_check:
14
+ raise ValueError("skip_symmetric_check is incompatible with make_symmetric=True")
15
+
16
+ if not skip_symmetric_check:
17
+ max_size = np.array([-size, size], dtype=np.int64)
18
+ process_group.allreduce_buffer(max_size, op=ReductionOp.MAX)
19
+ if -max_size[0] != max_size[1]:
20
+ # The buffer size is not the same on all processes.
21
+ if make_symmetric:
22
+ logger.info(
23
+ "Symmetric memory allocator: the buffer will be padded on some processes to "
24
+ f"satisfy symmetric requirement (make_symmetric=True), size={size} max_size={max_size[1]}."
25
+ )
26
+ else:
27
+ raise ValueError(
28
+ "The buffer size for symmetric memory allocation is not the same on all processes. "
29
+ "Consider using make_symmetric=True if you have uneven data distribution."
30
+ )
31
+ else:
32
+ logger.info(f"Symmetric memory allocator: the requested buffer size ({size}) is the same on all processes.")
33
+ # Sizes are equal or make_symmetric=True.
34
+ size = max_size[1]
35
+ return size
@@ -0,0 +1,70 @@
1
+ # Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Common distributed tensor interface.
7
+ """
8
+
9
+ from __future__ import annotations # allows typehint of class methods to return the self class
10
+
11
+ __all__ = ["DistributedTensor"]
12
+
13
+ from abc import abstractmethod
14
+ from collections.abc import Sequence
15
+ from typing import Literal
16
+
17
+ from nvmath.bindings import nvshmem # type: ignore
18
+ from nvmath.distributed._internal.nvshmem import free
19
+ from nvmath.distributed._internal.nvshmem import is_initialized as is_nvshmem_initialized
20
+ from nvmath.internal.package_ifc import StreamHolder
21
+ from nvmath.internal.tensor_ifc import Tensor, TensorHolder
22
+
23
+
24
+ class DistributedTensor(TensorHolder[Tensor]):
25
+ """Base class for distributed tensors.
26
+
27
+ Sets flag during construction to indicate if the tensor is on NVSHMEM symmetric memory
28
+ or not.
29
+ """
30
+
31
+ def __init__(self, tensor):
32
+ super().__init__(tensor)
33
+ self._is_symmetric_memory = False
34
+ if self.device == "cuda" and is_nvshmem_initialized():
35
+ self._is_symmetric_memory = nvshmem.ptr(self.data_ptr, nvshmem.my_pe()) != 0
36
+
37
+ @property
38
+ def is_symmetric_memory(self):
39
+ """True if the tensor is on NVSHMEM symmetric heap.
40
+
41
+ This doesn't apply to NCCL because window registrations in NCCL are
42
+ on a per-communicator basis, not global.
43
+ """
44
+ return self._is_symmetric_memory
45
+
46
+ @abstractmethod
47
+ def to(
48
+ self,
49
+ device_id: int | Literal["cpu"],
50
+ stream_holder: StreamHolder | None,
51
+ symmetric_memory: None | Literal["nvshmem", "nccl"] = None,
52
+ ) -> DistributedTensor:
53
+ """Copy the TensorHolder to a different device.
54
+
55
+ No copy is performed if the TensorHolder is already on the requested device.
56
+ """
57
+ raise NotImplementedError
58
+
59
+ @abstractmethod
60
+ def reshape(self, shape: Sequence[int], *, copy: bool | None = None) -> DistributedTensor:
61
+ raise NotImplementedError
62
+
63
+ def free_symmetric(self) -> None:
64
+ """
65
+ Release this tensor's allocation on NVSHMEM symmetric memory heap.
66
+ """
67
+ if not self._is_symmetric_memory:
68
+ raise TypeError("tensor is not on symmetric memory")
69
+
70
+ free(self.data_ptr)
@@ -0,0 +1,68 @@
1
+ # Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Interface to seamlessly use distributed Cupy ndarray objects.
7
+ """
8
+
9
+ from __future__ import annotations # allows typehint of class methods to return the self class
10
+
11
+ __all__ = ["CupyDistributedTensor", "HostDistributedTensor"]
12
+
13
+
14
+ try:
15
+ import cupy
16
+ except ImportError:
17
+ cupy = None
18
+
19
+
20
+ from nvmath.internal.ndbuffer import NDBuffer
21
+ from nvmath.internal.tensor_ifc_cupy import CupyTensor, HostTensor
22
+
23
+ from .tensor_ifc import DistributedTensor
24
+ from .tensor_ifc_host_device import CudaDistributedTensorMixIn, HostDistributedTensorMixIn
25
+
26
+
27
+ class HostDistributedTensor(HostDistributedTensorMixIn, HostTensor, DistributedTensor):
28
+ host_tensor_class: type[HostDistributedTensor] # set at the end of the file
29
+ device_tensor_class: type[CupyDistributedTensor] # set at the end of the file
30
+
31
+
32
+ # Most methods aren't redefined, because they simply act on the local array
33
+ class CupyDistributedTensor(CudaDistributedTensorMixIn, CupyTensor, DistributedTensor):
34
+ """
35
+ Tensor wrapper for distributed cupy ndarrays.
36
+ """
37
+
38
+ host_tensor_class: type[HostDistributedTensor] # set at the end of the file
39
+ device_tensor_class: type[CupyDistributedTensor] # set at the end of the file
40
+
41
+ @classmethod
42
+ def wrap_ndbuffer(cls, ndbuffer: NDBuffer) -> CupyDistributedTensor:
43
+ """
44
+ Wraps NDBuffer into a cupy.ndarray, the method assumes the
45
+ NDBuffer is backed by CUDA device memory.
46
+ """
47
+ base_ptr, size_in_bytes, offset_in_bytes = ndbuffer.raw_memory_range_info
48
+ mem = cupy.cuda.UnownedMemory(
49
+ base_ptr,
50
+ size_in_bytes,
51
+ owner=ndbuffer.data,
52
+ device_id=ndbuffer.device_id,
53
+ )
54
+ memptr = cupy.cuda.MemoryPointer(mem, offset=offset_in_bytes)
55
+ dtype = cls.name_to_dtype[ndbuffer.dtype_name]
56
+ tensor = cupy.ndarray(
57
+ ndbuffer.shape,
58
+ dtype=dtype,
59
+ strides=ndbuffer.strides_in_bytes,
60
+ memptr=memptr,
61
+ )
62
+ return cls(tensor)
63
+
64
+
65
+ HostDistributedTensor.host_tensor_class = HostDistributedTensor
66
+ CupyDistributedTensor.host_tensor_class = HostDistributedTensor
67
+ HostDistributedTensor.device_tensor_class = CupyDistributedTensor
68
+ CupyDistributedTensor.device_tensor_class = CupyDistributedTensor
@@ -0,0 +1,172 @@
1
+ # Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Mixins for handling host <-> device symmetry for distributed tensors
7
+ for packages that support only host or device tensors.
8
+
9
+ Most of the symmetric-memory logic is not package-specific, but handling
10
+ regular allocations or local tensor operations is, and can be delegated
11
+ to the non-distributed tensor implementation.
12
+ For this reason, the functionality is implemented as mixins, so that
13
+ we can delegate the `super()` calls without specifying the parent class.
14
+ """
15
+
16
+ from abc import ABC, abstractmethod
17
+ from collections.abc import Sequence
18
+ from typing import Literal
19
+
20
+ __all__ = ["HostDistributedTensorMixIn", "CudaDistributedTensorMixIn"]
21
+
22
+ import nvmath.distributed
23
+ from nvmath.distributed._internal.nccl import NcclNDBufferAllocator
24
+ from nvmath.distributed._internal.nvshmem import NvshmemNDBufferAllocator
25
+ from nvmath.internal.ndbuffer import NDBuffer, StridedLayout
26
+ from nvmath.internal.package_ifc import StreamHolder
27
+ from nvmath.internal.tensor_ifc import TensorHolder
28
+ from nvmath.internal.typemaps import NAME_TO_ITEM_SIZE
29
+ from nvmath.internal.utils import device_ctx
30
+
31
+
32
+ class HostDistributedTensorMixIn(ABC): # noqa: B024
33
+ """
34
+ Host counterpart for distributed tensor wrapping package that
35
+ does not support host memory space (e.g. cupy). The class is marked
36
+ as abstract, because the mixin is not meant to be instantiated directly.
37
+ """
38
+
39
+ def to(self, device_id, stream_holder, symmetric_memory: None | Literal["nvshmem", "nccl"] = None):
40
+ """
41
+ In addition to the base class semantics:
42
+ - If symmetric_memory != None, target device must be the one used to initialize
43
+ NVSHMEM or NCCL on this process.
44
+ - Strides must be dense non-overlapping.
45
+ - Memory layout is preserved (if strides are dense non-overlapping,
46
+ the base class guarantees that)
47
+ """
48
+ if not symmetric_memory or device_id == "cpu":
49
+ tensor = super().to(device_id, stream_holder) # type: ignore
50
+ elif isinstance(device_id, int):
51
+ device_cls = self.device_tensor_class # type: ignore
52
+ tensor = device_cls.create_from_host(self, device_id, stream_holder, symmetric_memory)
53
+ else:
54
+ raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
55
+ assert tensor.is_symmetric_memory == (symmetric_memory == "nvshmem")
56
+ return tensor
57
+
58
+
59
+ def _get_symmetric_memory_allocator(backend: Literal["nvshmem", "nccl"]):
60
+ if backend == "nvshmem":
61
+ return NvshmemNDBufferAllocator
62
+ elif backend == "nccl":
63
+ return NcclNDBufferAllocator
64
+ raise AssertionError(f"Internal error: unsupported backend {backend}.")
65
+
66
+
67
+ class CudaDistributedTensorMixIn(ABC):
68
+ @classmethod
69
+ def empty(
70
+ cls,
71
+ shape,
72
+ device_id="cpu",
73
+ *,
74
+ dtype="float32",
75
+ strides=None,
76
+ stream_holder: StreamHolder | None = None,
77
+ **context,
78
+ ):
79
+ """
80
+ Create an empty tensor of the specified shape and data type.
81
+
82
+ Note, that the strides, if specified, MUST correspond to a dense (possibly permuted)
83
+ tensor, otherwise the created tensor may be corrupted.
84
+ """
85
+ symmetric_memory = context.pop("symmetric_memory", None)
86
+ make_symmetric = context.pop("make_symmetric", False)
87
+ skip_symmetric_check = context.pop("skip_symmetric_check", False)
88
+
89
+ if not symmetric_memory:
90
+ if make_symmetric or skip_symmetric_check:
91
+ raise ValueError("Use of symmetric memory option with symmetric_memory=None")
92
+ return super().empty( # type: ignore
93
+ shape,
94
+ device_id=device_id,
95
+ dtype=dtype,
96
+ strides=strides,
97
+ stream_holder=stream_holder,
98
+ **context,
99
+ )
100
+
101
+ allocator_cls = _get_symmetric_memory_allocator(symmetric_memory)
102
+
103
+ logger = context.get("logger")
104
+ with device_ctx(device_id):
105
+ ctx = nvmath.distributed.get_context()
106
+ assert ctx is not None, "nvmath.distributed has not been initialized"
107
+ allocator = allocator_cls(device_id, ctx, make_symmetric=make_symmetric, skip_symmetric_check=skip_symmetric_check)
108
+ layout = StridedLayout(shape, strides, NAME_TO_ITEM_SIZE[dtype])
109
+ if not layout.is_contiguous_c and not layout.is_contiguous_f:
110
+ raise ValueError("CudaDistributedTensor only supports 'C' or 'F' order")
111
+ nd_dst = NDBuffer.empty(layout, dtype, device_id, stream=stream_holder, memory_resource=allocator, logger=logger)
112
+ return cls.wrap_ndbuffer(nd_dst)
113
+
114
+ @classmethod
115
+ def create_from_host(
116
+ cls,
117
+ tensor: TensorHolder,
118
+ device_id: int,
119
+ stream_holder: StreamHolder,
120
+ symmetric_memory: None | Literal["nvshmem", "nccl"] = None,
121
+ ):
122
+ if not symmetric_memory:
123
+ return super().create_from_host(tensor, device_id, stream_holder) # type: ignore
124
+
125
+ allocator_cls = _get_symmetric_memory_allocator(symmetric_memory)
126
+
127
+ with device_ctx(device_id):
128
+ ctx = nvmath.distributed.get_context()
129
+ assert ctx is not None, "nvmath.distributed has not been initialized"
130
+ allocator = allocator_cls(device_id, ctx, make_symmetric=True, skip_symmetric_check=False)
131
+ src_ndbuffer = tensor.asndbuffer()
132
+ dst_ndbuffer = NDBuffer.empty_like(
133
+ src_ndbuffer,
134
+ device_id=device_id,
135
+ stream=stream_holder,
136
+ memory_resource=allocator,
137
+ )
138
+ layout = dst_ndbuffer.layout
139
+ if not layout.is_contiguous_c and not layout.is_contiguous_f:
140
+ raise ValueError("CudaDistributedTensor only supports 'C' or 'F' order")
141
+ dst_ndbuffer.copy_(src_ndbuffer, stream=stream_holder)
142
+ return cls.wrap_ndbuffer(dst_ndbuffer)
143
+
144
+ @classmethod
145
+ @abstractmethod
146
+ def wrap_ndbuffer(cls, ndbuffer: NDBuffer):
147
+ """
148
+ Defines how to wrap NDBuffer into a distributed tensor instance.
149
+ The exact implementation depends on `self.tensor` type
150
+ expected by the TensorHolder implementation to be mixed in.
151
+ E.g. for NDBufferTensor, it suffices to call `cls(ndbuffer)`,
152
+ while for CupyTensor, we need to wrap the NDBuffer into a cupy.ndarray first.
153
+ """
154
+ raise NotImplementedError
155
+
156
+ def to(self, device_id, stream_holder, symmetric_memory: None | Literal["nvshmem", "nccl"] = None):
157
+ """
158
+ In addition to the base class semantics:
159
+ - Target device must be the one used to initialize NVSHMEM or NCCL on
160
+ this process.
161
+ - Strides must be dense non-overlapping.
162
+ - Memory layout is preserved (if strides are dense non-overlapping,
163
+ the base class guarantees that)
164
+ """
165
+ tensor = super().to(device_id, stream_holder) # type: ignore
166
+ assert tensor.is_symmetric_memory == (symmetric_memory == "nvshmem")
167
+ return tensor
168
+
169
+ def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
170
+ if copy:
171
+ raise NotImplementedError("reshape with copy=True is not supported for CUDA distributed tensor")
172
+ return super().reshape(shape, copy=copy) # type: ignore