nvmath-python 0.9.0__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +45 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/attribute_ifc_factory.py +330 -0
  5. nvmath/_internal/layout.py +70 -0
  6. nvmath/_internal/templates.py +383 -0
  7. nvmath/_utils.py +150 -0
  8. nvmath/bindings/__init__.py +51 -0
  9. nvmath/bindings/_internal/__init__.pxd +0 -0
  10. nvmath/bindings/_internal/__init__.py +0 -0
  11. nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
  12. nvmath/bindings/_internal/cublas.pxd +530 -0
  13. nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
  14. nvmath/bindings/_internal/cublasLt.pxd +59 -0
  15. nvmath/bindings/_internal/cublasMp.pxd +52 -0
  16. nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
  17. nvmath/bindings/_internal/cudss.pxd +47 -0
  18. nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
  19. nvmath/bindings/_internal/cufft.pxd +70 -0
  20. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  21. nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
  22. nvmath/bindings/_internal/curand.pxd +42 -0
  23. nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
  24. nvmath/bindings/_internal/cusolver.pxd +15 -0
  25. nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/cusolverDn.pxd +406 -0
  27. nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/cusparse.pxd +277 -0
  29. nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
  30. nvmath/bindings/_internal/cusparseLt.pxd +48 -0
  31. nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
  32. nvmath/bindings/_internal/cutensor.pxd +58 -0
  33. nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
  34. nvmath/bindings/_internal/mathdx.pxd +116 -0
  35. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  36. nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
  37. nvmath/bindings/_internal/utils.pxd +179 -0
  38. nvmath/bindings/_internal/utils.pyi +10 -0
  39. nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
  40. nvmath/bindings/cublas.pxd +558 -0
  41. nvmath/bindings/cublas.pyi +746 -0
  42. nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
  43. nvmath/bindings/cublasLt.pxd +109 -0
  44. nvmath/bindings/cublasLt.pyi +1337 -0
  45. nvmath/bindings/cublasMp.pxd +85 -0
  46. nvmath/bindings/cublasMp.pyi +219 -0
  47. nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
  48. nvmath/bindings/cudss.pxd +86 -0
  49. nvmath/bindings/cudss.pyi +282 -0
  50. nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
  51. nvmath/bindings/cufft.pxd +118 -0
  52. nvmath/bindings/cufft.pyi +241 -0
  53. nvmath/bindings/cufftMp.pxd +124 -0
  54. nvmath/bindings/cufftMp.pyi +260 -0
  55. nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
  56. nvmath/bindings/curand.pxd +71 -0
  57. nvmath/bindings/curand.pyi +159 -0
  58. nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
  59. nvmath/bindings/cusolver.pxd +62 -0
  60. nvmath/bindings/cusolver.pyi +242 -0
  61. nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
  62. nvmath/bindings/cusolverDn.pxd +430 -0
  63. nvmath/bindings/cusolverDn.pyi +416 -0
  64. nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
  65. nvmath/bindings/cusparse.pxd +338 -0
  66. nvmath/bindings/cusparse.pyi +659 -0
  67. nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
  68. nvmath/bindings/cusparseLt.pxd +99 -0
  69. nvmath/bindings/cusparseLt.pyi +198 -0
  70. nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
  71. nvmath/bindings/cutensor.pxd +98 -0
  72. nvmath/bindings/cutensor.pyi +294 -0
  73. nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
  74. nvmath/bindings/cycublas.pxd +684 -0
  75. nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
  76. nvmath/bindings/cycublasLt.pxd +1055 -0
  77. nvmath/bindings/cycublasMp.pxd +183 -0
  78. nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
  79. nvmath/bindings/cycudss.pxd +224 -0
  80. nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
  81. nvmath/bindings/cycufft.pxd +326 -0
  82. nvmath/bindings/cycufftMp.pxd +334 -0
  83. nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
  84. nvmath/bindings/cycurand.pxd +146 -0
  85. nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
  86. nvmath/bindings/cycusolver.pxd +154 -0
  87. nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
  88. nvmath/bindings/cycusolverDn.pxd +446 -0
  89. nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
  90. nvmath/bindings/cycusparse.pxd +470 -0
  91. nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
  92. nvmath/bindings/cycusparseLt.pxd +150 -0
  93. nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
  94. nvmath/bindings/cycutensor.pxd +192 -0
  95. nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
  96. nvmath/bindings/cymathdx.pxd +552 -0
  97. nvmath/bindings/cynvshmem.pxd +126 -0
  98. nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
  99. nvmath/bindings/mathdx.pxd +182 -0
  100. nvmath/bindings/mathdx.pyi +1244 -0
  101. nvmath/bindings/nvpl/__init__.pxd +0 -0
  102. nvmath/bindings/nvpl/__init__.py +13 -0
  103. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  104. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  105. nvmath/bindings/nvpl/_internal/blas.cp314-win_amd64.pyd +0 -0
  106. nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
  107. nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
  108. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  109. nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
  110. nvmath/bindings/nvpl/blas.pxd +85 -0
  111. nvmath/bindings/nvpl/blas.pyi +122 -0
  112. nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
  113. nvmath/bindings/nvpl/cyblas.pxd +166 -0
  114. nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
  115. nvmath/bindings/nvpl/cyfft.pxd +92 -0
  116. nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
  117. nvmath/bindings/nvpl/fft.pxd +100 -0
  118. nvmath/bindings/nvpl/fft.pyi +100 -0
  119. nvmath/bindings/nvshmem.pxd +54 -0
  120. nvmath/bindings/nvshmem.pyi +179 -0
  121. nvmath/device/__init__.py +21 -0
  122. nvmath/device/_deprecated.py +33 -0
  123. nvmath/device/common.py +313 -0
  124. nvmath/device/common_backend.py +131 -0
  125. nvmath/device/common_cuda.py +201 -0
  126. nvmath/device/common_numba.py +310 -0
  127. nvmath/device/common_opaque_tensor.py +201 -0
  128. nvmath/device/cublasdx.py +1805 -0
  129. nvmath/device/cublasdx_backend.py +807 -0
  130. nvmath/device/cublasdx_numba.py +1612 -0
  131. nvmath/device/cufftdx.py +510 -0
  132. nvmath/device/cufftdx_backend.py +196 -0
  133. nvmath/device/cufftdx_numba.py +196 -0
  134. nvmath/device/curand_kernel.py +9147 -0
  135. nvmath/device/cusolverdx.py +2690 -0
  136. nvmath/device/cusolverdx_backend.py +440 -0
  137. nvmath/device/cusolverdx_numba.py +1624 -0
  138. nvmath/device/llvm_array.py +29 -0
  139. nvmath/device/random.py +445 -0
  140. nvmath/device/random_helpers.py +23 -0
  141. nvmath/device/random_states.py +187 -0
  142. nvmath/device/types.py +147 -0
  143. nvmath/device/vector_types_numba.py +203 -0
  144. nvmath/distributed/__init__.py +205 -0
  145. nvmath/distributed/_internal/__init__.py +0 -0
  146. nvmath/distributed/_internal/nvshmem.py +302 -0
  147. nvmath/distributed/_internal/tensor_ifc.py +67 -0
  148. nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
  149. nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
  150. nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
  151. nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
  152. nvmath/distributed/_internal/tensor_wrapper.py +78 -0
  153. nvmath/distributed/_utils.py +167 -0
  154. nvmath/distributed/distribution.py +770 -0
  155. nvmath/distributed/fft/__init__.py +7 -0
  156. nvmath/distributed/fft/_configuration.py +79 -0
  157. nvmath/distributed/fft/fft.py +2801 -0
  158. nvmath/distributed/linalg/__init__.py +12 -0
  159. nvmath/distributed/linalg/_internal/__init__.py +3 -0
  160. nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -0
  161. nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
  162. nvmath/distributed/linalg/advanced/__init__.py +8 -0
  163. nvmath/distributed/linalg/advanced/_configuration.py +166 -0
  164. nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
  165. nvmath/distributed/process_group.py +408 -0
  166. nvmath/distributed/reshape/__init__.py +6 -0
  167. nvmath/distributed/reshape/_configuration.py +39 -0
  168. nvmath/distributed/reshape/reshape.py +1256 -0
  169. nvmath/fft/__init__.py +7 -0
  170. nvmath/fft/_configuration.py +208 -0
  171. nvmath/fft/_exec_utils.py +109 -0
  172. nvmath/fft/_helpers.py +237 -0
  173. nvmath/fft/fft.py +2903 -0
  174. nvmath/internal/__init__.pxd +3 -0
  175. nvmath/internal/__init__.py +10 -0
  176. nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
  177. nvmath/internal/_bindings.pxd +12 -0
  178. nvmath/internal/_device_utils.py +54 -0
  179. nvmath/internal/enum_utils.py +142 -0
  180. nvmath/internal/formatters.py +87 -0
  181. nvmath/internal/mem_limit.py +51 -0
  182. nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
  183. nvmath/internal/memory.pxd +10 -0
  184. nvmath/internal/memory.pyi +46 -0
  185. nvmath/internal/ndbuffer/__init__.pxd +3 -0
  186. nvmath/internal/ndbuffer/__init__.py +7 -0
  187. nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
  188. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
  189. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
  190. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
  191. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +240 -0
  192. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
  193. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
  194. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
  195. nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
  196. nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
  197. nvmath/internal/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
  198. nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
  199. nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
  200. nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
  201. nvmath/internal/ndbuffer/data_layout.pxd +72 -0
  202. nvmath/internal/ndbuffer/data_layout.pyi +23 -0
  203. nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
  204. nvmath/internal/ndbuffer/jit.pxd +7 -0
  205. nvmath/internal/ndbuffer/jit.pyi +6 -0
  206. nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
  207. nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
  208. nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
  209. nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
  210. nvmath/internal/ndbuffer/package_utils.pxd +11 -0
  211. nvmath/internal/ndbuffer/package_utils.pyi +12 -0
  212. nvmath/internal/package_ifc.py +147 -0
  213. nvmath/internal/package_ifc_cuda.py +49 -0
  214. nvmath/internal/package_ifc_cupy.py +49 -0
  215. nvmath/internal/package_ifc_torch.py +31 -0
  216. nvmath/internal/package_wrapper.py +14 -0
  217. nvmath/internal/tensor_ifc.py +194 -0
  218. nvmath/internal/tensor_ifc_cupy.py +241 -0
  219. nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
  220. nvmath/internal/tensor_ifc_numpy.py +183 -0
  221. nvmath/internal/tensor_ifc_torch.py +176 -0
  222. nvmath/internal/tensor_wrapper.py +157 -0
  223. nvmath/internal/typemaps.py +162 -0
  224. nvmath/internal/utils.py +771 -0
  225. nvmath/linalg/__init__.py +46 -0
  226. nvmath/linalg/_internal/__init__.py +3 -0
  227. nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
  228. nvmath/linalg/_internal/algo_config_ifc.py +43 -0
  229. nvmath/linalg/_internal/batch.py +217 -0
  230. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  231. nvmath/linalg/_internal/epilog_protocol.py +766 -0
  232. nvmath/linalg/_internal/layout.py +624 -0
  233. nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
  234. nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
  235. nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
  236. nvmath/linalg/_internal/typemaps.py +144 -0
  237. nvmath/linalg/_internal/utils.py +134 -0
  238. nvmath/linalg/advanced/__init__.py +8 -0
  239. nvmath/linalg/advanced/_algorithmmod.py +149 -0
  240. nvmath/linalg/advanced/_configuration.py +349 -0
  241. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  242. nvmath/linalg/advanced/helpers/matmul.py +1348 -0
  243. nvmath/linalg/advanced/matmulmod.py +3937 -0
  244. nvmath/linalg/generic/__init__.py +43 -0
  245. nvmath/linalg/generic/_configuration/__init__.py +37 -0
  246. nvmath/linalg/generic/_configuration/layout.py +263 -0
  247. nvmath/linalg/generic/_configuration/match.py +609 -0
  248. nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
  249. nvmath/linalg/generic/_configuration/wrap.py +217 -0
  250. nvmath/linalg/generic/_dtype.py +15 -0
  251. nvmath/linalg/generic/matmulmod.py +1060 -0
  252. nvmath/memory.py +282 -0
  253. nvmath/sparse/__init__.py +38 -0
  254. nvmath/sparse/_internal/__init__.py +21 -0
  255. nvmath/sparse/_internal/common_utils.py +144 -0
  256. nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
  257. nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
  258. nvmath/sparse/_internal/cudss_utils.py +445 -0
  259. nvmath/sparse/_internal/cusparse_utils.py +382 -0
  260. nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
  261. nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
  262. nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
  263. nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
  264. nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
  265. nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
  266. nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
  267. nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
  268. nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
  269. nvmath/sparse/_internal/utils.py +56 -0
  270. nvmath/sparse/advanced/__init__.py +7 -0
  271. nvmath/sparse/advanced/_configuration.py +230 -0
  272. nvmath/sparse/advanced/direct_solver.py +1884 -0
  273. nvmath/sparse/generic/__init__.py +7 -0
  274. nvmath/sparse/generic/_configuration.py +129 -0
  275. nvmath/sparse/generic/_helpers.py +137 -0
  276. nvmath/sparse/generic/_thunks.py +21 -0
  277. nvmath/sparse/generic/matmulmod.py +2426 -0
  278. nvmath/sparse/ust/__init__.py +7 -0
  279. nvmath/sparse/ust/_converters.py +378 -0
  280. nvmath/sparse/ust/_drawer.py +552 -0
  281. nvmath/sparse/ust/_emitter.py +553 -0
  282. nvmath/sparse/ust/_jit.py +212 -0
  283. nvmath/sparse/ust/_kernel.py +346 -0
  284. nvmath/sparse/ust/_semiring.py +71 -0
  285. nvmath/sparse/ust/_utils.py +102 -0
  286. nvmath/sparse/ust/interfaces/__init__.py +0 -0
  287. nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
  288. nvmath/sparse/ust/semiring_ops.py +71 -0
  289. nvmath/sparse/ust/tensor.py +1027 -0
  290. nvmath/sparse/ust/tensor_drawer.py +552 -0
  291. nvmath/sparse/ust/tensor_emitter.py +558 -0
  292. nvmath/sparse/ust/tensor_format.py +935 -0
  293. nvmath/sparse/ust/tensor_jit.py +212 -0
  294. nvmath/sparse/ust/tensor_kernel.py +348 -0
  295. nvmath/sparse/ust/tensor_utils.py +380 -0
  296. nvmath/tensor/__init__.py +6 -0
  297. nvmath/tensor/_configuration.py +95 -0
  298. nvmath/tensor/_internal/__init__.py +3 -0
  299. nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
  300. nvmath/tensor/_internal/cutensor_utils.py +162 -0
  301. nvmath/tensor/_internal/data.py +43 -0
  302. nvmath/tensor/_internal/einsum_parser.py +444 -0
  303. nvmath/tensor/_internal/typemaps.py +96 -0
  304. nvmath/tensor/contract.py +1861 -0
  305. nvmath_python-0.9.0.dist-info/METADATA +127 -0
  306. nvmath_python-0.9.0.dist-info/RECORD +309 -0
  307. nvmath_python-0.9.0.dist-info/WHEEL +5 -0
  308. nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
  309. nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,553 @@
1
+ # Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ This module defines a CUDA emitter for the universal sparse tensor (UST).
7
+ """
8
+
9
+ __all__ = []
10
+
11
+ from enum import IntEnum
12
+ from io import StringIO
13
+
14
+ from ._semiring import prolog_epilog_decl, semiring_ops_decl
15
+ from ._utils import COMPLEX_PRECISION, type_str
16
+ from .tensor_format import Add, Dimension, Divide, LevelExpr, LevelFormat, Modulo, Subtract
17
+
18
+
19
+ class _EmitAction(IntEnum):
20
+ APPLY = 0 # apply value
21
+ DOT = 1 # c = A(i) b(i)
22
+ VM = 2 # c(j) = A(i) B(i,j)
23
+ VM_T = 3 # c(j) = A(i) B(i,j)^T
24
+ MV = 4 # c(i) = A(i,j) b(j)
25
+ BMM = 5 # C(i,k) = A(i,j) B(j,k) or C(b0.., i,k) = A(b0.., i,j) B(j,k)
26
+ BMM_T = 6 # C(i,k) = A(i,j) B(j,k)^T or C(b0.., i,k) = A(b0.., i,j) B(j,k)^T
27
+ BMBM = 7 # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
28
+ BMBM_T = 8 # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)^T (last two dimensions)
29
+
30
+
31
+ def _transposeB(action):
32
+ if action == _EmitAction.DOT:
33
+ return _EmitAction.DOT
34
+ if action == _EmitAction.VM:
35
+ return _EmitAction.VM_T
36
+ if action == _EmitAction.VM_T:
37
+ return _EmitAction.VM
38
+ if action == _EmitAction.BMM:
39
+ return _EmitAction.BMM_T
40
+ if action == _EmitAction.BMM_T:
41
+ return _EmitAction.BMM
42
+ if action == _EmitAction.BMBM:
43
+ return _EmitAction.BMBM_T
44
+ if action == _EmitAction.BMBM_T:
45
+ return _EmitAction.BMBM
46
+ raise ValueError(f"Unexpected transposition of {action}")
47
+
48
+
49
+ def _find_range(litems, expr1, expr2):
50
+ for rl, (k, v) in enumerate(litems):
51
+ if v == LevelFormat.RANGE and k in (expr1, expr2):
52
+ return rl, k
53
+ raise ValueError(f"Cannot find {expr1} or {expr2} in levels")
54
+
55
+
56
+ def _emit_lvl2dim(tensor, indent, stream):
57
+ """Private method to translate levels to dimensions."""
58
+ litems = tensor.tensor_format.levels.items()
59
+ for lvl, (k, fmt) in enumerate(litems):
60
+ if isinstance(fmt, tuple):
61
+ fmt, _ = fmt
62
+ if isinstance(k, Dimension):
63
+ di = tensor.tensor_format.dimensions.index(k)
64
+ print(f"{indent}d{di} = l{lvl};", file=stream)
65
+ elif isinstance(k.operator, Add):
66
+ rl, re = _find_range(litems, k.expression1, k.expression2)
67
+ if re == k.expression2:
68
+ i = tensor.tensor_format.dimensions.index(k.expression1)
69
+ print(f"{indent}d{i} = l{lvl} - l{rl};", file=stream)
70
+ else:
71
+ assert re == k.expression1
72
+ i = tensor.tensor_format.dimensions.index(k.expression2)
73
+ print(f"{indent}d{i} = l{lvl} - l{rl};", file=stream)
74
+ elif isinstance(k.operator, Subtract):
75
+ rl, re = _find_range(litems, k.expression1, k.expression2)
76
+ if re == k.expression2:
77
+ i = tensor.tensor_format.dimensions.index(k.expression1)
78
+ print(f"{indent}d{i} = l{rl} + l{lvl};", file=stream)
79
+ else:
80
+ assert re == k.expression1
81
+ i = tensor.tensor_format.dimensions.index(k.expression2)
82
+ print(f"{indent}d{i} = l{rl} - l{lvl};", file=stream)
83
+ elif isinstance(k.operator, Divide):
84
+ di = tensor.tensor_format.dimensions.index(k.expression1)
85
+ print(f"{indent}d{di} = l{lvl} * {k.expression2};", file=stream)
86
+ elif isinstance(k.operator, Modulo):
87
+ di = tensor.tensor_format.dimensions.index(k.expression1)
88
+ print(f"{indent}d{di} += l{lvl};", file=stream) # seen second
89
+ else:
90
+ raise AssertionError(f"Unsupported: {k}")
91
+
92
+
93
+ def _emit_types(tensor, ctp, stream):
94
+ """Private method to emit type macros."""
95
+ vtp = type_str(tensor.dtype)
96
+ itp = type_str(tensor.index_type)
97
+ atp = vtp
98
+
99
+ if tensor.dtype in ["float8_e4m3fn", "float8_e5m2"]:
100
+ print("#include <cuda_fp8.h>\n", file=stream)
101
+ atp = ctp # TODO: remove, but to make it compile atomic
102
+ elif tensor.dtype == "float16":
103
+ print("#include <cuda_fp16.h>\n", file=stream)
104
+ elif tensor.dtype == "bfloat16":
105
+ print("#include <cuda_bf16.h>\n", file=stream)
106
+ elif tensor.dtype in ["complex64", "complex128"]:
107
+ print("#include <cuda/std/complex>\n", file=stream)
108
+ atp = f"{COMPLEX_PRECISION[tensor.dtype]}"
109
+
110
+ print(f"using VAL = {vtp};", file=stream)
111
+ print(f"using POS = {itp};", file=stream)
112
+ print(f"using CRD = {itp};", file=stream)
113
+ if ctp is not None:
114
+ print(f"using ATP = {atp};", file=stream)
115
+ print(f"using CTP = {ctp};", file=stream)
116
+
117
+
118
+ def _emit_parameters(tensor, A, kind, stream):
119
+ """Private method to emit parameters."""
120
+ for lvl, (_, fmt) in enumerate(tensor.tensor_format.levels.items()):
121
+ if isinstance(fmt, tuple):
122
+ fmt, _ = fmt
123
+ # Handle level format.
124
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH or fmt == LevelFormat.RANGE:
125
+ pass
126
+ elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.DELTA:
127
+ print(f" const POS* __restrict__ {A}pos{lvl},", file=stream)
128
+ print(f" const CRD* __restrict__ {A}crd{lvl},", file=stream)
129
+ elif fmt == LevelFormat.SINGLETON:
130
+ print(f" const CRD* __restrict__ {A}crd{lvl},", file=stream)
131
+ else:
132
+ raise AssertionError(f"Unsupported: {fmt}")
133
+ print(f" VAL* __restrict__ {A}values", file=stream, end="\n" if kind == 0 else ",\n")
134
+
135
+ # Optionally append dimension or level sizes.
136
+ if kind == 1:
137
+ print(" ", ", ".join([f"unsigned long {A}d{i}" for i in range(tensor.num_dimensions)]), end=",\n", file=stream)
138
+ print(" ", ", ".join([f"unsigned long {A}l{i}" for i in range(tensor.num_levels)]), end=",\n", file=stream)
139
+
140
+
141
+ def _emit_header(stream):
142
+ """Private method to emit header with thread/block logic."""
143
+ print(") {", file=stream)
144
+ print(" const unsigned long tidx = threadIdx.x;", file=stream)
145
+ print(" const unsigned long bidx = blockIdx.x;", file=stream)
146
+ print(" const unsigned long tid = bidx * blockDim.x + tidx;", file=stream)
147
+
148
+
149
+ def _emit_decls(tensor, stream):
150
+ if not tensor.tensor_format.is_identity:
151
+ dims = ", ".join(f"d{d}" for d in range(tensor.num_dimensions))
152
+ print(f" CRD {dims};", file=stream)
153
+ lvls = ", ".join(f"l{level}" for level in range(tensor.num_levels))
154
+ print(f" CRD {lvls};", file=stream)
155
+
156
+
157
+ def _emit_load_a(aidx, stream, end=", "):
158
+ print(f"prolog_a(static_cast<CTP>(Avalues[{aidx}]))", end=end, file=stream)
159
+
160
+
161
+ def _emit_load_b(bidx, stream, end=");\n"):
162
+ print(f"prolog_b(static_cast<CTP>(Bvalues[{bidx}]))", end=end, file=stream)
163
+
164
+
165
+ def _emit_load_c(cidx, indent, stream):
166
+ print(f"{indent}CTP acc = prolog_c(static_cast<CTP>(Cvalues[{cidx}]));", file=stream)
167
+
168
+
169
+ def _emit_store_c(cidx, indent, stream):
170
+ print(f"{indent}Cvalues[{cidx}] = static_cast<VAL>(epilog(acc));", file=stream)
171
+
172
+
173
+ def _emit_atomic(dtype, indent, cidx, stream):
174
+ if "complex" in dtype:
175
+ print(f"{indent} VAL* offset = Cvalues + {cidx};", file=stream)
176
+ print(f"{indent} ATP* address = reinterpret_cast<ATP *>(offset);", file=stream)
177
+ print(f"{indent} atomic_add(address + 0, acc.real());", file=stream)
178
+ print(f"{indent} atomic_add(address + 1, acc.imag());", file=stream)
179
+ else:
180
+ # ATP == VAL
181
+ print(f"{indent} atomic_add(Cvalues + {cidx}, static_cast<VAL>(acc));", file=stream)
182
+
183
+
184
+ def _emit_traversal(tensor, action, transpose_A, stream):
185
+ # Open the traversal.
186
+ P = None
187
+ lasta = None
188
+ batch = 0
189
+ no_atomic = False
190
+ for lvl, (k, fmt) in enumerate(tensor.tensor_format.levels.items()):
191
+ if isinstance(fmt, tuple):
192
+ fmt, _ = fmt
193
+ lvlsz = tensor.levels[lvl] if action == _EmitAction.APPLY else f"Al{lvl}"
194
+ indent = " " * (lvl + 1)
195
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH:
196
+ if lvl == 0:
197
+ # Dense outermost driver loop.
198
+ print(f"{indent}const CRD p0 = tid;", file=stream)
199
+ print(f"{indent}if (p0 >= {lvlsz})", file=stream)
200
+ print(f"{indent} return;", file=stream)
201
+ print(f"{indent}l0 = p0;", file=stream)
202
+ if not transpose_A and action == _EmitAction.MV and tensor.tensor_format.is_identity:
203
+ _emit_load_c("l0", indent, stream)
204
+ no_atomic = True
205
+ print(f"{indent}{{", file=stream)
206
+ else:
207
+ # Dense inner traversal loop.
208
+ print(f"{indent}POS p{lvl} = p{P} * {lvlsz};", file=stream)
209
+ print(
210
+ f"{indent}for (CRD i{lvl} = 0; i{lvl} < {lvlsz}; i{lvl}++, p{lvl}++) {{",
211
+ file=stream,
212
+ )
213
+ print(f"{indent} l{lvl} = i{lvl};", file=stream)
214
+ P = lvl
215
+ if fmt == LevelFormat.BATCH:
216
+ batch += 1
217
+ elif fmt == LevelFormat.COMPRESSED:
218
+ if lvl == 0:
219
+ # Compressed outermost driver loop.
220
+ print(f"{indent}const POS p0 = tid;", file=stream)
221
+ print(f"{indent}if (p0 >= Apos0[1])", file=stream)
222
+ print(f"{indent} return;", file=stream)
223
+ print(f"{indent}l0 = Acrd0[p0];", file=stream)
224
+ print(f"{indent}{{", file=stream)
225
+ else:
226
+ # Compressed inner traversal loop.
227
+ if batch > 0:
228
+ # This only happens for prior BATCH. Correct the higher-dimensions in
229
+ # both pos and crd buffers and adjust position by #nnz per batch.
230
+ cidx = f"p{batch - 1} * (Al{batch} + 1) + l{P}"
231
+ hidx = f"p{batch - 1} * (Al{batch} + 1) + Al{batch}"
232
+ print(f"{indent}const POS lo{lvl} = Apos{lvl}[{cidx}];", file=stream)
233
+ print(f"{indent}const POS hi{lvl} = Apos{lvl}[{cidx} + 1];", file=stream)
234
+ print(f"{indent}const POS no{lvl} = Apos{lvl}[{hidx}];", file=stream)
235
+ print(
236
+ f"{indent}for (POS i{lvl} = lo{lvl}, p{lvl} = p{lvl - 2} * no{lvl} "
237
+ f"+ i{lvl}; i{lvl} < hi{lvl}; i{lvl}++, p{lvl}++) {{",
238
+ file=stream,
239
+ )
240
+ print(f"{indent} l{lvl} = Acrd{lvl}[p{lvl}];", file=stream)
241
+ batch = 0 # consumed
242
+ else:
243
+ print(f"{indent}const POS lo{lvl} = Apos{lvl}[p{P}];", file=stream)
244
+ print(f"{indent}const POS hi{lvl} = Apos{lvl}[p{P} + 1];", file=stream)
245
+ print(f"{indent}for (POS p{lvl} = lo{lvl}; p{lvl} < hi{lvl}; p{lvl}++) {{", file=stream)
246
+ print(f"{indent} l{lvl} = Acrd{lvl}[p{lvl}];", file=stream)
247
+ P = lvl
248
+ if isinstance(k, LevelExpr) and isinstance(k.operator, (Add, Subtract)):
249
+ assert lasta is None # no add/sub nesting
250
+ lasta = lvl, k # record last add/sub
251
+ elif fmt == LevelFormat.SINGLETON:
252
+ assert lvl > 0 # no driver loop
253
+ print(f"{indent}l{lvl} = Acrd{lvl}[p{P}];", file=stream)
254
+ print(f"{indent}{{", file=stream)
255
+ elif fmt == LevelFormat.RANGE:
256
+ assert lvl > 0 # no driver loop
257
+ assert lasta is not None
258
+ la, add = lasta
259
+ isI = k == add.expression2
260
+ di = tensor.tensor_format.dimensions.index(k)
261
+ dj = tensor.tensor_format.dimensions.index(add.expression1 if isI else add.expression2)
262
+ szi = tensor.extents[di] if action == _EmitAction.APPLY else f"Ad{di}"
263
+ szj = tensor.extents[dj] if action == _EmitAction.APPLY else f"Ad{dj}"
264
+ if isinstance(add.operator, Add):
265
+ print(f"{indent}const CRD of{lvl} = l{la};", file=stream)
266
+ print(f"{indent}const CRD lo{lvl} = llmax(0, of{lvl} - {szj} + 1);", file=stream)
267
+ print(f"{indent}const CRD hi{lvl} = llmin({szi}, of{lvl} + 1);", file=stream)
268
+ else:
269
+ sign = "-" if isI else ""
270
+ print(f"{indent}const CRD of{lvl} = {sign}l{la};", file=stream)
271
+ print(f"{indent}const CRD lo{lvl} = llmax(0, of{lvl});", file=stream)
272
+ print(f"{indent}const CRD hi{lvl} = llmin({szi}, {szj} + of{lvl});", file=stream)
273
+ print(
274
+ f"{indent}POS p{lvl} = p{P} * {szi} + lo{lvl};",
275
+ file=stream,
276
+ )
277
+ print(
278
+ f"{indent}for (CRD i{lvl} = lo{lvl}; i{lvl} < hi{lvl}; i{lvl}++, p{lvl}++) {{",
279
+ file=stream,
280
+ )
281
+ print(f"{indent} l{lvl} = i{lvl};", file=stream)
282
+ P = lvl
283
+ elif fmt == LevelFormat.DELTA:
284
+ assert lvl > 0 # no driver loop
285
+ # Delta compressed inner traversal loop.
286
+ print(f"{indent}const POS lo{lvl} = Apos{lvl}[p{P}];", file=stream)
287
+ print(f"{indent}const POS hi{lvl} = Apos{lvl}[p{P} + 1];", file=stream)
288
+ print(
289
+ f"{indent}for (POS p{lvl} = lo{lvl}, at{lvl} = 0; p{lvl} < hi{lvl}; p{lvl}++, at{lvl}++) {{",
290
+ file=stream,
291
+ )
292
+ print(f"{indent} at{lvl} += Acrd{lvl}[p{lvl}];", file=stream)
293
+ print(f"{indent} l{lvl} = at{lvl};", file=stream)
294
+ P = lvl
295
+ else:
296
+ raise AssertionError(f"Unsupported: {fmt}")
297
+ lvl += 1
298
+ # Translation prior to traversal.
299
+ indent = " " * (tensor.num_levels + 1)
300
+ if tensor.tensor_format.is_identity:
301
+ dvars = [f"l{level}" for level in range(tensor.num_levels)]
302
+ else:
303
+ _emit_lvl2dim(tensor, indent, stream)
304
+ dvars = [f"d{d}" for d in range(tensor.num_dimensions)]
305
+ # Transposition of A (last two dimensions).
306
+ if transpose_A:
307
+ dvars[-2], dvars[-1] = dvars[-1], dvars[-2]
308
+ # Perform the traversal.
309
+ if action == _EmitAction.APPLY: # apply
310
+ idxs = ", ".join(d for d in dvars)
311
+ print(f"{indent}Avalues[p{P}] = apply(Avalues[p{P}], {idxs});", file=stream)
312
+ elif action == _EmitAction.DOT: # c = A(i) b(i)
313
+ print(f"{indent}{{", file=stream)
314
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
315
+ _emit_load_a(f"p{P}", stream)
316
+ _emit_load_b(f"{dvars[0]}", stream)
317
+ _emit_atomic(tensor.dtype, indent, "0", stream)
318
+ print(f"{indent}}}", file=stream)
319
+ elif action == _EmitAction.VM or action == _EmitAction.VM_T: # c(k) = A(j) B(j,k)
320
+ print(f"{indent}for (CRD k = 0; k < Bd1; k++) {{", file=stream)
321
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
322
+ _emit_load_a(f"p{P}", stream)
323
+ bidx = f"{dvars[0]} * Bd1 + k" if action == _EmitAction.VM else f"{dvars[0]} + Bd0 * k"
324
+ _emit_load_b(f"{bidx}", stream)
325
+ _emit_atomic(tensor.dtype, indent, "k", stream)
326
+ print(f"{indent}}}", file=stream)
327
+ elif action == _EmitAction.MV: # c(i) = A(i,j) b(j)
328
+ print(f"{indent}{{", file=stream)
329
+ if no_atomic:
330
+ print(f"{indent} acc = add(acc, mul(", end="", file=stream)
331
+ _emit_load_a(f"p{P}", stream)
332
+ _emit_load_b(f"{dvars[1]}", stream, end="));\n")
333
+ else:
334
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
335
+ _emit_load_a(f"p{P}", stream)
336
+ _emit_load_b(f"{dvars[1]}", stream)
337
+ _emit_atomic(tensor.dtype, indent, f"{dvars[0]}", stream)
338
+ print(f"{indent}}}", file=stream)
339
+ elif action == _EmitAction.BMM or action == _EmitAction.BMM_T: # C(b0.., i,k) = A(b0.., i,j) B(j,k)
340
+ b = tensor.num_dimensions - 1
341
+ print(f"{indent}for (CRD k = 0; k < Bd1; k++) {{", file=stream)
342
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
343
+ _emit_load_a(f"p{P}", stream)
344
+ bidx = f"{dvars[b]} * Bd1 + k" if action == _EmitAction.BMM else f"{dvars[b]} + Bd0 * k"
345
+ _emit_load_b(f"{bidx}", stream)
346
+ cidx = f"{dvars[0]}"
347
+ for d in range(1, b):
348
+ cidx = f"({cidx} * Ad{d} + {dvars[d]})"
349
+ _emit_atomic(tensor.dtype, indent, f"{cidx} * Bd1 + k", stream)
350
+ print(f"{indent}}}", file=stream)
351
+ elif action == _EmitAction.BMBM or action == _EmitAction.BMBM_T: # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
352
+ b = tensor.num_dimensions - 1
353
+ print(f"{indent}for (CRD k = 0; k < Bd{b}; k++) {{", file=stream)
354
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
355
+ _emit_load_a(f"p{P}", stream)
356
+ bidx = f"{dvars[0]}"
357
+ for d in range(1, b - 1):
358
+ bidx = f"({bidx} * Ad{d} + {dvars[d]})"
359
+ bidx = (
360
+ f"(({bidx} * Bd{b - 1}) + {dvars[b]}) * Bd{b} + k"
361
+ if action == _EmitAction.BMBM
362
+ else f"(({bidx} * Bd{b - 1}) + k) * Bd{b} + {dvars[b]}"
363
+ )
364
+ _emit_load_b(f"{bidx}", stream)
365
+ cidx = f"{dvars[0]}"
366
+ for d in range(1, b):
367
+ cidx = f"({cidx} * Ad{d} + {dvars[d]})"
368
+ _emit_atomic(tensor.dtype, indent, f"{cidx} * Bd{b} + k", stream)
369
+ print(f"{indent}}}", file=stream)
370
+ else:
371
+ raise TypeError(f"Unsupported: {action}")
372
+ # Close the traversal.
373
+ for level in range(tensor.num_levels, 0, -1):
374
+ indent = " " * level
375
+ print(f"{indent}}}", file=stream)
376
+ if no_atomic:
377
+ _emit_store_c("l0", indent, stream)
378
+
379
+
380
+ def emit_apply(tensor, with_indices):
381
+ """
382
+ Emits CUDA code for an apply() operation. Note that since the kernel
383
+ is very specific to one UST instance, the kernel can freely specialize
384
+ on metadata like dimension or level sizes.
385
+ """
386
+ stream = StringIO()
387
+ _emit_types(tensor, None, stream)
388
+ dim = tensor.num_dimensions if with_indices else 0
389
+ print(f'\nextern "C" __device__ VAL apply(VAL{", CRD" * dim});\n', file=stream)
390
+ print('extern "C" __global__ void apply_kernel(', file=stream)
391
+ if with_indices:
392
+ _emit_parameters(tensor, "A", 0, stream)
393
+ _emit_header(stream)
394
+ _emit_decls(tensor, stream)
395
+ _emit_traversal(tensor, _EmitAction.APPLY, False, stream)
396
+ else:
397
+ # Fast path for values only.
398
+ print(" VAL* __restrict__ Avalues,", file=stream)
399
+ print(" POS Anse", file=stream)
400
+ _emit_header(stream)
401
+ print(" if (tid >= Anse)", file=stream)
402
+ print(" return;", file=stream)
403
+ print(" Avalues[tid] = apply(Avalues[tid]);", file=stream)
404
+ print("}", file=stream)
405
+ return stream.getvalue()
406
+
407
+
408
+ # TODO: proof-of-concept sparse emitter that should be generalized; currently
409
+ # it only accepts very simple forms where only operand A is sparse;
410
+ # also, currently it drops the prolog_c/epilog when atomic updates are needed
411
+ def _actions(tensor_A, tensor_B, tensor_C):
412
+ """Returns (akind, bkind, action) encoding for supported matmul combinations."""
413
+
414
+ if tensor_B.tensor_format.name not in [
415
+ "DenseVector",
416
+ "DensedRight",
417
+ "DensedLeft",
418
+ "Dense3D-0-1-2",
419
+ "Dense4D-0-1-2-3",
420
+ ] or tensor_C.tensor_format.name not in ["Scalar", "DenseVector", "DensedRight", "Dense3D-0-1-2", "Dense4D-0-1-2-3"]:
421
+ raise NotImplementedError(
422
+ f"The code generator doesn't currently support the \
423
+ {tensor_B.tensor_format.name} or {tensor_C.tensor_format.name} formats."
424
+ )
425
+
426
+ if tensor_A.num_dimensions == 1:
427
+ # A is a vector.
428
+ if tensor_B.num_dimensions == 1 and tensor_C.num_dimensions == 0:
429
+ return 1, 1, _EmitAction.DOT # c = A(i) b(i)
430
+ if tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == 1:
431
+ if tensor_B.tensor_format.name != "DensedLeft":
432
+ return 1, 1, _EmitAction.VM # c(j) = A(i) B(i,j)
433
+ else:
434
+ return 1, 1, _EmitAction.VM_T # c(j) = A(i) B(i,j)^T
435
+ elif tensor_A.num_dimensions == 2:
436
+ # A is a matrix.
437
+ if tensor_B.num_dimensions == 1 and tensor_C.num_dimensions == 1:
438
+ return 1, -1, _EmitAction.MV # c(i) = A(i,j) b(j)
439
+ elif tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == 2:
440
+ if tensor_B.tensor_format.name != "DensedLeft":
441
+ return 1, 1, _EmitAction.BMM # C(i,k) = A(i,j) B(j,k)
442
+ else:
443
+ return 1, 1, _EmitAction.BMM_T # C(i,k) = A(i,j) B(j,k)^T
444
+ elif tensor_A.num_dimensions > 2:
445
+ # A is a tensor.
446
+ if tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == tensor_A.num_dimensions:
447
+ if tensor_B.tensor_format.name != "DensedLeft":
448
+ return 1, 1, _EmitAction.BMM # C(b0.., i,k) = A(b0.., i,j) B(j,k)
449
+ else:
450
+ return 1, 1, _EmitAction.BMM_T # C(b0.., i,k) = A(b0.., i,j) B(j,k)^T
451
+ elif tensor_B.num_dimensions == tensor_A.num_dimensions and tensor_C.num_dimensions == tensor_A.num_dimensions:
452
+ return 1, 1, _EmitAction.BMBM # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
453
+ raise TypeError("Unsupported matmul() in sparse emitter")
454
+
455
+
456
+ def emit_matmul(tensor_A, tensor_B, tensor_C, ctp, transpose_A=False, transpose_B=False):
457
+ """
458
+ Emits CUDA code for a matmul(A, B, C) operation. Note that since the kernel
459
+ is cached at a generic UST and type level only, the kernel should not specialize
460
+ on metadata like dimension or level sizes, but use parameter values instead.
461
+ """
462
+ akind, bkind, action = _actions(tensor_A, tensor_B, tensor_C)
463
+ stream = StringIO()
464
+ _emit_types(tensor_A, ctp, stream)
465
+ print(f"{semiring_ops_decl}{prolog_epilog_decl}", file=stream)
466
+ print('extern "C" __global__ void matmul(', file=stream)
467
+ _emit_parameters(tensor_A, "A", akind, stream)
468
+ _emit_parameters(tensor_B, "B", bkind, stream)
469
+ _emit_parameters(tensor_C, "C", 0, stream)
470
+ _emit_header(stream)
471
+ _emit_decls(tensor_A, stream)
472
+ if transpose_B:
473
+ action = _transposeB(action)
474
+ _emit_traversal(tensor_A, action, transpose_A, stream)
475
+ print("}", file=stream)
476
+ return stream.getvalue()
477
+
478
+
479
+ def _populate_sizes(params, tensor):
480
+ for i in range(tensor.num_dimensions):
481
+ params.append(tensor.extents[i])
482
+ for i in range(tensor.num_levels):
483
+ params.append(tensor.levels[i])
484
+ return params
485
+
486
+
487
+ # TODO: improve the parallelization scheme dramatically
488
+ def _populate_parameter(params, tensor, kind):
489
+ """Private method to populate parameters for a single UST tensor."""
490
+ size = None
491
+ for lvl, (_, fmt) in enumerate(tensor.tensor_format.levels.items()):
492
+ if isinstance(fmt, tuple):
493
+ fmt, _ = fmt
494
+ # Handle level format.
495
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH or fmt == LevelFormat.RANGE:
496
+ if lvl == 0:
497
+ size = tensor.levels[0]
498
+ else:
499
+ size = tensor.extents[0] if size < tensor.extents[0] else size
500
+ elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.DELTA:
501
+ params.append(tensor.pos(lvl).data_ptr)
502
+ params.append(tensor.crd(lvl).data_ptr)
503
+ if lvl == 0:
504
+ size = tensor.crd(0).size
505
+ elif fmt == LevelFormat.SINGLETON:
506
+ params.append(tensor.crd(lvl).data_ptr)
507
+ else:
508
+ raise TypeError(f"Unsupported: {fmt}")
509
+ params.append(tensor.val.data_ptr)
510
+
511
+ # Optionally append dimension and level sizes.
512
+ if kind == 1:
513
+ params = _populate_sizes(params, tensor)
514
+
515
+ return (params, size)
516
+
517
+
518
+ def populate_apply_parameters(tensor, with_indices=True):
519
+ """
520
+ Populates the parameters for an apply() operation (with our without indices).
521
+ The API follows the UST parameter passing conventions for the tensor when
522
+ indices are needed. Otherwise it directly passes the values buffer.
523
+
524
+ Returns (parameter list, kernel launch size)
525
+ """
526
+ if with_indices:
527
+ return _populate_parameter([], tensor, 0)
528
+ return ([tensor.val.data_ptr, tensor.nse], tensor.nse)
529
+
530
+
531
+ def populate_matmul_parameters(tensor_A, tensor_B, tensor_C, dense_bc=False):
532
+ """
533
+ Populates the parameters for a matmul(A, B, C) operation.
534
+
535
+ The API follows the UST parameter passing conventions for A, B, C,
536
+ each possibly followed by the dimension and level sizes.
537
+
538
+ Returns (parameter list, kernel launch size)
539
+ """
540
+ akind, bkind, _ = _actions(tensor_A, tensor_B, tensor_C)
541
+ params = []
542
+ params, n = _populate_parameter(params, tensor_A, akind)
543
+ if dense_bc:
544
+ # Fast path for dense B and C.
545
+ params.append(tensor_B._val.data_ptr)
546
+ if bkind == 1:
547
+ params = _populate_sizes(params, tensor_B)
548
+ params.append(tensor_C._val.data_ptr)
549
+ else:
550
+ params, _ = _populate_parameter(params, tensor_B, bkind)
551
+ params, _ = _populate_parameter(params, tensor_C, 0)
552
+ assert n is not None
553
+ return (params, n)