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,558 @@
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
+ "emit_apply",
11
+ "emit_matmul",
12
+ "populate_apply_parameters",
13
+ "populate_matmul_parameters",
14
+ ]
15
+
16
+ from enum import IntEnum
17
+ from io import StringIO
18
+
19
+ from ._utils import COMPLEX_PRECISION, type_str
20
+ from .semiring_ops import prolog_epilog_decl, semiring_ops_decl
21
+ from .tensor_format import Add, Dimension, Divide, LevelExpr, LevelFormat, Modulo, Subtract
22
+
23
+
24
+ class _EmitAction(IntEnum):
25
+ APPLY = 0 # apply value
26
+ DOT = 1 # c = A(i) b(i)
27
+ VM = 2 # c(j) = A(i) B(i,j)
28
+ VM_T = 3 # c(j) = A(i) B(i,j)^T
29
+ MV = 4 # c(i) = A(i,j) b(j)
30
+ BMM = 5 # C(i,k) = A(i,j) B(j,k) or C(b0.., i,k) = A(b0.., i,j) B(j,k)
31
+ 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
32
+ BMBM = 7 # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
33
+ BMBM_T = 8 # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)^T (last two dimensions)
34
+
35
+
36
+ def _transposeB(action):
37
+ if action == _EmitAction.DOT:
38
+ return _EmitAction.DOT
39
+ if action == _EmitAction.VM:
40
+ return _EmitAction.VM_T
41
+ if action == _EmitAction.VM_T:
42
+ return _EmitAction.VM
43
+ if action == _EmitAction.BMM:
44
+ return _EmitAction.BMM_T
45
+ if action == _EmitAction.BMM_T:
46
+ return _EmitAction.BMM
47
+ if action == _EmitAction.BMBM:
48
+ return _EmitAction.BMBM_T
49
+ if action == _EmitAction.BMBM_T:
50
+ return _EmitAction.BMBM
51
+ raise ValueError(f"Unexpected transposition of {action}")
52
+
53
+
54
+ def _find_range(litems, expr1, expr2):
55
+ for rl, (k, v) in enumerate(litems):
56
+ if v == LevelFormat.RANGE and k in (expr1, expr2):
57
+ return rl, k
58
+ raise ValueError(f"Cannot find {expr1} or {expr2} in levels")
59
+
60
+
61
+ def _emit_lvl2dim(tensor, indent, stream):
62
+ """Private method to translate levels to dimensions."""
63
+ litems = tensor.tensor_format.levels.items()
64
+ for lvl, (k, fmt) in enumerate(litems):
65
+ if isinstance(fmt, tuple):
66
+ fmt, _ = fmt
67
+ if isinstance(k, Dimension):
68
+ di = tensor.tensor_format.dimensions.index(k)
69
+ print(f"{indent}d{di} = l{lvl};", file=stream)
70
+ elif isinstance(k.operator, Add):
71
+ rl, re = _find_range(litems, k.expression1, k.expression2)
72
+ if re == k.expression2:
73
+ i = tensor.tensor_format.dimensions.index(k.expression1)
74
+ print(f"{indent}d{i} = l{lvl} - l{rl};", file=stream)
75
+ else:
76
+ assert re == k.expression1
77
+ i = tensor.tensor_format.dimensions.index(k.expression2)
78
+ print(f"{indent}d{i} = l{lvl} - l{rl};", file=stream)
79
+ elif isinstance(k.operator, Subtract):
80
+ rl, re = _find_range(litems, k.expression1, k.expression2)
81
+ if re == k.expression2:
82
+ i = tensor.tensor_format.dimensions.index(k.expression1)
83
+ print(f"{indent}d{i} = l{rl} + l{lvl};", file=stream)
84
+ else:
85
+ assert re == k.expression1
86
+ i = tensor.tensor_format.dimensions.index(k.expression2)
87
+ print(f"{indent}d{i} = l{rl} - l{lvl};", file=stream)
88
+ elif isinstance(k.operator, Divide):
89
+ di = tensor.tensor_format.dimensions.index(k.expression1)
90
+ print(f"{indent}d{di} = l{lvl} * {k.expression2};", file=stream)
91
+ elif isinstance(k.operator, Modulo):
92
+ di = tensor.tensor_format.dimensions.index(k.expression1)
93
+ print(f"{indent}d{di} += l{lvl};", file=stream) # seen second
94
+ else:
95
+ raise TypeError(f"Unsupported: {k}")
96
+
97
+
98
+ def _emit_types(tensor, ctp, stream):
99
+ """Private method to emit type macros."""
100
+ vtp = type_str(tensor.dtype)
101
+ itp = type_str(tensor.index_type)
102
+ atp = vtp
103
+
104
+ if tensor.dtype in ["float8_e4m3fn", "float8_e5m2"]:
105
+ print("#include <cuda_fp8.h>\n", file=stream)
106
+ atp = ctp # TODO: remove, but to make it compile atomic
107
+ elif tensor.dtype == "float16":
108
+ print("#include <cuda_fp16.h>\n", file=stream)
109
+ elif tensor.dtype == "bfloat16":
110
+ print("#include <cuda_bf16.h>\n", file=stream)
111
+ elif tensor.dtype in ["complex64", "complex128"]:
112
+ print("#include <cuda/std/complex>\n", file=stream)
113
+ atp = f"{COMPLEX_PRECISION[tensor.dtype]}"
114
+
115
+ print(f"using VAL = {vtp};", file=stream)
116
+ print(f"using POS = {itp};", file=stream)
117
+ print(f"using CRD = {itp};", file=stream)
118
+ if ctp is not None:
119
+ print(f"using ATP = {atp};", file=stream)
120
+ print(f"using CTP = {ctp};", file=stream)
121
+
122
+
123
+ def _emit_parameters(tensor, A, kind, stream):
124
+ """Private method to emit parameters."""
125
+ for lvl, (_, fmt) in enumerate(tensor.tensor_format.levels.items()):
126
+ if isinstance(fmt, tuple):
127
+ fmt, _ = fmt
128
+ # Handle level format.
129
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH or fmt == LevelFormat.RANGE:
130
+ pass
131
+ elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.DELTA:
132
+ print(f" const POS* __restrict__ {A}pos{lvl},", file=stream)
133
+ print(f" const CRD* __restrict__ {A}crd{lvl},", file=stream)
134
+ elif fmt == LevelFormat.SINGLETON:
135
+ print(f" const CRD* __restrict__ {A}crd{lvl},", file=stream)
136
+ else:
137
+ raise TypeError(f"Unsupported: {fmt}")
138
+ print(f" VAL* __restrict__ {A}values", file=stream, end="\n" if kind == 0 else ",\n")
139
+
140
+ # Optionally append dimension or level sizes.
141
+ if kind == 1:
142
+ print(" ", ", ".join([f"unsigned long {A}d{i}" for i in range(tensor.num_dimensions)]), end=",\n", file=stream)
143
+ print(" ", ", ".join([f"unsigned long {A}l{i}" for i in range(tensor.num_levels)]), end=",\n", file=stream)
144
+
145
+
146
+ def _emit_header(stream):
147
+ """Private method to emit header with thread/block logic."""
148
+ print(") {", file=stream)
149
+ print(" const unsigned long tidx = threadIdx.x;", file=stream)
150
+ print(" const unsigned long bidx = blockIdx.x;", file=stream)
151
+ print(" const unsigned long tid = bidx * blockDim.x + tidx;", file=stream)
152
+
153
+
154
+ def _emit_decls(tensor, stream):
155
+ if not tensor.tensor_format.is_identity:
156
+ dims = ", ".join(f"d{d}" for d in range(tensor.num_dimensions))
157
+ print(f" CRD {dims};", file=stream)
158
+ lvls = ", ".join(f"l{level}" for level in range(tensor.num_levels))
159
+ print(f" CRD {lvls};", file=stream)
160
+
161
+
162
+ def _emit_load_a(aidx, stream, end=", "):
163
+ print(f"prolog_a(static_cast<CTP>(Avalues[{aidx}]))", end=end, file=stream)
164
+
165
+
166
+ def _emit_load_b(bidx, stream, end=");\n"):
167
+ print(f"prolog_b(static_cast<CTP>(Bvalues[{bidx}]))", end=end, file=stream)
168
+
169
+
170
+ def _emit_load_c(cidx, indent, stream):
171
+ print(f"{indent}CTP acc = prolog_c(static_cast<CTP>(Cvalues[{cidx}]));", file=stream)
172
+
173
+
174
+ def _emit_store_c(cidx, indent, stream):
175
+ print(f"{indent}Cvalues[{cidx}] = static_cast<VAL>(epilog(acc));", file=stream)
176
+
177
+
178
+ def _emit_atomic(dtype, indent, cidx, stream):
179
+ if "complex" in dtype:
180
+ print(f"{indent} VAL* offset = Cvalues + {cidx};", file=stream)
181
+ print(f"{indent} ATP* address = reinterpret_cast<ATP *>(offset);", file=stream)
182
+ print(f"{indent} atomic_add(address + 0, acc.real());", file=stream)
183
+ print(f"{indent} atomic_add(address + 1, acc.imag());", file=stream)
184
+ else:
185
+ # ATP == VAL
186
+ print(f"{indent} atomic_add(Cvalues + {cidx}, static_cast<VAL>(acc));", file=stream)
187
+
188
+
189
+ def _emit_traversal(tensor, action, transpose_A, stream):
190
+ # Open the traversal.
191
+ P = None
192
+ lasta = None
193
+ batch = 0
194
+ no_atomic = False
195
+ for lvl, (k, fmt) in enumerate(tensor.tensor_format.levels.items()):
196
+ if isinstance(fmt, tuple):
197
+ fmt, _ = fmt
198
+ lvlsz = tensor.levels[lvl] if action == _EmitAction.APPLY else f"Al{lvl}"
199
+ indent = " " * (lvl + 1)
200
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH:
201
+ if lvl == 0:
202
+ # Dense outermost driver loop.
203
+ print(f"{indent}const CRD p0 = tid;", file=stream)
204
+ print(f"{indent}if (p0 >= {lvlsz})", file=stream)
205
+ print(f"{indent} return;", file=stream)
206
+ print(f"{indent}l0 = p0;", file=stream)
207
+ if not transpose_A and action == _EmitAction.MV and tensor.tensor_format.is_identity:
208
+ _emit_load_c("l0", indent, stream)
209
+ no_atomic = True
210
+ print(f"{indent}{{", file=stream)
211
+ else:
212
+ # Dense inner traversal loop.
213
+ print(f"{indent}POS p{lvl} = p{P} * {lvlsz};", file=stream)
214
+ print(
215
+ f"{indent}for (CRD i{lvl} = 0; i{lvl} < {lvlsz}; i{lvl}++, p{lvl}++) {{",
216
+ file=stream,
217
+ )
218
+ print(f"{indent} l{lvl} = i{lvl};", file=stream)
219
+ P = lvl
220
+ if fmt == LevelFormat.BATCH:
221
+ batch += 1
222
+ elif fmt == LevelFormat.COMPRESSED:
223
+ if lvl == 0:
224
+ # Compressed outermost driver loop.
225
+ print(f"{indent}const POS p0 = tid;", file=stream)
226
+ print(f"{indent}if (p0 >= Apos0[1])", file=stream)
227
+ print(f"{indent} return;", file=stream)
228
+ print(f"{indent}l0 = Acrd0[p0];", file=stream)
229
+ print(f"{indent}{{", file=stream)
230
+ else:
231
+ # Compressed inner traversal loop.
232
+ if batch > 0:
233
+ # This only happens for prior BATCH. Correct the higher-dimensions in
234
+ # both pos and crd buffers and adjust position by #nnz per batch.
235
+ cidx = f"p{batch - 1} * (Al{batch} + 1) + l{P}"
236
+ hidx = f"p{batch - 1} * (Al{batch} + 1) + Al{batch}"
237
+ print(f"{indent}const POS lo{lvl} = Apos{lvl}[{cidx}];", file=stream)
238
+ print(f"{indent}const POS hi{lvl} = Apos{lvl}[{cidx} + 1];", file=stream)
239
+ print(f"{indent}const POS no{lvl} = Apos{lvl}[{hidx}];", file=stream)
240
+ print(
241
+ f"{indent}for (POS i{lvl} = lo{lvl}, p{lvl} = p{lvl - 2} * no{lvl} "
242
+ f"+ i{lvl}; i{lvl} < hi{lvl}; i{lvl}++, p{lvl}++) {{",
243
+ file=stream,
244
+ )
245
+ print(f"{indent} l{lvl} = Acrd{lvl}[p{lvl}];", file=stream)
246
+ batch = 0 # consumed
247
+ else:
248
+ print(f"{indent}const POS lo{lvl} = Apos{lvl}[p{P}];", file=stream)
249
+ print(f"{indent}const POS hi{lvl} = Apos{lvl}[p{P} + 1];", file=stream)
250
+ print(f"{indent}for (POS p{lvl} = lo{lvl}; p{lvl} < hi{lvl}; p{lvl}++) {{", file=stream)
251
+ print(f"{indent} l{lvl} = Acrd{lvl}[p{lvl}];", file=stream)
252
+ P = lvl
253
+ if isinstance(k, LevelExpr) and isinstance(k.operator, (Add, Subtract)):
254
+ assert lasta is None # no add/sub nesting
255
+ lasta = lvl, k # record last add/sub
256
+ elif fmt == LevelFormat.SINGLETON:
257
+ assert lvl > 0 # no driver loop
258
+ print(f"{indent}l{lvl} = Acrd{lvl}[p{P}];", file=stream)
259
+ print(f"{indent}{{", file=stream)
260
+ elif fmt == LevelFormat.RANGE:
261
+ assert lvl > 0 # no driver loop
262
+ assert lasta is not None
263
+ la, add = lasta
264
+ isI = k == add.expression2
265
+ di = tensor.tensor_format.dimensions.index(k)
266
+ dj = tensor.tensor_format.dimensions.index(add.expression1 if isI else add.expression2)
267
+ szi = tensor.extents[di] if action == _EmitAction.APPLY else f"Ad{di}"
268
+ szj = tensor.extents[dj] if action == _EmitAction.APPLY else f"Ad{dj}"
269
+ if isinstance(add.operator, Add):
270
+ print(f"{indent}const CRD of{lvl} = l{la};", file=stream)
271
+ print(f"{indent}const CRD lo{lvl} = llmax(0, of{lvl} - {szj} + 1);", file=stream)
272
+ print(f"{indent}const CRD hi{lvl} = llmin({szi}, of{lvl} + 1);", file=stream)
273
+ else:
274
+ sign = "-" if isI else ""
275
+ print(f"{indent}const CRD of{lvl} = {sign}l{la};", file=stream)
276
+ print(f"{indent}const CRD lo{lvl} = llmax(0, of{lvl});", file=stream)
277
+ print(f"{indent}const CRD hi{lvl} = llmin({szi}, {szj} + of{lvl});", file=stream)
278
+ print(
279
+ f"{indent}POS p{lvl} = p{P} * {szi} + lo{lvl};",
280
+ file=stream,
281
+ )
282
+ print(
283
+ f"{indent}for (CRD i{lvl} = lo{lvl}; i{lvl} < hi{lvl}; i{lvl}++, p{lvl}++) {{",
284
+ file=stream,
285
+ )
286
+ print(f"{indent} l{lvl} = i{lvl};", file=stream)
287
+ P = lvl
288
+ elif fmt == LevelFormat.DELTA:
289
+ assert lvl > 0 # no driver loop
290
+ # Delta compressed inner traversal loop.
291
+ print(f"{indent}const POS lo{lvl} = Apos{lvl}[p{P}];", file=stream)
292
+ print(f"{indent}const POS hi{lvl} = Apos{lvl}[p{P} + 1];", file=stream)
293
+ print(
294
+ f"{indent}for (POS p{lvl} = lo{lvl}, at{lvl} = 0; p{lvl} < hi{lvl}; p{lvl}++, at{lvl}++) {{",
295
+ file=stream,
296
+ )
297
+ print(f"{indent} at{lvl} += Acrd{lvl}[p{lvl}];", file=stream)
298
+ print(f"{indent} l{lvl} = at{lvl};", file=stream)
299
+ P = lvl
300
+ else:
301
+ raise TypeError(f"Unsupported: {fmt}")
302
+ lvl += 1
303
+ # Translation prior to traversal.
304
+ indent = " " * (tensor.num_levels + 1)
305
+ if tensor.tensor_format.is_identity:
306
+ dvars = [f"l{level}" for level in range(tensor.num_levels)]
307
+ else:
308
+ _emit_lvl2dim(tensor, indent, stream)
309
+ dvars = [f"d{d}" for d in range(tensor.num_dimensions)]
310
+ # Transposition of A (last two dimensions).
311
+ if transpose_A:
312
+ dvars[-2], dvars[-1] = dvars[-1], dvars[-2]
313
+ # Perform the traversal.
314
+ if action == _EmitAction.APPLY: # apply
315
+ idxs = ", ".join(d for d in dvars)
316
+ print(f"{indent}Avalues[p{P}] = apply(Avalues[p{P}], {idxs});", file=stream)
317
+ elif action == _EmitAction.DOT: # c = A(i) b(i)
318
+ print(f"{indent}{{", file=stream)
319
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
320
+ _emit_load_a(f"p{P}", stream)
321
+ _emit_load_b(f"{dvars[0]}", stream)
322
+ _emit_atomic(tensor.dtype, indent, "0", stream)
323
+ print(f"{indent}}}", file=stream)
324
+ elif action == _EmitAction.VM or action == _EmitAction.VM_T: # c(k) = A(j) B(j,k)
325
+ print(f"{indent}for (CRD k = 0; k < Bd1; k++) {{", file=stream)
326
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
327
+ _emit_load_a(f"p{P}", stream)
328
+ bidx = f"{dvars[0]} * Bd1 + k" if action == _EmitAction.VM else f"{dvars[0]} + Bd0 * k"
329
+ _emit_load_b(f"{bidx}", stream)
330
+ _emit_atomic(tensor.dtype, indent, "k", stream)
331
+ print(f"{indent}}}", file=stream)
332
+ elif action == _EmitAction.MV: # c(i) = A(i,j) b(j)
333
+ print(f"{indent}{{", file=stream)
334
+ if no_atomic:
335
+ print(f"{indent} acc = add(acc, mul(", end="", file=stream)
336
+ _emit_load_a(f"p{P}", stream)
337
+ _emit_load_b(f"{dvars[1]}", stream, end="));\n")
338
+ else:
339
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
340
+ _emit_load_a(f"p{P}", stream)
341
+ _emit_load_b(f"{dvars[1]}", stream)
342
+ _emit_atomic(tensor.dtype, indent, f"{dvars[0]}", stream)
343
+ print(f"{indent}}}", file=stream)
344
+ elif action == _EmitAction.BMM or action == _EmitAction.BMM_T: # C(b0.., i,k) = A(b0.., i,j) B(j,k)
345
+ b = tensor.num_dimensions - 1
346
+ print(f"{indent}for (CRD k = 0; k < Bd1; k++) {{", file=stream)
347
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
348
+ _emit_load_a(f"p{P}", stream)
349
+ bidx = f"{dvars[b]} * Bd1 + k" if action == _EmitAction.BMM else f"{dvars[b]} + Bd0 * k"
350
+ _emit_load_b(f"{bidx}", stream)
351
+ cidx = f"{dvars[0]}"
352
+ for d in range(1, b):
353
+ cidx = f"({cidx} * Ad{d} + {dvars[d]})"
354
+ _emit_atomic(tensor.dtype, indent, f"{cidx} * Bd1 + k", stream)
355
+ print(f"{indent}}}", file=stream)
356
+ elif action == _EmitAction.BMBM or action == _EmitAction.BMBM_T: # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
357
+ b = tensor.num_dimensions - 1
358
+ print(f"{indent}for (CRD k = 0; k < Bd{b}; k++) {{", file=stream)
359
+ print(f"{indent} const CTP acc = mul(", end="", file=stream)
360
+ _emit_load_a(f"p{P}", stream)
361
+ bidx = f"{dvars[0]}"
362
+ for d in range(1, b - 1):
363
+ bidx = f"({bidx} * Ad{d} + {dvars[d]})"
364
+ bidx = (
365
+ f"(({bidx} * Bd{b - 1}) + {dvars[b]}) * Bd{b} + k"
366
+ if action == _EmitAction.BMBM
367
+ else f"(({bidx} * Bd{b - 1}) + k) * Bd{b} + {dvars[b]}"
368
+ )
369
+ _emit_load_b(f"{bidx}", stream)
370
+ cidx = f"{dvars[0]}"
371
+ for d in range(1, b):
372
+ cidx = f"({cidx} * Ad{d} + {dvars[d]})"
373
+ _emit_atomic(tensor.dtype, indent, f"{cidx} * Bd{b} + k", stream)
374
+ print(f"{indent}}}", file=stream)
375
+ else:
376
+ raise TypeError(f"Unsupported: {action}")
377
+ # Close the traversal.
378
+ for level in range(tensor.num_levels, 0, -1):
379
+ indent = " " * level
380
+ print(f"{indent}}}", file=stream)
381
+ if no_atomic:
382
+ _emit_store_c("l0", indent, stream)
383
+
384
+
385
+ def emit_apply(tensor, with_indices):
386
+ """
387
+ Emits CUDA code for an apply() operation. Note that since the kernel
388
+ is very specific to one UST instance, the kernel can freely specialize
389
+ on metadata like dimension or level sizes.
390
+ """
391
+ stream = StringIO()
392
+ _emit_types(tensor, None, stream)
393
+ dim = tensor.num_dimensions if with_indices else 0
394
+ print(f'\nextern "C" __device__ VAL apply(VAL{", CRD" * dim});\n', file=stream)
395
+ print('extern "C" __global__ void apply_kernel(', file=stream)
396
+ if with_indices:
397
+ _emit_parameters(tensor, "A", 0, stream)
398
+ _emit_header(stream)
399
+ _emit_decls(tensor, stream)
400
+ _emit_traversal(tensor, _EmitAction.APPLY, False, stream)
401
+ else:
402
+ # Fast path for values only.
403
+ print(" VAL* __restrict__ Avalues,", file=stream)
404
+ print(" POS Anse", file=stream)
405
+ _emit_header(stream)
406
+ print(" if (tid >= Anse)", file=stream)
407
+ print(" return;", file=stream)
408
+ print(" Avalues[tid] = apply(Avalues[tid]);", file=stream)
409
+ print("}", file=stream)
410
+ return stream.getvalue()
411
+
412
+
413
+ # TODO: proof-of-concept sparse emitter that should be generalized; currently
414
+ # it only accepts very simple forms where only operand A is sparse;
415
+ # also, currently it drops the prolog_c/epilog when atomic updates are needed
416
+ def _actions(tensor_A, tensor_B, tensor_C):
417
+ """Returns (akind, bkind, action) encoding for supported matmul combinations."""
418
+
419
+ if tensor_B.tensor_format.name not in [
420
+ "DenseVector",
421
+ "DensedRight",
422
+ "DensedLeft",
423
+ "Dense3D-0-1-2",
424
+ "Dense4D-0-1-2-3",
425
+ ] or tensor_C.tensor_format.name not in ["Scalar", "DenseVector", "DensedRight", "Dense3D-0-1-2", "Dense4D-0-1-2-3"]:
426
+ raise NotImplementedError(
427
+ f"The code generator doesn't currently support the \
428
+ {tensor_B.tensor_format.name} or {tensor_C.tensor_format.name} formats."
429
+ )
430
+
431
+ if tensor_A.num_dimensions == 1:
432
+ # A is a vector.
433
+ if tensor_B.num_dimensions == 1 and tensor_C.num_dimensions == 0:
434
+ return 1, 1, _EmitAction.DOT # c = A(i) b(i)
435
+ if tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == 1:
436
+ if tensor_B.tensor_format.name != "DensedLeft":
437
+ return 1, 1, _EmitAction.VM # c(j) = A(i) B(i,j)
438
+ else:
439
+ return 1, 1, _EmitAction.VM_T # c(j) = A(i) B(i,j)^T
440
+ elif tensor_A.num_dimensions == 2:
441
+ # A is a matrix.
442
+ if tensor_B.num_dimensions == 1 and tensor_C.num_dimensions == 1:
443
+ return 1, -1, _EmitAction.MV # c(i) = A(i,j) b(j)
444
+ elif tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == 2:
445
+ if tensor_B.tensor_format.name != "DensedLeft":
446
+ return 1, 1, _EmitAction.BMM # C(i,k) = A(i,j) B(j,k)
447
+ else:
448
+ return 1, 1, _EmitAction.BMM_T # C(i,k) = A(i,j) B(j,k)^T
449
+ elif tensor_A.num_dimensions > 2:
450
+ # A is a tensor.
451
+ if tensor_B.num_dimensions == 2 and tensor_C.num_dimensions == tensor_A.num_dimensions:
452
+ if tensor_B.tensor_format.name != "DensedLeft":
453
+ return 1, 1, _EmitAction.BMM # C(b0.., i,k) = A(b0.., i,j) B(j,k)
454
+ else:
455
+ return 1, 1, _EmitAction.BMM_T # C(b0.., i,k) = A(b0.., i,j) B(j,k)^T
456
+ elif tensor_B.num_dimensions == tensor_A.num_dimensions and tensor_C.num_dimensions == tensor_A.num_dimensions:
457
+ return 1, 1, _EmitAction.BMBM # C(b0.., i,k) = A(b0.., i,j) B(b0.., j,k)
458
+ raise TypeError("Unsupported matmul() in sparse emitter")
459
+
460
+
461
+ def emit_matmul(tensor_A, tensor_B, tensor_C, ctp, transpose_A=False, transpose_B=False):
462
+ """
463
+ Emits CUDA code for a matmul(A, B, C) operation. Note that since the kernel
464
+ is cached at a generic UST and type level only, the kernel should not specialize
465
+ on metadata like dimension or level sizes, but use parameter values instead.
466
+ """
467
+ akind, bkind, action = _actions(tensor_A, tensor_B, tensor_C)
468
+ stream = StringIO()
469
+ _emit_types(tensor_A, ctp, stream)
470
+ print(f"{semiring_ops_decl}{prolog_epilog_decl}", file=stream)
471
+ print('extern "C" __global__ void matmul(', file=stream)
472
+ _emit_parameters(tensor_A, "A", akind, stream)
473
+ _emit_parameters(tensor_B, "B", bkind, stream)
474
+ _emit_parameters(tensor_C, "C", 0, stream)
475
+ _emit_header(stream)
476
+ _emit_decls(tensor_A, stream)
477
+ if transpose_B:
478
+ action = _transposeB(action)
479
+ _emit_traversal(tensor_A, action, transpose_A, stream)
480
+ print("}", file=stream)
481
+ return stream.getvalue()
482
+
483
+
484
+ def _populate_sizes(params, tensor):
485
+ for i in range(tensor.num_dimensions):
486
+ params.append(tensor.extents[i])
487
+ for i in range(tensor.num_levels):
488
+ params.append(tensor.levels[i])
489
+ return params
490
+
491
+
492
+ # TODO: improve the parallelization scheme dramatically
493
+ def _populate_parameter(params, tensor, kind):
494
+ """Private method to populate parameters for a single UST tensor."""
495
+ size = None
496
+ for lvl, (_, fmt) in enumerate(tensor.tensor_format.levels.items()):
497
+ if isinstance(fmt, tuple):
498
+ fmt, _ = fmt
499
+ # Handle level format.
500
+ if fmt == LevelFormat.DENSE or fmt == LevelFormat.BATCH or fmt == LevelFormat.RANGE:
501
+ if lvl == 0:
502
+ size = tensor.levels[0]
503
+ else:
504
+ size = tensor.extents[0] if size < tensor.extents[0] else size
505
+ elif fmt == LevelFormat.COMPRESSED or fmt == LevelFormat.DELTA:
506
+ params.append(tensor.pos(lvl).data_ptr)
507
+ params.append(tensor.crd(lvl).data_ptr)
508
+ if lvl == 0:
509
+ size = tensor.crd(0).size
510
+ elif fmt == LevelFormat.SINGLETON:
511
+ params.append(tensor.crd(lvl).data_ptr)
512
+ else:
513
+ raise TypeError(f"Unsupported: {fmt}")
514
+ params.append(tensor.val.data_ptr)
515
+
516
+ # Optionally append dimension and level sizes.
517
+ if kind == 1:
518
+ params = _populate_sizes(params, tensor)
519
+
520
+ return (params, size)
521
+
522
+
523
+ def populate_apply_parameters(tensor, with_indices=True):
524
+ """
525
+ Populates the parameters for an apply() operation (with our without indices).
526
+ The API follows the UST parameter passing conventions for the tensor when
527
+ indices are needed. Otherwise it directly passes the values buffer.
528
+
529
+ Returns (parameter list, kernel launch size)
530
+ """
531
+ if with_indices:
532
+ return _populate_parameter([], tensor, 0)
533
+ return ([tensor.val.data_ptr, tensor.nse], tensor.nse)
534
+
535
+
536
+ def populate_matmul_parameters(tensor_A, tensor_B, tensor_C, dense_bc=False):
537
+ """
538
+ Populates the parameters for a matmul(A, B, C) operation.
539
+
540
+ The API follows the UST parameter passing conventions for A, B, C,
541
+ each possibly followed by the dimension and level sizes.
542
+
543
+ Returns (parameter list, kernel launch size)
544
+ """
545
+ akind, bkind, _ = _actions(tensor_A, tensor_B, tensor_C)
546
+ params = []
547
+ params, n = _populate_parameter(params, tensor_A, akind)
548
+ if dense_bc:
549
+ # Fast path for dense B and C.
550
+ params.append(tensor_B._val.data_ptr)
551
+ if bkind == 1:
552
+ params = _populate_sizes(params, tensor_B)
553
+ params.append(tensor_C._val.data_ptr)
554
+ else:
555
+ params, _ = _populate_parameter(params, tensor_B, bkind)
556
+ params, _ = _populate_parameter(params, tensor_C, 0)
557
+ assert n is not None
558
+ return (params, n)