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,734 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Matrix multiplication function selection and matching for BLAS operations.
7
+
8
+ This module provides functionality to select and configure the appropriate BLAS matrix
9
+ multiplication functions based on matrix qualifiers, batch traits, and execution context.
10
+ It supports both CPU (NVPL) and GPU (cuBLAS) backends and handles various matrix types
11
+ including general, symmetric, hermitian, triangular, and diagonal matrices.
12
+ """
13
+
14
+ import typing
15
+
16
+ import numpy as np
17
+
18
+ import nvmath.bindings.cublas as cublas
19
+ from nvmath._internal.templates import ExecutionCPU, ExecutionCUDA
20
+ from nvmath._internal.utils import LoggerLike
21
+ from nvmath.internal import tensor_wrapper, typemaps, utils
22
+ from nvmath.linalg._internal.batch import BatchTraits
23
+ from nvmath.linalg._internal.layout import BLASMMTraitsView
24
+
25
+ from .qualifiers import (
26
+ DiagonalMatrixQualifier,
27
+ GeneralMatrixQualifier,
28
+ HermitianMatrixQualifier,
29
+ MatrixQualifier,
30
+ SymmetricMatrixQualifier,
31
+ TriangularMatrixQualifier,
32
+ )
33
+ from .wrap import (
34
+ cublas_enum_mapper,
35
+ cublas_mm_function,
36
+ get_address_zeroth_element,
37
+ get_value_zeroth_element,
38
+ nvpl_enum_mapper,
39
+ nvpl_mm_function,
40
+ )
41
+
42
+ """A matmul function returned by this module."""
43
+ WrappedMMFunction: typing.TypeAlias = typing.Callable[
44
+ [
45
+ tensor_wrapper.TensorHolder,
46
+ tensor_wrapper.TensorHolder,
47
+ tensor_wrapper.TensorHolder,
48
+ np.ndarray,
49
+ np.ndarray,
50
+ utils.StreamHolder | None,
51
+ ],
52
+ None,
53
+ ]
54
+
55
+ """A function which returns a BLAS implementation's matching matmul function."""
56
+ MMFunctionGetter: typing.TypeAlias = typing.Callable[
57
+ [
58
+ ExecutionCUDA | ExecutionCPU,
59
+ typemaps.cudaDataType,
60
+ str,
61
+ LoggerLike,
62
+ typing.Literal["", "stride", "group"],
63
+ ],
64
+ typing.Callable,
65
+ ]
66
+
67
+
68
+ def select_blas_mm_function(
69
+ batch_traits: tuple[BatchTraits, BatchTraits, BatchTraits],
70
+ mm_traits: BLASMMTraitsView,
71
+ qualifiers: MatrixQualifier,
72
+ logger: LoggerLike,
73
+ execution: ExecutionCUDA | ExecutionCPU,
74
+ ) -> tuple[WrappedMMFunction, str]:
75
+ """Return a matrix multiplication function which matches the provided arguments."""
76
+
77
+ # At this level, we only select the appropriate library
78
+ match execution:
79
+ case ExecutionCPU():
80
+ mm_function_getter = nvpl_mm_function
81
+ mm_enum_mapper = nvpl_enum_mapper
82
+ # NOTE: the BLAS APIs take values for real alpha/beta, pointers for complex
83
+ if mm_traits.a_layout_traits.dtype.name.startswith("CUDA_C"):
84
+ mm_alpha_beta_picker = get_address_zeroth_element
85
+ else:
86
+ mm_alpha_beta_picker = get_value_zeroth_element
87
+ case ExecutionCUDA():
88
+ mm_function_getter = cublas_mm_function
89
+ mm_enum_mapper = cublas_enum_mapper
90
+ mm_alpha_beta_picker = get_address_zeroth_element
91
+ case _:
92
+ raise ValueError("Only ExectionCUDA and ExecutionCPU are supported.")
93
+
94
+ return _select_blas_mm_function_from_qualifiers(
95
+ batch_traits,
96
+ mm_traits,
97
+ qualifiers,
98
+ logger,
99
+ execution,
100
+ mm_function_getter,
101
+ mm_enum_mapper,
102
+ mm_alpha_beta_picker,
103
+ )
104
+
105
+
106
+ def _select_blas_mm_function_from_qualifiers(
107
+ batch_traits: tuple[BatchTraits, BatchTraits, BatchTraits],
108
+ mm_traits: BLASMMTraitsView,
109
+ qualifiers: MatrixQualifier,
110
+ logger: LoggerLike,
111
+ execution: ExecutionCUDA | ExecutionCPU,
112
+ mm_function_getter: MMFunctionGetter,
113
+ mm_enum_mapper: typing.Callable,
114
+ mm_alpha_beta_picker: typing.Callable,
115
+ ) -> tuple[WrappedMMFunction, str]:
116
+ """Match and wrap a matrix multiplication function based on the provided arguments."""
117
+ # NOTE: The parameters of this function are only the operands that will be resettable by
118
+ # reset_operands(); the rest of the parameters should be unchanged by reset_operands.
119
+ # Therefore we can amortize the cost of those bits.
120
+ batchCount = max(b.count for b in batch_traits)
121
+ if batchCount >= 0 and GeneralMatrixQualifier.is_valid(qualifiers):
122
+ operationA = mm_traits.a_layout_traits.operation
123
+ operationB = mm_traits.b_layout_traits.operation
124
+ m, n, k = mm_traits.M, mm_traits.N, mm_traits.K
125
+ lda, ldb, ldc = mm_traits.a_layout_traits.ld, mm_traits.b_layout_traits.ld, mm_traits.c_layout_traits.ld
126
+ assert mm_traits.c_layout_traits.operation == cublas.Operation.N
127
+ strideA, strideB, strideC = (t.stride for t in batch_traits)
128
+
129
+ if mm_traits.is_swapped_AB:
130
+ strideA, strideB = strideB, strideA
131
+
132
+ operationA = mm_enum_mapper(operationA)
133
+ operationB = mm_enum_mapper(operationB)
134
+
135
+ func = mm_function_getter(
136
+ execution,
137
+ mm_traits.a_layout_traits.dtype,
138
+ GeneralMatrixQualifier.abbreviation,
139
+ logger,
140
+ "stride" if batchCount > 1 else "",
141
+ )
142
+
143
+ def wrapped(
144
+ A: tensor_wrapper.TensorHolder,
145
+ B: tensor_wrapper.TensorHolder,
146
+ C: tensor_wrapper.TensorHolder,
147
+ alpha: np.ndarray,
148
+ beta: np.ndarray,
149
+ stream_holder: utils.StreamHolder | None,
150
+ ) -> None:
151
+ if mm_traits.is_swapped_AB:
152
+ A, B = B, A
153
+ logger.debug(
154
+ "Calling %s(operationA=%s, operationB=%s, m=%d, n=%d, k=%d, alpha=%s, lda=%d, strideA=%d, "
155
+ "ldb=%d, strideB=%d, beta=%s, ldc=%d, strideC=%d, batchCount=%d)",
156
+ func.__name__,
157
+ operationA,
158
+ operationB,
159
+ m,
160
+ n,
161
+ k,
162
+ alpha[0],
163
+ lda,
164
+ strideA,
165
+ ldb,
166
+ strideB,
167
+ beta[0],
168
+ ldc,
169
+ strideC,
170
+ batchCount,
171
+ )
172
+ if batchCount > 1:
173
+ func(
174
+ operationA,
175
+ operationB,
176
+ m,
177
+ n,
178
+ k,
179
+ mm_alpha_beta_picker(alpha),
180
+ A.data_ptr,
181
+ lda,
182
+ strideA,
183
+ B.data_ptr,
184
+ ldb,
185
+ strideB,
186
+ mm_alpha_beta_picker(beta),
187
+ C.data_ptr,
188
+ ldc,
189
+ strideC,
190
+ batchCount,
191
+ stream_holder=stream_holder,
192
+ )
193
+ else:
194
+ func(
195
+ operationA,
196
+ operationB,
197
+ m,
198
+ n,
199
+ k,
200
+ mm_alpha_beta_picker(alpha),
201
+ A.data_ptr,
202
+ lda,
203
+ B.data_ptr,
204
+ ldb,
205
+ mm_alpha_beta_picker(beta),
206
+ C.data_ptr,
207
+ ldc,
208
+ stream_holder=stream_holder,
209
+ )
210
+ elif (
211
+ batchCount >= 0
212
+ and GeneralMatrixQualifier.is_valid(qualifiers[2])
213
+ and (
214
+ (
215
+ (HermitianMatrixQualifier.is_valid(qualifiers[0]) or SymmetricMatrixQualifier.is_valid(qualifiers[0]))
216
+ and GeneralMatrixQualifier.is_valid(qualifiers[1])
217
+ )
218
+ or (
219
+ (HermitianMatrixQualifier.is_valid(qualifiers[1]) or SymmetricMatrixQualifier.is_valid(qualifiers[1]))
220
+ and GeneralMatrixQualifier.is_valid(qualifiers[0])
221
+ )
222
+ )
223
+ ):
224
+ if HermitianMatrixQualifier.is_valid(qualifiers[0]) or SymmetricMatrixQualifier.is_valid(qualifiers[0]):
225
+ qualifierS = qualifiers[0]
226
+ # qualifierG = qualifiers[1]
227
+ # qualifierC = qualifiers[2]
228
+ traitsS = mm_traits.a_layout_traits
229
+ traitsG = mm_traits.b_layout_traits
230
+ traitsC = mm_traits.c_layout_traits
231
+ strideS = batch_traits[0].stride
232
+ strideG = batch_traits[1].stride
233
+ strideC = batch_traits[2].stride
234
+ is_left_side_symmetric = True
235
+ # Parameter A must always be the symmetric matrix, so if the user provided a
236
+ # SymmetricMatrixQualifier as qualifiers[1], we must move the corresponding
237
+ # matrix to the A input in the BLAS API.
238
+ swapABinputs = False
239
+ elif HermitianMatrixQualifier.is_valid(qualifiers[1]) or SymmetricMatrixQualifier.is_valid(qualifiers[1]):
240
+ # qualifierG = qualifiers[0]
241
+ qualifierS = qualifiers[1]
242
+ # qualifierC = qualifiers[2]
243
+ traitsS = mm_traits.b_layout_traits
244
+ traitsG = mm_traits.a_layout_traits
245
+ traitsC = mm_traits.c_layout_traits
246
+ strideS = batch_traits[1].stride
247
+ strideG = batch_traits[0].stride
248
+ strideC = batch_traits[2].stride
249
+ is_left_side_symmetric = False
250
+ swapABinputs = True
251
+ else:
252
+ raise ValueError("Internal Error: At least one must be a HermitianMatrixQualifier | SymmetricMatrixQualifier!")
253
+
254
+ if mm_traits.is_swapped_AB:
255
+ traitsS, traitsG = traitsG, traitsS
256
+ is_left_side_symmetric = not is_left_side_symmetric
257
+
258
+ func = mm_function_getter(
259
+ execution,
260
+ traitsS.dtype,
261
+ qualifierS["abbreviation"],
262
+ logger,
263
+ "stride" if batchCount > 1 else "",
264
+ )
265
+
266
+ if traitsG.operation != cublas.Operation.N or traitsC.operation != cublas.Operation.N:
267
+ raise ValueError(
268
+ f"Operations on the non-hermitian/non-symmetric operands B,C are not supported for {func.__name__}"
269
+ )
270
+
271
+ if traitsS.operation == cublas.Operation.C and SymmetricMatrixQualifier.is_valid(qualifierS):
272
+ raise ValueError(f"Conjugate-Transpose on operand A is not supported for {func.__name__}")
273
+
274
+ if traitsS.operation == cublas.Operation.T and HermitianMatrixQualifier.is_valid(qualifierS):
275
+ raise ValueError(f"Transpose on operand A is not supported for {func.__name__}")
276
+
277
+ side = cublas.SideMode.LEFT if is_left_side_symmetric else cublas.SideMode.RIGHT
278
+ uplo = cublas.FillMode.LOWER if traitsS.is_lower else cublas.FillMode.UPPER
279
+ m, n = mm_traits.M, mm_traits.N
280
+ lda, ldb, ldc = traitsS.ld, traitsG.ld, traitsC.ld
281
+
282
+ side = mm_enum_mapper(side)
283
+ uplo = mm_enum_mapper(uplo)
284
+
285
+ def wrapped(
286
+ A: tensor_wrapper.TensorHolder,
287
+ B: tensor_wrapper.TensorHolder,
288
+ C: tensor_wrapper.TensorHolder,
289
+ alpha: np.ndarray,
290
+ beta: np.ndarray,
291
+ stream_holder: utils.StreamHolder | None,
292
+ ) -> None:
293
+ if swapABinputs:
294
+ A, B = B, A
295
+ logger.debug(
296
+ "Calling %s(side=%s, uplo=%s, m=%d, n=%d, alpha=%s, lda=%d, strideA=%d, "
297
+ "ldb=%d, strideB=%d, beta=%s, ldc=%d, strideC=%d, batchCount=%d)",
298
+ func.__name__,
299
+ side,
300
+ uplo,
301
+ m,
302
+ n,
303
+ alpha[0],
304
+ lda,
305
+ strideS,
306
+ ldb,
307
+ strideG,
308
+ beta[0],
309
+ ldc,
310
+ strideC,
311
+ batchCount,
312
+ )
313
+ if batchCount > 1:
314
+ func(
315
+ side,
316
+ uplo,
317
+ m,
318
+ n,
319
+ mm_alpha_beta_picker(alpha),
320
+ A.data_ptr,
321
+ lda,
322
+ strideS,
323
+ B.data_ptr,
324
+ ldb,
325
+ strideG,
326
+ mm_alpha_beta_picker(beta),
327
+ C.data_ptr,
328
+ ldc,
329
+ strideC,
330
+ batchCount,
331
+ stream_holder=stream_holder,
332
+ )
333
+ else:
334
+ func(
335
+ side,
336
+ uplo,
337
+ m,
338
+ n,
339
+ mm_alpha_beta_picker(alpha),
340
+ A.data_ptr,
341
+ lda,
342
+ B.data_ptr,
343
+ ldb,
344
+ mm_alpha_beta_picker(beta),
345
+ C.data_ptr,
346
+ ldc,
347
+ stream_holder=stream_holder,
348
+ )
349
+ elif (
350
+ batchCount >= 0
351
+ and GeneralMatrixQualifier.is_valid(qualifiers[2])
352
+ and (
353
+ (TriangularMatrixQualifier.is_valid(qualifiers[0]) and GeneralMatrixQualifier.is_valid(qualifiers[1]))
354
+ or (TriangularMatrixQualifier.is_valid(qualifiers[1]) and GeneralMatrixQualifier.is_valid(qualifiers[0]))
355
+ )
356
+ ):
357
+ func = mm_function_getter(
358
+ execution,
359
+ mm_traits.a_layout_traits.dtype,
360
+ TriangularMatrixQualifier.abbreviation,
361
+ logger,
362
+ "stride" if batchCount > 1 else "",
363
+ )
364
+ if TriangularMatrixQualifier.is_valid(qualifiers[0]):
365
+ qualifierT = qualifiers[0]
366
+ # qualifierG = qualifiers[1]
367
+ # qualifierC = qualifiers[2]
368
+ traitsT = mm_traits.a_layout_traits
369
+ traitsG = mm_traits.b_layout_traits
370
+ traitsC = mm_traits.c_layout_traits
371
+ strideT = batch_traits[0].stride
372
+ strideG = batch_traits[1].stride
373
+ strideC = batch_traits[2].stride
374
+ is_left_side_triangle = True
375
+ # Parameter A must always be the triangular matrix, so if the user provided a
376
+ # TriangularMatrixQualifier as qualifiers[1], we must move the corresponding
377
+ # matrix to the A input in the BLAS API.
378
+ swapABinputs = False
379
+ elif TriangularMatrixQualifier.is_valid(qualifiers[1]):
380
+ # qualifierG = qualifiers[0]
381
+ qualifierT = qualifiers[1]
382
+ # qualifierC = qualifiers[2]
383
+ traitsT = mm_traits.b_layout_traits
384
+ traitsG = mm_traits.a_layout_traits
385
+ traitsC = mm_traits.c_layout_traits
386
+ strideT = batch_traits[1].stride
387
+ strideG = batch_traits[0].stride
388
+ strideC = batch_traits[2].stride
389
+ is_left_side_triangle = False
390
+ swapABinputs = True
391
+ else:
392
+ raise ValueError("Internal Error: At least one must be a TriangularMatrixQualifier!")
393
+
394
+ if mm_traits.is_swapped_AB:
395
+ traitsT, traitsG = traitsG, traitsT
396
+ is_left_side_triangle = not is_left_side_triangle
397
+
398
+ if traitsG.operation != cublas.Operation.N or traitsC.operation != cublas.Operation.N:
399
+ raise ValueError(f"Operations on the non-triangular operands B,C are not supported for {func.__name__}")
400
+
401
+ side = cublas.SideMode.LEFT if is_left_side_triangle else cublas.SideMode.RIGHT
402
+ uplo = cublas.FillMode.LOWER if traitsT.is_lower else cublas.FillMode.UPPER
403
+ operation = traitsT.operation
404
+ diag = qualifierT["diag"]
405
+ m, n = mm_traits.M, mm_traits.N
406
+ lda, ldb, ldc = traitsT.ld, traitsG.ld, traitsC.ld
407
+
408
+ if (
409
+ mm_traits.a_layout_traits.dtype == typemaps.cudaDataType.CUDA_C_64F
410
+ and n >= 256
411
+ and m == 1
412
+ and side == cublas.SideMode.RIGHT
413
+ ):
414
+ raise ValueError("This configuration is unsupported for CTK <13.")
415
+
416
+ side = mm_enum_mapper(side)
417
+ uplo = mm_enum_mapper(uplo)
418
+ operation = mm_enum_mapper(operation)
419
+ diag = mm_enum_mapper(diag)
420
+
421
+ def wrapped(
422
+ A: tensor_wrapper.TensorHolder,
423
+ B: tensor_wrapper.TensorHolder,
424
+ C: tensor_wrapper.TensorHolder,
425
+ alpha: np.ndarray,
426
+ beta: np.ndarray,
427
+ stream_holder: utils.StreamHolder | None,
428
+ ) -> None:
429
+ if swapABinputs:
430
+ A, B = B, A
431
+ logger.debug(
432
+ "Calling %s(side=%s, uplo=%s, operation=%s, diag=%s, m=%d, n=%d, alpha=%s, lda=%d, strideA=%d, "
433
+ "ldb=%d, strideB=%d, ldc=%d, strideC=%d, batchCount=%d)",
434
+ func.__name__,
435
+ side,
436
+ uplo,
437
+ operation,
438
+ diag,
439
+ m,
440
+ n,
441
+ alpha[0],
442
+ lda,
443
+ strideT,
444
+ ldb,
445
+ strideG,
446
+ ldc,
447
+ strideC,
448
+ batchCount,
449
+ )
450
+ if batchCount > 1:
451
+ func(
452
+ side,
453
+ uplo,
454
+ operation,
455
+ diag,
456
+ m,
457
+ n,
458
+ mm_alpha_beta_picker(alpha),
459
+ A.data_ptr,
460
+ lda,
461
+ strideT,
462
+ B.data_ptr,
463
+ ldb,
464
+ strideG,
465
+ C.data_ptr,
466
+ ldc,
467
+ strideC,
468
+ batchCount,
469
+ stream_holder=stream_holder,
470
+ )
471
+ else:
472
+ func(
473
+ side,
474
+ uplo,
475
+ operation,
476
+ diag,
477
+ m,
478
+ n,
479
+ mm_alpha_beta_picker(alpha),
480
+ A.data_ptr,
481
+ lda,
482
+ B.data_ptr,
483
+ ldb,
484
+ C.data_ptr,
485
+ ldc,
486
+ stream_holder=stream_holder,
487
+ )
488
+ elif (
489
+ batchCount >= 0
490
+ and GeneralMatrixQualifier.is_valid(qualifiers[2])
491
+ and (
492
+ (DiagonalMatrixQualifier.is_valid(qualifiers[0]) and GeneralMatrixQualifier.is_valid(qualifiers[1]))
493
+ or (DiagonalMatrixQualifier.is_valid(qualifiers[1]) and GeneralMatrixQualifier.is_valid(qualifiers[0]))
494
+ )
495
+ ):
496
+ func = mm_function_getter(
497
+ execution,
498
+ mm_traits.a_layout_traits.dtype,
499
+ DiagonalMatrixQualifier.abbreviation,
500
+ logger,
501
+ "stride" if batchCount > 1 else "",
502
+ )
503
+ if DiagonalMatrixQualifier.is_valid(qualifiers[0]):
504
+ qualifierX = qualifiers[0]
505
+ # qualifierG = qualifiers[1]
506
+ # qualifierC = qualifiers[2]
507
+ traitsX = mm_traits.a_layout_traits
508
+ traitsG = mm_traits.b_layout_traits
509
+ traitsC = mm_traits.c_layout_traits
510
+ strideX = batch_traits[0].stride
511
+ strideG = batch_traits[1].stride
512
+ strideC = batch_traits[2].stride
513
+ is_left_side_diagonal = True
514
+ # Parameter X must always be the diagonal matrix, so if the user provided a
515
+ # DiagonalMatrixQualifier as qualifiers[0], we must move the corresponding
516
+ # matrix to the X input in the BLAS API.
517
+ swapABinputs = True
518
+ elif DiagonalMatrixQualifier.is_valid(qualifiers[1]):
519
+ # qualifierG = qualifiers[0]
520
+ qualifierX = qualifiers[1]
521
+ # qualifierC = qualifiers[2]
522
+ traitsX = mm_traits.b_layout_traits
523
+ traitsG = mm_traits.a_layout_traits
524
+ traitsC = mm_traits.c_layout_traits
525
+ strideX = batch_traits[1].stride
526
+ strideG = batch_traits[0].stride
527
+ strideC = batch_traits[2].stride
528
+ is_left_side_diagonal = False
529
+ swapABinputs = False
530
+ else:
531
+ raise ValueError("Internal Error: At least one must be a DiagonalMatrixQualifier!")
532
+
533
+ if mm_traits.is_swapped_AB:
534
+ traitsX, traitsG = traitsG, traitsX
535
+ is_left_side_diagonal = not is_left_side_diagonal
536
+
537
+ if traitsG.operation != cublas.Operation.N or traitsC.operation != cublas.Operation.N:
538
+ raise ValueError(f"Operations on the non-diagonal operands A,C are not supported for {func.__name__}")
539
+
540
+ # Operation.T is allowed for diagonal matrix because the transpose is a no-op
541
+ if traitsX.operation == cublas.Operation.C:
542
+ raise ValueError(f"Conjugate-Transpose on operand X is not supported for {func.__name__}")
543
+
544
+ side = cublas.SideMode.LEFT if is_left_side_diagonal else cublas.SideMode.RIGHT
545
+ m, n = mm_traits.M, mm_traits.N
546
+ lda, ldc = traitsG.ld, traitsC.ld
547
+ incx = qualifierX["incx"] * max(traitsX.strides)
548
+
549
+ side = mm_enum_mapper(side)
550
+
551
+ def wrapped(
552
+ A: tensor_wrapper.TensorHolder,
553
+ B: tensor_wrapper.TensorHolder,
554
+ C: tensor_wrapper.TensorHolder,
555
+ alpha: np.ndarray,
556
+ beta: np.ndarray,
557
+ stream_holder: utils.StreamHolder | None,
558
+ ) -> None:
559
+ if swapABinputs:
560
+ A, B = B, A
561
+ logger.debug(
562
+ "Calling %s(side=%s, m=%d, n=%d, lda=%d, strideA=%d, incx=%d, strideX=%d, ldc=%d, strideC=%d, batchCount=%d)",
563
+ func.__name__,
564
+ side,
565
+ m,
566
+ n,
567
+ lda,
568
+ strideG,
569
+ incx,
570
+ strideX,
571
+ ldc,
572
+ strideC,
573
+ batchCount,
574
+ )
575
+ if batchCount > 1:
576
+ func(
577
+ side,
578
+ m,
579
+ n,
580
+ A.data_ptr,
581
+ lda,
582
+ strideG,
583
+ B.data_ptr,
584
+ incx,
585
+ strideX,
586
+ C.data_ptr,
587
+ ldc,
588
+ strideC,
589
+ batchCount,
590
+ stream_holder=stream_holder,
591
+ )
592
+ else:
593
+ func(
594
+ side,
595
+ m,
596
+ n,
597
+ A.data_ptr,
598
+ lda,
599
+ B.data_ptr,
600
+ incx,
601
+ C.data_ptr,
602
+ ldc,
603
+ stream_holder=stream_holder,
604
+ )
605
+ else:
606
+ msg = f"No available generic matrix multiplication matches the provided matrices: {qualifiers}."
607
+ raise ValueError(msg)
608
+
609
+ return wrapped, func.__name__
610
+
611
+
612
+ def select_blas_group_mm_function(
613
+ batch_traits: list[BatchTraits],
614
+ mm_traits: list[BLASMMTraitsView],
615
+ qualifiers: list[MatrixQualifier],
616
+ logger: LoggerLike,
617
+ execution: ExecutionCUDA | ExecutionCPU,
618
+ ) -> tuple[WrappedMMFunction, str]:
619
+ """Return a matrix multiplication function which matches the provided arguments."""
620
+
621
+ # At this level, we only select the appropriate library
622
+ match execution:
623
+ case ExecutionCPU():
624
+ mm_function_getter = nvpl_mm_function
625
+ mm_enum_mapper = nvpl_enum_mapper
626
+ mm_alpha_beta_picker = get_address_zeroth_element
627
+ case ExecutionCUDA():
628
+ mm_function_getter = cublas_mm_function
629
+ mm_enum_mapper = cublas_enum_mapper
630
+ mm_alpha_beta_picker = get_address_zeroth_element
631
+ case _:
632
+ raise ValueError("Only ExecutionCUDA and ExecutionCPU are supported.")
633
+
634
+ return _select_blas_group_mm_function_from_qualifiers(
635
+ batch_traits,
636
+ mm_traits,
637
+ qualifiers,
638
+ logger,
639
+ execution,
640
+ mm_function_getter,
641
+ mm_enum_mapper,
642
+ mm_alpha_beta_picker,
643
+ )
644
+
645
+
646
+ def _select_blas_group_mm_function_from_qualifiers(
647
+ batch_traits: list[BatchTraits],
648
+ mm_traits: list[BLASMMTraitsView],
649
+ qualifiers: list[MatrixQualifier],
650
+ logger: LoggerLike,
651
+ execution: ExecutionCUDA | ExecutionCPU,
652
+ mm_function_getter: MMFunctionGetter,
653
+ mm_enum_mapper: typing.Callable,
654
+ mm_alpha_beta_picker: typing.Callable,
655
+ ) -> tuple[WrappedMMFunction, str]:
656
+ """Match and wrap a matrix multiplication function based on the provided arguments."""
657
+ # NOTE: The parameters of this function are only the operands that will be resettable by
658
+ # reset_operands(); the rest of the parameters should be unchanged by reset_operands.
659
+ # Therefore we can amortize the cost of those bits.
660
+ group_count = len(mm_traits)
661
+ if all(GeneralMatrixQualifier.is_valid(q) for q in qualifiers):
662
+ # Allocate separate numpy arrays for each parameter
663
+ transa_array = np.array([mm_enum_mapper(m.a_layout_traits.operation) for m in mm_traits], dtype=np.intc)
664
+ transb_array = np.array([mm_enum_mapper(m.b_layout_traits.operation) for m in mm_traits], dtype=np.intc)
665
+ transc_array = np.array([mm_enum_mapper(m.c_layout_traits.operation) for m in mm_traits], dtype=np.intc)
666
+ assert np.all(transc_array == mm_enum_mapper(cublas.Operation.N))
667
+ # NOTE: Switch between LP64 and ILP64 here
668
+ integer_dtype = np.int32
669
+ # integer_dtype = np.int64
670
+ m_array = np.array([m.M for m in mm_traits], dtype=integer_dtype)
671
+ n_array = np.array([m.N for m in mm_traits], dtype=integer_dtype)
672
+ k_array = np.array([m.K for m in mm_traits], dtype=integer_dtype)
673
+ lda_array = np.array([m.a_layout_traits.ld for m in mm_traits], dtype=integer_dtype)
674
+ ldb_array = np.array([m.b_layout_traits.ld for m in mm_traits], dtype=integer_dtype)
675
+ ldc_array = np.array([m.c_layout_traits.ld for m in mm_traits], dtype=integer_dtype)
676
+ group_size_array = np.array([max(1, b.count) for b in batch_traits], dtype=integer_dtype)
677
+
678
+ func = mm_function_getter(
679
+ execution,
680
+ mm_traits[0].a_layout_traits.dtype,
681
+ GeneralMatrixQualifier.abbreviation,
682
+ logger,
683
+ "group",
684
+ )
685
+
686
+ def wrapped(
687
+ Aarray: tensor_wrapper.TensorHolder,
688
+ Barray: tensor_wrapper.TensorHolder,
689
+ Carray: tensor_wrapper.TensorHolder,
690
+ alpha_array: np.ndarray,
691
+ beta_array: np.ndarray,
692
+ stream_holder: utils.StreamHolder | None,
693
+ ) -> None:
694
+ # A,B pointers are swapped in _execute()
695
+ logger.debug(
696
+ "Calling %s(operationA=%s, operationB=%s, m=%s, n=%s, k=%s, alpha=%s, lda=%s, "
697
+ "ldb=%s, beta=%s, ldc=%s, groupCount=%d, groupSize=%s)",
698
+ func.__name__,
699
+ transa_array,
700
+ transb_array,
701
+ m_array,
702
+ n_array,
703
+ k_array,
704
+ alpha_array,
705
+ lda_array,
706
+ ldb_array,
707
+ beta_array,
708
+ ldc_array,
709
+ group_count,
710
+ group_size_array,
711
+ )
712
+ func(
713
+ transa_array.ctypes.data,
714
+ transb_array.ctypes.data,
715
+ m_array.ctypes.data,
716
+ n_array.ctypes.data,
717
+ k_array.ctypes.data,
718
+ alpha_array.ctypes.data,
719
+ Aarray.data_ptr,
720
+ lda_array.ctypes.data,
721
+ Barray.data_ptr,
722
+ ldb_array.ctypes.data,
723
+ beta_array.ctypes.data,
724
+ Carray.data_ptr,
725
+ ldc_array.ctypes.data,
726
+ group_count,
727
+ group_size_array.ctypes.data,
728
+ stream_holder=stream_holder,
729
+ )
730
+ else:
731
+ msg = f"No available explicitly batched generic matrix multiplication matches the provided matrices: {qualifiers}."
732
+ raise ValueError(msg)
733
+
734
+ return wrapped, func.__name__