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,476 @@
1
+ # Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ This module overrides PyTorch tensors with the UST (for easy "injection").
7
+ """
8
+
9
+ __all__ = ["TorchUST", "prune_model", "reformat_model"]
10
+
11
+
12
+ import numbers
13
+ from collections.abc import Callable
14
+ from typing import Any
15
+
16
+ import numpy as np
17
+ import torch
18
+ import torch.nn.utils.prune as prune
19
+
20
+ from nvmath.sparse.generic import Matmul
21
+ from nvmath.sparse.ust._utils import Cache
22
+ from nvmath.sparse.ust.tensor import Tensor
23
+
24
+ _MATMUL_CACHE = Cache()
25
+
26
+
27
+ def _matmul(A, B, C_shape, transpose_a=False):
28
+ a = A.ust
29
+ b = Tensor.from_package(B)
30
+
31
+ vtp = a.dtype
32
+ itp = a.index_type
33
+ format_a = a.tensor_format.name
34
+ format_b = b.tensor_format.name
35
+ sizes = (tuple(a.extents), tuple(b.extents), C_shape)
36
+
37
+ # Lookup matmul. Also recycles the result tensor allocation.
38
+ key = (vtp, itp, format_a, format_b, transpose_a, sizes, A.stream, A.device)
39
+ mm = _MATMUL_CACHE.get(key)
40
+ if mm is None:
41
+ t = torch.zeros(C_shape, dtype=A.dtype, device=A.device)
42
+ c = Tensor.from_package(t)
43
+ # Or: options = {"codegen": True}
44
+ options = None
45
+ if transpose_a:
46
+ matrix_qualifiers_dtype = np.dtype([("is_transpose", "<i4"), ("is_conjugate", "<i4")])
47
+ qualifiers = np.zeros((3,), dtype=matrix_qualifiers_dtype)
48
+ qualifiers[0]["is_transpose"] = True
49
+ else:
50
+ qualifiers = None
51
+ mm = Matmul(a, b, c, beta=1.0, qualifiers=qualifiers, options=options)
52
+ mm.plan()
53
+ _MATMUL_CACHE[key] = (mm, t, c)
54
+ else:
55
+ mm, t, c = mm
56
+ t.zero_()
57
+ mm.reset_operands_unchecked(a=a, b=b, c=c)
58
+ mm.execute()
59
+ mm.release_operands()
60
+
61
+ return t # fast c.to_package()
62
+
63
+
64
+ def _ust_detach(func, types, args, kwargs) -> torch.Tensor:
65
+ assert len(args) == 1
66
+ self = args[0]
67
+ assert isinstance(self, TorchUST)
68
+ return self.__class__(
69
+ shape=self.shape,
70
+ device=self.device,
71
+ dtype=self.dtype,
72
+ layout=self.layout,
73
+ requires_grad=False,
74
+ ust=self.ust,
75
+ transposed=self.transposed,
76
+ )
77
+
78
+
79
+ def _ust_zeros_like(func, types, args, kwargs) -> torch.Tensor:
80
+ assert len(args) == 1
81
+ self = args[0]
82
+ assert isinstance(self, TorchUST)
83
+ return torch.zeros(self.shape, dtype=self.dtype, device=self.device)
84
+
85
+
86
+ def _ust_ones_like(func, types, args, kwargs) -> torch.Tensor:
87
+ assert len(args) == 1
88
+ self = args[0]
89
+ assert isinstance(self, TorchUST)
90
+ return torch.ones(self.shape, dtype=self.dtype, device=self.device)
91
+
92
+
93
+ def _ust_empty_like(func, types, args, kwargs) -> torch.Tensor:
94
+ assert len(args) == 1
95
+ self = args[0]
96
+ assert isinstance(self, TorchUST)
97
+ return torch.empty(self.shape, dtype=self.dtype, device=self.device)
98
+
99
+
100
+ def _ust_to_copy(func, types, args, kwargs) -> torch.Tensor:
101
+ assert len(args) == 1
102
+ self = args[0]
103
+ assert isinstance(self, TorchUST)
104
+ return self
105
+
106
+
107
+ def _ust_t(func, types, args, kwargs) -> torch.Tensor:
108
+ assert len(args) == 1
109
+ self = args[0]
110
+ assert isinstance(self, TorchUST)
111
+ lshape = len(self.shape)
112
+ # TODO: self.requires_grad?
113
+ if lshape == 1:
114
+ return self.__class__(
115
+ shape=self.shape,
116
+ device=self.device,
117
+ dtype=self.dtype,
118
+ layout=self.layout,
119
+ requires_grad=False,
120
+ ust=self.ust,
121
+ transposed=False, # no impact on vector
122
+ )
123
+ elif lshape == 2:
124
+ return self.__class__(
125
+ shape=(self.shape[1], self.shape[0]), # type: ignore
126
+ device=self.device,
127
+ dtype=self.dtype,
128
+ layout=self.layout,
129
+ requires_grad=False,
130
+ ust=self.ust,
131
+ transposed=not self.transposed, # simply flip
132
+ )
133
+ raise NotImplementedError("`TorchUST` transpose: Unexpected operand")
134
+
135
+
136
+ def _ust_permute(func, types, args, kwargs) -> torch.Tensor:
137
+ assert len(args) == 2
138
+ self, perm = args
139
+ assert isinstance(self, TorchUST)
140
+ if len(perm) == 1 or (len(perm) == 2 and perm[0] == 1 and perm[1] == 0):
141
+ return _ust_t(func, types, args[:-1], kwargs)
142
+ raise NotImplementedError("`TorchUST` transpose: Unexpected operand")
143
+
144
+
145
+ def _ust_view(func, types, args, kwargs) -> torch.Tensor:
146
+ assert len(args) == 2
147
+ self, perm = args
148
+ raise NotImplementedError("`TorchUST` view: Unexpected operand")
149
+
150
+
151
+ def _ust_dot_impl(A, B):
152
+ assert A.ndim == 1 and B.ndim == 1
153
+ if isinstance(A, TorchUST):
154
+ if isinstance(B, TorchUST):
155
+ raise NotImplementedError("`TorchUST` dot: Only one operand can be sparse")
156
+ # DOT a x b direct, can ignore A.transposed.
157
+ return _matmul(A, B, ())
158
+ elif isinstance(B, TorchUST):
159
+ # DOT a x b as b x a, can ignore B.transposed.
160
+ return _matmul(B, A, ())
161
+ raise NotImplementedError("`TorchUST` dot: Unexpected operands")
162
+
163
+
164
+ def _ust_mv_impl(A, B):
165
+ assert A.ndim == 2 and B.ndim == 1
166
+ if isinstance(A, TorchUST):
167
+ if isinstance(B, TorchUST):
168
+ raise NotImplementedError("`TorchUST` mv: Only one operand can be sparse")
169
+ # MV A* x b direct.
170
+ return _matmul(A, B, (A.shape[0],), transpose_a=A.transposed)
171
+ elif isinstance(B, TorchUST):
172
+ # MV A x b as b x A^T, can ignore sparse vector B.transposed.
173
+ return _matmul(B, A.t(), (A.shape[0],))
174
+ raise NotImplementedError("`TorchUST` mv: Unexpected operands")
175
+
176
+
177
+ def _ust_mm_impl(A, B):
178
+ if isinstance(A, TorchUST):
179
+ if isinstance(B, TorchUST):
180
+ raise NotImplementedError("`TorchUST` mm: Only one operand can be sparse")
181
+ # MM A* x B direct.
182
+ return _matmul(A, B, (*A.shape[:-1], B.shape[-1]), transpose_a=A.transposed)
183
+ elif isinstance(B, TorchUST):
184
+ assert A.ndim == 2 and B.ndim == 2
185
+ # MM A x B* as (B** x A^T)^T.
186
+ return _matmul(B, A.t(), (B.shape[1], A.shape[0]), transpose_a=not B.transposed).t()
187
+ raise NotImplementedError("`TorchUST` mm: Unexpected operands")
188
+
189
+
190
+ def _ust_dot(func, types, args=(), kwargs=None) -> torch.Tensor:
191
+ assert len(args) == 2
192
+ A, B = args
193
+ C = _ust_dot_impl(A, B)
194
+ # print("ust_dot(", A.shape, ",", B.shape, ") ->", C.shape)
195
+ return C
196
+
197
+
198
+ def _ust_mv(func, types, args=(), kwargs=None) -> torch.Tensor:
199
+ assert len(args) in [2, 3]
200
+ A, B = args[-2:]
201
+ C = _ust_mv_impl(A, B)
202
+ # print("ust_mv(", A.shape, ",", B.shape, ") ->", C.shape)
203
+ return C if len(args) == 2 else C + args[0]
204
+
205
+
206
+ def _ust_mm(func, types, args=(), kwargs=None) -> torch.Tensor:
207
+ assert len(args) in [2, 3]
208
+ A, B = args[-2:]
209
+ # if A.shape[0] == 1:
210
+ # C = _ust_mv_impl(B.t(), A.squeeze(dim=0)).unsqueeze(dim=0)
211
+ # # print("ust_mm(", A.shape, ",", B.shape, ") ->", C.shape, "as vec")
212
+ # else:
213
+ C = _ust_mm_impl(A, B)
214
+ # print("ust_mm(", A.shape, ",", B.shape, ") ->", C.shape)
215
+ return C if len(args) == 2 else C + args[0]
216
+
217
+
218
+ def _ust_linear(func, types, args=(), kwargs=None) -> torch.Tensor:
219
+ assert len(args) in [2, 3]
220
+ A, B = args[:2] # bias at end
221
+ if A.ndim == 1:
222
+ # Recognized matvec (e.g. single token inference).
223
+ C = _ust_mv_impl(B, A)
224
+ # print("ust_linear_1(", A.shape, ",", B.shape, ") ->", C.shape)
225
+ else:
226
+ # Cast into matmul (works for matvec as well).
227
+ shape = A.shape
228
+ A_2d = A.view(-1, shape[-1])
229
+ C = _ust_mm_impl(A_2d, B.t()).view(*shape[:-1], -1)
230
+ # print("ust_linear(", shape, "->", A_2d.shape, ",", B.shape, ") ->", C.shape)
231
+ return C if len(args) == 2 else C + args[2]
232
+
233
+
234
+ def _ust_mul_inplace(func, types, args=(), kwargs=None) -> torch.Tensor:
235
+ assert len(args) == 2
236
+ A, B = args
237
+ # This only works for broadcasting scalar B because otherwise there
238
+ # is no direct match between values array (nse) and shape of B (all).
239
+ assert isinstance(A, TorchUST)
240
+ if not isinstance(B, numbers.Number):
241
+ raise NotImplementedError("`TorchUST` mul: Unexpected operands")
242
+ # print("ust_mul_inplace(", A.shape, ",", B, ")")
243
+ v = A.ust._val.tensor
244
+ v *= B # good performance
245
+ return A
246
+
247
+
248
+ def _ust_addcdiv_inplace(func, types, args=(), kwargs=None) -> torch.Tensor:
249
+ assert len(args) == 3
250
+ A, B, C = args
251
+ assert isinstance(A, TorchUST)
252
+ assert not isinstance(B, TorchUST)
253
+ assert not isinstance(C, TorchUST)
254
+ # print("ust_addcdiv_inplace(", A.shape, ",", B.shape, ",", C.shape, ")", kwargs)
255
+ val = kwargs["value"]
256
+ if val is not None:
257
+ raise NotImplementedError("`TorchUST` no inplace addcdiv")
258
+ return A
259
+
260
+
261
+ def _ust_multi_head_attention(func, types, args=(), kwargs=None) -> torch.Tensor:
262
+ raise NotImplementedError("`TorchUST` no multi-head attention (try running in training mode)")
263
+
264
+
265
+ class TorchUST(torch.Tensor):
266
+ """
267
+ This class wraps the universal sparse tensor as a :class:`torch.Tensor`.
268
+
269
+ The purpose of this class is to inject the UST into PyTorch models with minimal
270
+ code changes. Objects of the ``TorchUST`` class behave like PyTorch tensors, but
271
+ transparently use an UST implementation for the actual operations. A set of
272
+ operations commonly used in models is supported (otherwise a "can't perform"
273
+ message is prompted; please let us know of such cases, so we can extend the
274
+ supported set accordingly).
275
+
276
+ Examples:
277
+ >>> import torch
278
+ >>> from nvmath.sparse.ust.interfaces.torch_interface import TorchUST
279
+
280
+ Create two torch vectors.
281
+
282
+ >>> x = (1.0 + torch.arange(32)).cuda()
283
+ >>> y = (2.0 + torch.arange(32)).cuda()
284
+
285
+ Now perform a dot product operation.
286
+
287
+ >>> z = torch.dot(x, y)
288
+
289
+ Convert the first operand to UST.
290
+
291
+ >>> x = TorchUST.from_torch(x)
292
+
293
+ Now perform the same dot production operation. It transparently
294
+ uses the UST implementation!
295
+
296
+ >>> z = torch.dot(x, y)
297
+ """
298
+
299
+ SPARSE_DISPATCH: dict[Callable, Callable]
300
+
301
+ ust: Tensor
302
+ transposed: bool
303
+ stream: int
304
+
305
+ __slots__ = ["ust", "transposed"]
306
+
307
+ @staticmethod
308
+ def __new__(
309
+ cls,
310
+ shape: torch.Size,
311
+ device: torch.device,
312
+ dtype: torch.dtype,
313
+ layout: torch.layout,
314
+ requires_grad: bool,
315
+ ust: Tensor,
316
+ transposed: bool,
317
+ ):
318
+ # print("new", cls, "(", shape, ",", dtype, layout, ", transp =", transposed, ")")
319
+ cls._load_dispatch_table()
320
+ torch._dynamo.allow_in_graph(cls)
321
+ tensor = torch.Tensor._make_wrapper_subclass(
322
+ cls,
323
+ shape,
324
+ device=device,
325
+ dtype=dtype,
326
+ layout=torch.strided, # cheat
327
+ requires_grad=requires_grad,
328
+ )
329
+ tensor.ust = ust
330
+ tensor.transposed = transposed
331
+ tensor.stream = torch.cuda.current_stream().cuda_stream
332
+ return tensor
333
+
334
+ @classmethod
335
+ def from_torch(cls, original_tensor: torch.Tensor) -> "TorchUST":
336
+ """Constructs a ``TorchUST`` from the given ``torch.Tensor``."""
337
+ ust = Tensor.from_package(original_tensor)
338
+ return cls(
339
+ original_tensor.shape,
340
+ device=original_tensor.device,
341
+ dtype=original_tensor.dtype,
342
+ layout=original_tensor.layout,
343
+ requires_grad=original_tensor.requires_grad,
344
+ ust=ust,
345
+ transposed=False,
346
+ )
347
+
348
+ @classmethod
349
+ def __torch_dispatch__(cls, func, types, args, kwargs) -> Any: # type: ignore[override]
350
+ if func._overloadpacket not in cls.SPARSE_DISPATCH:
351
+ raise NotImplementedError(
352
+ f"{cls.__name__} only supports a specific set of operations, "
353
+ f"can't perform requested op ({func.__name__} aka {func._overloadpacket})"
354
+ )
355
+ return cls.SPARSE_DISPATCH[func._overloadpacket](func, types, args, kwargs)
356
+
357
+ @classmethod
358
+ def _load_dispatch_table(cls, custom_dispatch_table=None) -> None:
359
+ """
360
+ Loads the op overload sparse dispatch table for the current class.
361
+ """
362
+ if getattr(cls, "SPARSE_DISPATCH", None) is None:
363
+ cls.SPARSE_DISPATCH = {
364
+ torch.ops.aten.detach: _ust_detach,
365
+ torch.ops.aten.zeros_like: _ust_zeros_like,
366
+ torch.ops.aten.ones_like: _ust_ones_like,
367
+ torch.ops.aten.empty_like: _ust_empty_like,
368
+ torch.ops.aten._to_copy: _ust_to_copy,
369
+ torch.ops.aten.t: _ust_t, # .t()
370
+ torch.ops.aten.permute: _ust_permute, # .T
371
+ torch.ops.aten.view: _ust_view,
372
+ torch.ops.aten.dot: _ust_dot,
373
+ torch.ops.aten.mv: _ust_mv,
374
+ torch.ops.aten.addmv: _ust_mv,
375
+ torch.ops.aten.mm: _ust_mm,
376
+ torch.ops.aten.addmm: _ust_mm,
377
+ torch.ops.aten.matmul: _ust_mm,
378
+ torch.ops.aten.linear: _ust_linear,
379
+ torch.ops.aten.bmm: _ust_mm,
380
+ torch.ops.aten.baddbmm: _ust_mm,
381
+ torch.ops.aten.mul_: _ust_mul_inplace,
382
+ torch.ops.aten.addcdiv_: _ust_addcdiv_inplace,
383
+ torch.ops.aten._native_multi_head_attention: _ust_multi_head_attention,
384
+ }
385
+ if custom_dispatch_table is not None:
386
+ cls.SPARSE_DISPATCH.update(custom_dispatch_table)
387
+
388
+ def __str__(self):
389
+ return self.ust.__str__()
390
+
391
+
392
+ def prune_model(model, *, local=True, amount=0.5):
393
+ """
394
+ This is a convenience wrapper that uses the framework :mod:`torch.nn.utils.prune`
395
+ to prune all the weights of linear layers in a model either locally (per layer)
396
+ or globally (over all layers) with the given amount.
397
+
398
+ Args:
399
+ model: the model to be pruned
400
+ local: local per layer pruning if True, otherwise global over all layers
401
+ amount: amount of weights to be dropped (e.g. 0.50 drops 50%)
402
+ """
403
+ # Local pruning.
404
+ if local:
405
+ for module in model.modules():
406
+ if isinstance(module, torch.nn.Linear):
407
+ prune.l1_unstructured(module, name="weight", amount=amount)
408
+ return
409
+ # Global pruning.
410
+ parameters_to_prune = tuple([(module, "weight") for module in model.modules() if isinstance(module, torch.nn.Linear)])
411
+ prune.global_unstructured(
412
+ parameters_to_prune,
413
+ pruning_method=prune.L1Unstructured,
414
+ amount=amount,
415
+ )
416
+
417
+
418
+ def reformat_model(model, *, func=None):
419
+ """
420
+ This function potentially converts the linear weights in a model into UST format.
421
+ If ``func`` is None, all weights are unconditionally converted into the UST COO format
422
+ (stress testing the system with exactly the same weights but using sparse operations).
423
+ If a user-defined function ``func=reformat`` is given, this method is applied to every
424
+ weight and replaces the parameter only if the function returns not None.
425
+
426
+ Args:
427
+ model: the model to be reformatted
428
+ func: if set, user-defined reformatting function
429
+
430
+ Examples:
431
+ >>> import torch
432
+ >>> from nvmath.sparse.ust.interfaces.torch_interface import TorchUST
433
+
434
+ Inside the ``reformat`` method, inspect the weight sparsity (note that we
435
+ could even prune here, but it is more common to rely on other pruning
436
+ frameworks like ``torch.nn.utils.prune`` in combination with fine-tuning
437
+ for accuracy).
438
+
439
+ If the condition is met, pick a suitable format for ``weight`` and then
440
+ return ``TorchUST.from_torch(weight)``. Otherwise, just return ``None``.
441
+
442
+ >>> def reformat(weight):
443
+ ... nel = weight.numel()
444
+ ... nnz = torch.count_nonzero(weight)
445
+ ... sparsity = (1.0 - float(nnz) / float(nel)) * 100.0
446
+ ... if sparsity >= sparse_threshold:
447
+ ... # TODO: Pick suitable format for weight
448
+ ... return TorchUST.from_torch(weight)
449
+ ... return None
450
+
451
+ This approach enables experimenting with novel formats to speedup
452
+ sparsified models during inference by simply calling the method
453
+ ``ust.reformat_model(model, func=reformat)``.
454
+ No source code changes inside the model are required! If used during
455
+ training, always make sure to construct the optimizer (by calling e.g.
456
+ ``torch.optim.Adam(model.parameters(), lr=0.001)``)
457
+ after the reformatting method call, so that the new parameters will
458
+ be involved in the optimizer steps.
459
+ """
460
+ for name, module in model.named_modules():
461
+ if isinstance(module, torch.nn.Linear):
462
+ # Make any pruning permanent prior to reformatting
463
+ # (this is required to get a proper weight matrix).
464
+ if prune.is_pruned(module):
465
+ print(f"Making pruning in {name} permanent prior to reformatting")
466
+ prune.remove(module, name="weight")
467
+
468
+ # Apply unconditional reformatting into COO if func is None.
469
+ # Otherwise, apply the user-defined function.
470
+ if func is None:
471
+ U = TorchUST.from_torch(module.weight.data.to_sparse())
472
+ module.weight = torch.nn.Parameter(U)
473
+ else:
474
+ U = func(module.weight.data)
475
+ if U is not None:
476
+ module.weight = torch.nn.Parameter(U)