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,444 @@
1
+ # Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ A collection of functions for parsing Einsum expressions.
7
+ """
8
+
9
+ from collections import Counter
10
+ from functools import lru_cache
11
+ from itertools import chain
12
+
13
+ from ...internal import formatters, tensor_wrapper
14
+ from .data import WHITESPACE_UNICODE
15
+
16
+ DISALLOWED_LABELS = {".", "-", ">"}
17
+ native_to_str = lambda native: "'" + "".join(s if s is not Ellipsis else "..." for s in native) + "'"
18
+
19
+
20
+ def select_morpher(mapper=None):
21
+ """
22
+ Select appropriate function for mode label representation based on string format.
23
+ """
24
+ if mapper is None:
25
+ return native_to_str
26
+
27
+ return lambda s: native_to_str(mapper(s))
28
+
29
+
30
+ class ModeLabelMapper:
31
+ """
32
+ Map mode labels, with special treatment for Ellipsis characters.
33
+ """
34
+
35
+ def __init__(self, _map):
36
+ """
37
+ Args:
38
+ _map = dict-like object to map mode labels.
39
+ """
40
+ self._map = _map
41
+
42
+ def __call__(self, sequence):
43
+ return tuple(s if s is Ellipsis else self._map[s] for s in sequence)
44
+
45
+
46
+ def parse_single(single):
47
+ """
48
+ Parse single operand mode labels considering ellipsis.
49
+ Leading or trailing whitespace, if present, is removed.
50
+ """
51
+ whitespace = WHITESPACE_UNICODE
52
+ subexpr = single.strip(whitespace).split("...")
53
+ n = len(subexpr)
54
+ expr = [[Ellipsis]] * (2 * n - 1)
55
+ expr[::2] = subexpr
56
+
57
+ return tuple(chain(*expr))
58
+
59
+
60
+ def check_single(single):
61
+ """
62
+ Check for disallowed characters used as mode labels for a single operand.
63
+ """
64
+ whitespace = WHITESPACE_UNICODE
65
+ for s in single:
66
+ if s is Ellipsis:
67
+ continue
68
+ if s in whitespace or s in DISALLOWED_LABELS:
69
+ return False
70
+
71
+ return True
72
+
73
+
74
+ @lru_cache(maxsize=128)
75
+ def parse_einsum_str(expr):
76
+ """
77
+ Parse einsum expression in string format, retaining ellipses if present.
78
+
79
+ Return operand as well as output mode labels if explicit form or None for
80
+ implicit form.
81
+ """
82
+ inputs, output, *rest = expr.split("->") if "->" in expr else (expr, None)
83
+ if rest:
84
+ raise ValueError("""Invalid expression.
85
+ It is not permitted to specify more than one '->' in the Einstein summation
86
+ expression.""")
87
+
88
+ inputs = list(parse_single(_input) for _input in inputs.split(",")) # noqa: C400
89
+ if output is not None:
90
+ output = parse_single(output)
91
+
92
+ checks = [check_single(_input) for _input in inputs]
93
+ if not all(checks):
94
+ incorrect = [
95
+ f"{location}: {native_to_str(inputs[location])}" for location, predicate in enumerate(checks) if predicate is False
96
+ ]
97
+ incorrect = formatters.array2string(incorrect)
98
+ message = f"""Incorrect term.
99
+ Whitespace characters and characters from the set {DISALLOWED_LABELS} cannot be
100
+ used as mode labels in a summation expression.
101
+ The incorrectly specified terms as a sequence of "position: term" are:
102
+ \n{incorrect}"""
103
+ raise ValueError(message)
104
+
105
+ return inputs, output
106
+
107
+
108
+ def check_ellipses(user_inputs, morpher):
109
+ """
110
+ Check ellipsis specification for validity.
111
+
112
+ Args:
113
+ user_inputs: Einsum expression in "neutral format"
114
+ (sequence of sequences) before mapping.
115
+ morpher: A callable that transforms a term in neutral format
116
+ (sequence) to string format.
117
+ """
118
+
119
+ checks = [user_input.count(Ellipsis) <= 1 for user_input in user_inputs]
120
+ if not all(checks):
121
+ incorrect = [
122
+ f"{location}: {morpher(user_inputs[location])}" for location, predicate in enumerate(checks) if predicate is False
123
+ ]
124
+ incorrect = formatters.array2string(incorrect)
125
+ message = f"""Incorrect ellipsis use.
126
+ There must not be more than one ellipsis present in each term.
127
+ The incorrectly specified terms as a sequence of "position: term" are:
128
+ \n{incorrect}"""
129
+ raise ValueError(message)
130
+
131
+
132
+ def check_einsum_with_operands(user_inputs, operands, morpher):
133
+ """
134
+ Check that the number of modes in each Einsum term is consistent
135
+ with the shape of the corresponding operand.
136
+
137
+ Args:
138
+ operands: Wrapped operands.
139
+ user_inputs: Einsum expression in "neutral format"
140
+ (sequence of sequences) before mapping.
141
+ morpher: A callable that transforms a term in neutral format
142
+ (sequence) to string format.
143
+ """
144
+
145
+ checks = [
146
+ len(i) - 1 <= len(o.shape) if Ellipsis in i else len(i) == len(o.shape)
147
+ for i, o in zip(user_inputs, operands, strict=False)
148
+ ]
149
+ if not all(checks):
150
+ mismatch = [
151
+ f"{location}: {morpher(user_inputs[location])} <=> {operands[location].shape}"
152
+ for location, predicate in enumerate(checks)
153
+ if predicate is False
154
+ ]
155
+ mismatch = formatters.array2string(mismatch)
156
+ message = f"""Term-operand shape mismatch.
157
+ The number of mode labels in each term of the expression must match the shape
158
+ of the corresponding operand.
159
+ The mismatch as a sequence of "position: mode labels in term <=> operand shape"
160
+ is: \n{mismatch}"""
161
+ raise ValueError(message)
162
+
163
+
164
+ def map_modes(user_inputs, user_output, num_extra_labels, morpher):
165
+ """
166
+ Map modes in user-defined inputs and output to ordinals, leaving ellipsis
167
+ for later processing. Create extra mode labels in anticipation of ellipsis
168
+ replacement. Create the forward as well as inverse maps.
169
+
170
+ Args:
171
+ user_inputs: Einsum expression in "neutral format"
172
+ (sequence of sequences) before mapping.
173
+ user_output: The output mode labels before mapping as a sequence or None.
174
+ num_extra_labels: The number of extra mode labels to generate
175
+ to use in ellipsis expansion later.
176
+ morpher: A callable that transforms a term in neutral format
177
+ (sequence) to string format.
178
+
179
+ Returns:
180
+ tuple: A 5-tuple containing (mapped input, mapped output, forward map,
181
+ reverse map, largest label).
182
+ """
183
+
184
+ ordinal = 0
185
+ mode_map_user_to_ord = {}
186
+ for modes in user_inputs:
187
+ for mode in modes:
188
+ if mode not in mode_map_user_to_ord:
189
+ mode_map_user_to_ord[mode] = ordinal
190
+ ordinal += 1
191
+
192
+ mode_map_user_to_ord.update((f"__{i}__", i) for i in range(ordinal, ordinal + num_extra_labels))
193
+ label_end = ordinal + num_extra_labels
194
+
195
+ mode_map_ord_to_user = {v: k for k, v in mode_map_user_to_ord.items()}
196
+
197
+ inputs = list(tuple(m if m is Ellipsis else mode_map_user_to_ord[m] for m in modes) for modes in user_inputs) # noqa: C400
198
+
199
+ output = None
200
+ if user_output is not None:
201
+ extra = set(user_output) - set(mode_map_user_to_ord.keys()) - {Ellipsis}
202
+ if extra:
203
+ output_modes = morpher(user_output)
204
+ message = f"""Extra modes in output.
205
+ The specified output modes {output_modes} contain the extra modes: {extra}"""
206
+ raise ValueError(message)
207
+ output = tuple(m if m is Ellipsis else mode_map_user_to_ord[m] for m in user_output)
208
+
209
+ return inputs, output, mode_map_user_to_ord, mode_map_ord_to_user, label_end
210
+
211
+
212
+ def create_size_dict(inputs, operands):
213
+ """
214
+ Create size dictionary (mode label to extent map) capturing the extent of
215
+ each mode.
216
+
217
+ Args:
218
+ inputs: Einsum expression in "neutral format" (sequence of sequences)
219
+ after relabelling modes.
220
+ operands: Wrapped operands.
221
+
222
+ Returns:
223
+ size_dict: size dictionary.
224
+ """
225
+
226
+ size_dict = {}
227
+ for i, _input in enumerate(inputs):
228
+ for m, mode in enumerate(_input):
229
+ shape = operands[i].shape
230
+ if mode in size_dict:
231
+ if size_dict[mode] == 1: # Handle broadcasting
232
+ size_dict[mode] = shape[m]
233
+ elif size_dict[mode] != shape[m] and shape[m] != 1:
234
+ message = f"""Extent mismatch.
235
+ The extent ({shape[m]}) of mode {m} for operand {i} does not match the extent
236
+ ({size_dict[mode]}) of the same mode found in previous operand(s)."""
237
+ raise ValueError(message)
238
+ else:
239
+ size_dict[mode] = shape[m]
240
+
241
+ return size_dict
242
+
243
+
244
+ def infer_output_mode_labels(inputs, mode_map_ord_to_user=None):
245
+ """
246
+ Infer output mode labels (those that appear exactly once).
247
+
248
+ Args:
249
+ inputs: Einsum expression in "neutral format" (sequence of sequences).
250
+ If `mode_map_ord_to_user` is provided, the mode labels correspond to
251
+ ordinals, otherwise they correspond to user labels.
252
+ mode_map_ord_to_user: the map from ordinals to user labels.
253
+ """
254
+ mode_label_freq = Counter(chain(*inputs))
255
+ del mode_label_freq[Ellipsis]
256
+
257
+ key = None if mode_map_ord_to_user is None else lambda m: mode_map_ord_to_user[m]
258
+ return tuple(sorted((m for m, c in mode_label_freq.items() if c == 1), key=key))
259
+
260
+
261
+ def process_ellipses(inputs, output, operands, label_end, mode_map_ord_to_user, mapping_morpher):
262
+ """
263
+ Replace ellipses by generated mode labels, using 'label_end' and aligning
264
+ shapes from the right. Infer or update output mode labels.
265
+
266
+ Args:
267
+ inputs: Einsum expression in "neutral format" (sequence of sequences)
268
+ after relabelling modes.
269
+ output: The output mode labels after relabelling as a sequence or None.
270
+ operands: Wrapped operands.
271
+ label_end: One past the largest mode label (int), including modes
272
+ resulting from Ellipsis expansion.
273
+ mode_map_ord_to_user: the map from ordinals to user labels.
274
+ mapping_morpher: A callable that transforms a term in neutral format
275
+ (sequence) to string format, while converting internal labels to
276
+ user labels.
277
+
278
+ Returns:
279
+ tuple: a 2-tuple (inputs, output) after ellipsis expansion and inferring
280
+ output mode labels if needed.
281
+ """
282
+
283
+ inferred = False
284
+ if output is None:
285
+ output = infer_output_mode_labels(inputs, mode_map_ord_to_user)
286
+ inferred = True
287
+
288
+ shortest, longest = label_end, 0
289
+ for i, _input in enumerate(inputs):
290
+ if Ellipsis not in _input:
291
+ continue
292
+
293
+ n = len(operands[i].shape) - (len(_input) - 1)
294
+ assert n >= 0, "Internal error"
295
+
296
+ s = _input.index(Ellipsis)
297
+ shortest, longest = min(shortest, n), max(longest, n)
298
+ inputs[i] = _input[:s] + tuple(range(label_end - n, label_end)) + _input[s + 1 :]
299
+
300
+ if not inferred:
301
+ count = output.count(Ellipsis)
302
+ if count > 1:
303
+ message = f"""Incorrect ellipsis use.
304
+ The output term cannot have more than one ellipsis.
305
+ Specified term = {mapping_morpher(output)}"""
306
+ raise ValueError(message)
307
+ if count == 1: # Replace ellipsis by the longest sequence of labels.
308
+ s = output.index(Ellipsis)
309
+ output = output[:s] + tuple(range(label_end - longest, label_end)) + output[s + 1 :]
310
+ else: # If all ellipses expand to the same number of mode labels, the latter are reduced.
311
+ if shortest != longest:
312
+ message = f"""Ellipsis length mismatch for reduction.
313
+ The ellipses specified in the expression do not expand to the same number of
314
+ mode labels and thus cannot be reduced. The expanded number of dimensions
315
+ ranges from {shortest} to {longest}."""
316
+ raise ValueError(message)
317
+ else: # The mode labels corresponding to ellipsis expansion followed by the inferred mode labels.
318
+ output = tuple(range(label_end - longest, label_end)) + output
319
+
320
+ return inputs, output
321
+
322
+
323
+ def parse_einsum(expr, *operands):
324
+ """
325
+ Parse the generalized Einstein summation expression in string format. Any
326
+ hashable and comparable object is accepted for mode label specification, and
327
+ unicode strings are accepted. If the output is not provided (implicit form
328
+ or missing output sublist), it will be inferred from the expression.
329
+
330
+ Returns wrapped operands, mapped inputs and output, size dictionary based on
331
+ internal mode numbers, and the forward as well as the reverse mode maps.
332
+ """
333
+
334
+ # Parse einsum keeping ellipses.
335
+
336
+ inputs, output = parse_einsum_str(expr)
337
+
338
+ num_operand, num_input = len(operands), len(inputs)
339
+ if num_operand != num_input:
340
+ message = f"""Operand-term mismatch.
341
+ The number of operands ({num_operand}) must match the number of inputs
342
+ ({num_input}) specified in the Einsum expression."""
343
+ raise ValueError(message)
344
+
345
+ morpher = select_morpher()
346
+
347
+ if num_operand < 1:
348
+ message = f"""The number of operands must be either 2 (binary contraction) or 3 (ternary contraction),
349
+ found {num_operand}."""
350
+ raise ValueError(message)
351
+
352
+ # First wrap operands.
353
+ operands = tensor_wrapper.wrap_operands(operands)
354
+
355
+ # Preliminary checks, before mode label remapping.
356
+
357
+ ellipses = any(Ellipsis in _input for _input in inputs)
358
+
359
+ # Ensure at most one ellipsis per operand.
360
+ if ellipses:
361
+ check_ellipses(inputs, morpher)
362
+
363
+ # Ensure that ellipsis is not present only in the output.
364
+ if not ellipses and output is not None and Ellipsis in output:
365
+ message = f"""Invalid ellipsis specification.
366
+ The output term {morpher(output)} contains ellipsis while none of the input
367
+ terms do."""
368
+ raise ValueError(message)
369
+
370
+ # Ensure that the number of modes is consistent with the operand shape.
371
+ check_einsum_with_operands(inputs, operands, morpher)
372
+
373
+ # Calculate the maximum number of extra mode labels that will be needed.
374
+ num_extra_labels = max(len(o.shape) for o in operands) if ellipses else 0
375
+
376
+ # Map data to ordinals for cutensornet.
377
+ inputs, output, mode_map_user_to_ord, mode_map_ord_to_user, label_end = map_modes(inputs, output, num_extra_labels, morpher)
378
+
379
+ has_user_output = output is not None
380
+
381
+ mapper = ModeLabelMapper(mode_map_ord_to_user)
382
+ mapping_morpher = select_morpher(mapper)
383
+
384
+ # Ellipsis expansion.
385
+ if ellipses:
386
+ inputs, output = process_ellipses(inputs, output, operands, label_end, mode_map_ord_to_user, mapping_morpher)
387
+ elif output is None:
388
+ output = infer_output_mode_labels(inputs, mode_map_ord_to_user)
389
+
390
+ # Create mode-extent map based on internal mode numbers.
391
+ size_dict = create_size_dict(inputs, operands)
392
+
393
+ return operands, inputs, output, has_user_output, size_dict, mode_map_user_to_ord, mode_map_ord_to_user, ellipses
394
+
395
+
396
+ def parse_elementary_einsum(inputs, output, a, b, c):
397
+ morpher = select_morpher()
398
+
399
+ # Preliminary checks, before mode label remapping.
400
+ ellipses = any(Ellipsis in _input for _input in inputs)
401
+
402
+ # Ensure at most one ellipsis per operand.
403
+ if ellipses:
404
+ check_ellipses(inputs, morpher)
405
+
406
+ # Ensure that ellipsis is not present only in the output.
407
+ if not ellipses and output is not None and Ellipsis in output:
408
+ message = f"""Invalid ellipsis specification.
409
+ The output term {morpher(output)} contains ellipsis while none of the input
410
+ terms do."""
411
+ raise ValueError(message)
412
+
413
+ # Ensure that the number of modes is consistent with the operand shape.
414
+ num_inputs = len(inputs)
415
+ if num_inputs == 2:
416
+ operands = [a, b]
417
+ elif num_inputs == 3:
418
+ operands = [a, b, c]
419
+ else:
420
+ raise ValueError(f"Invalid number of inputs: {num_inputs}")
421
+
422
+ check_einsum_with_operands(inputs, operands, morpher)
423
+
424
+ # Calculate the maximum number of extra mode labels that will be needed.
425
+ num_extra_labels = max(len(o.shape) for o in operands) if ellipses else 0
426
+
427
+ # Map data to ordinals for cutensornet.
428
+ inputs, output, mode_map_user_to_ord, mode_map_ord_to_user, label_end = map_modes(inputs, output, num_extra_labels, morpher)
429
+
430
+ has_user_output = output is not None
431
+
432
+ mapper = ModeLabelMapper(mode_map_ord_to_user)
433
+ mapping_morpher = select_morpher(mapper)
434
+
435
+ # Ellipsis expansion.
436
+ if ellipses:
437
+ inputs, output = process_ellipses(inputs, output, operands, label_end, mode_map_ord_to_user, mapping_morpher)
438
+ elif output is None:
439
+ output = infer_output_mode_labels(inputs, mode_map_ord_to_user)
440
+
441
+ # Create mode-extent map based on internal mode numbers.
442
+ size_dict = create_size_dict(inputs, operands)
443
+
444
+ return inputs, output, has_user_output, size_dict, mode_map_user_to_ord, mode_map_ord_to_user, ellipses
@@ -0,0 +1,96 @@
1
+ # Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ __all__ = ["get_default_compute_type_from_dtype_name", "get_supported_compute_types", "get_compute_type_name"]
6
+
7
+ import threading
8
+
9
+ from nvmath.bindings.cutensor import ComputeDesc # type: ignore
10
+
11
+ DEFAULT_COMPUTE_TYPE: dict[str, int] = {} # dtype_name -> default compute type
12
+ SUPPORTED_COMPUTE_TYPES: dict[str, set[int]] = {} # dtype_name -> set of compute types supported
13
+ COMPUTE_TYPE_TO_NAME: dict[int, str] = {} # compute type -> compute type name
14
+ _typemap_lock = threading.Lock()
15
+
16
+
17
+ def _maybe_initialize_compute_type_map():
18
+ # https://docs.nvidia.com/cuda/cutensor/latest/api/cutensor.html#cutensorcreatecontraction
19
+ global DEFAULT_COMPUTE_TYPE, SUPPORTED_COMPUTE_TYPES, COMPUTE_TYPE_TO_NAME
20
+ if not DEFAULT_COMPUTE_TYPE: # fast path if the map is already initialized
21
+ with _typemap_lock:
22
+ if not DEFAULT_COMPUTE_TYPE: # double-check to avoid race condition
23
+ DEFAULT_COMPUTE_TYPE = {
24
+ "float16": ComputeDesc.COMPUTE_32F(),
25
+ "bfloat16": ComputeDesc.COMPUTE_32F(),
26
+ "float32": ComputeDesc.COMPUTE_32F(),
27
+ "complex64": ComputeDesc.COMPUTE_32F(),
28
+ "complex128": ComputeDesc.COMPUTE_64F(),
29
+ "float64": ComputeDesc.COMPUTE_64F(),
30
+ }
31
+ SUPPORTED_COMPUTE_TYPES = {
32
+ "float16": {ComputeDesc.COMPUTE_32F()},
33
+ "bfloat16": {ComputeDesc.COMPUTE_32F()},
34
+ "float32": {
35
+ ComputeDesc.COMPUTE_32F(),
36
+ ComputeDesc.COMPUTE_TF32(),
37
+ ComputeDesc.COMPUTE_3XTF32(),
38
+ ComputeDesc.COMPUTE_16F(),
39
+ ComputeDesc.COMPUTE_16BF(),
40
+ ComputeDesc.COMPUTE_4X16F(),
41
+ ComputeDesc.COMPUTE_9X16BF(),
42
+ },
43
+ "complex64": {
44
+ ComputeDesc.COMPUTE_32F(),
45
+ ComputeDesc.COMPUTE_TF32(),
46
+ ComputeDesc.COMPUTE_3XTF32(),
47
+ ComputeDesc.COMPUTE_16F(),
48
+ ComputeDesc.COMPUTE_16BF(),
49
+ ComputeDesc.COMPUTE_4X16F(),
50
+ ComputeDesc.COMPUTE_9X16BF(),
51
+ },
52
+ "complex128": {
53
+ ComputeDesc.COMPUTE_32F(),
54
+ ComputeDesc.COMPUTE_64F(),
55
+ ComputeDesc.COMPUTE_8XINT8(),
56
+ },
57
+ "float64": {
58
+ ComputeDesc.COMPUTE_32F(),
59
+ ComputeDesc.COMPUTE_64F(),
60
+ ComputeDesc.COMPUTE_8XINT8(),
61
+ },
62
+ }
63
+ COMPUTE_TYPE_TO_NAME = {
64
+ ComputeDesc.COMPUTE_32F(): "COMPUTE_32F",
65
+ ComputeDesc.COMPUTE_64F(): "COMPUTE_64F",
66
+ ComputeDesc.COMPUTE_16F(): "COMPUTE_16F",
67
+ ComputeDesc.COMPUTE_4X16F(): "COMPUTE_4X16F",
68
+ ComputeDesc.COMPUTE_16BF(): "COMPUTE_16BF",
69
+ ComputeDesc.COMPUTE_TF32(): "COMPUTE_TF32",
70
+ ComputeDesc.COMPUTE_3XTF32(): "COMPUTE_3XTF32",
71
+ ComputeDesc.COMPUTE_9X16BF(): "COMPUTE_9X16BF",
72
+ ComputeDesc.COMPUTE_8XINT8(): "COMPUTE_8XINT8",
73
+ }
74
+ return
75
+
76
+
77
+ def get_default_compute_type_from_dtype_name(dtype_name: str) -> int:
78
+ _maybe_initialize_compute_type_map()
79
+ if dtype_name not in DEFAULT_COMPUTE_TYPE:
80
+ raise ValueError(f"Invalid data type: {dtype_name}")
81
+ return DEFAULT_COMPUTE_TYPE[dtype_name]
82
+
83
+
84
+ def get_supported_compute_types(dtype_name: str) -> set[int]:
85
+ # https://docs.nvidia.com/cuda/cutensor/latest/api/cutensor.html#cutensorcreatecontraction
86
+ _maybe_initialize_compute_type_map()
87
+ if dtype_name not in SUPPORTED_COMPUTE_TYPES:
88
+ raise ValueError(f"Invalid data type: {dtype_name}")
89
+ return SUPPORTED_COMPUTE_TYPES[dtype_name]
90
+
91
+
92
+ def get_compute_type_name(compute_type: int) -> str:
93
+ _maybe_initialize_compute_type_map()
94
+ if compute_type not in COMPUTE_TYPE_TO_NAME:
95
+ raise ValueError(f"Invalid compute type: {compute_type}")
96
+ return COMPUTE_TYPE_TO_NAME[compute_type]