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,957 @@
1
+ # Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ The tensor format DSL of the Universal Sparse Tensor maps tensor dimensions
7
+ (logical tensor indices) to storage levels (physical memory indices) using
8
+ an invertible function that defines how each level should be stored.
9
+ """
10
+
11
+ __all__ = [
12
+ "is_ordered",
13
+ "is_unique",
14
+ "Dimension",
15
+ "LevelFormat",
16
+ "LevelProperty",
17
+ "LevelExpr",
18
+ "TensorFormat",
19
+ "NamedFormats",
20
+ ]
21
+
22
+ from collections.abc import Sequence
23
+ from enum import IntEnum
24
+
25
+
26
+ def is_ordered(prop):
27
+ """Determines if given property is ordered."""
28
+ if isinstance(prop, Sequence):
29
+ for p in prop:
30
+ if not is_ordered(p):
31
+ return False
32
+ elif isinstance(prop, LevelProperty) and prop == LevelProperty.UNORDERED:
33
+ return False
34
+ return True # ordered unless seen otherwise
35
+
36
+
37
+ def is_unique(prop):
38
+ """Determines if given property is unique."""
39
+ if isinstance(prop, Sequence):
40
+ for p in prop:
41
+ if not is_unique(p):
42
+ return False
43
+ elif isinstance(prop, LevelProperty) and prop == LevelProperty.NONUNIQUE:
44
+ return False
45
+ return True # unique unless seen otherwise
46
+
47
+
48
+ class LevelFormat(IntEnum):
49
+ DENSE = 0
50
+ BATCH = 1
51
+ COMPRESSED = 2
52
+ SINGLETON = 3
53
+ RANGE = 4
54
+ DELTA = 5
55
+ STRUCTURED = 6
56
+
57
+ def __repr__(self):
58
+ """Returns representation without index."""
59
+ return f"<{self.__class__.__name__}.{self.name}>"
60
+
61
+
62
+ class LevelProperty(IntEnum):
63
+ UNIQUE = 0
64
+ NONUNIQUE = 1
65
+ ORDERED = 2
66
+ UNORDERED = 3
67
+
68
+ def __repr__(self):
69
+ """Returns representation without index."""
70
+ return f"<{self.__class__.__name__}.{self.name}>"
71
+
72
+
73
+ # The inverse map is used to check for certain incompatible property sequences.
74
+ LevelPropertyInverse = {
75
+ LevelProperty.UNIQUE: LevelProperty.NONUNIQUE,
76
+ LevelProperty.NONUNIQUE: LevelProperty.UNIQUE,
77
+ LevelProperty.ORDERED: LevelProperty.UNORDERED,
78
+ LevelProperty.UNORDERED: LevelProperty.ORDERED,
79
+ }
80
+
81
+
82
+ def _find_range(levels, expr1, expr2):
83
+ for rl, (k, v) in enumerate(levels.items()):
84
+ if v == LevelFormat.RANGE and k in (expr1, expr2):
85
+ return rl, k
86
+ raise ValueError(f"Cannot find {expr1} or {expr2} in levels")
87
+
88
+
89
+ class Operator:
90
+ """
91
+ An abstract binary level expression operator type.
92
+ """
93
+
94
+ # TODO: use protocol.
95
+ pass
96
+
97
+
98
+ class Add(Operator):
99
+ """
100
+ Add two level expressions.
101
+ """
102
+
103
+ def __call__(self, expr1, expr2, as_size):
104
+ if as_size:
105
+ return expr1 + expr2 - 1
106
+ return expr1 + expr2
107
+
108
+ def invert(self, expr1, expr2, dimensions, levels, dim_indices, lvl_indices, idx):
109
+ rl, re = _find_range(levels, expr1, expr2)
110
+ if re == expr2:
111
+ dim_indices[dimensions.index(expr1)] = lvl_indices[idx] - lvl_indices[rl]
112
+ else:
113
+ assert re == expr1
114
+ dim_indices[dimensions.index(expr2)] = lvl_indices[idx] - lvl_indices[rl]
115
+
116
+ def __repr__(self):
117
+ return "+"
118
+
119
+
120
+ class Subtract(Operator):
121
+ """
122
+ Subtract a level expression from another.
123
+ """
124
+
125
+ def __call__(self, expr1, expr2, as_size):
126
+ if as_size:
127
+ return expr1 + expr2 - 1
128
+ return expr1 - expr2
129
+
130
+ def invert(self, expr1, expr2, dimensions, levels, dim_indices, lvl_indices, idx):
131
+ rl, re = _find_range(levels, expr1, expr2)
132
+ if re == expr2:
133
+ dim_indices[dimensions.index(expr1)] = lvl_indices[rl] + lvl_indices[idx]
134
+ else:
135
+ assert re == expr1
136
+ dim_indices[dimensions.index(expr2)] = lvl_indices[rl] - lvl_indices[idx]
137
+
138
+ def __repr__(self):
139
+ return "-"
140
+
141
+
142
+ class Divide(Operator):
143
+ """
144
+ Divide a level expression by an integer.
145
+ """
146
+
147
+ def __call__(self, expr1, expr2, as_size):
148
+ if as_size:
149
+ assert expr2 > 0, f"Internal error: {expr2}"
150
+ if expr1 % expr2 != 0:
151
+ raise NotImplementedError(f"block size {expr2} does not evenly divide size {expr1}")
152
+ return expr1 // expr2
153
+
154
+ def invert(self, expr1, expr2, dimensions, levels, dim_indices, lvl_indices, idx):
155
+ i = dimensions.index(expr1)
156
+ dim_indices[i] = lvl_indices[idx] * expr2
157
+
158
+ def __repr__(self):
159
+ return "//"
160
+
161
+
162
+ class Modulo(Operator):
163
+ """
164
+ The integer modulo of a level expression.
165
+ """
166
+
167
+ def __call__(self, expr1, expr2, as_size):
168
+ if as_size:
169
+ assert expr2 > 0, f"Internal error: {expr2}"
170
+ return expr2
171
+ return expr1 % expr2
172
+
173
+ def invert(self, expr1, expr2, dimensions, levels, dim_indices, lvl_indices, idx):
174
+ i = dimensions.index(expr1)
175
+ dim_indices[i] += lvl_indices[idx] # update (seen after div)
176
+
177
+ def __repr__(self):
178
+ return "%"
179
+
180
+
181
+ class LevelExpr:
182
+ """
183
+ A (binary) level expression is a triple: dimension object or level expression,
184
+ operator, dimension or level expression or int.
185
+
186
+ Args:
187
+ expression1: a Dimension or LevelExpr object.
188
+ operator: operator derived from Operator (Add, Subtract, Divide, Modulo).
189
+ expression2: a Dimension or LevelExpr object, or an integer.
190
+ """
191
+
192
+ __slots__ = ("expression1", "operator", "expression2")
193
+
194
+ def __init__(self, *, expression1, operator, expression2):
195
+ lhs_level_expr_types = Dimension, LevelExpr
196
+ rhs_level_expr_types = lhs_level_expr_types + (int,)
197
+ if not isinstance(expression1, lhs_level_expr_types):
198
+ raise TypeError(f"LHS expression {expression1} must have one of these types: {lhs_level_expr_types}.")
199
+ if not isinstance(operator, Operator):
200
+ raise TypeError(f"Operator {operator} must be derived from Operator.")
201
+ if not isinstance(expression2, rhs_level_expr_types):
202
+ raise TypeError(f"RHS expression {expression2} must have one of these types: {rhs_level_expr_types}.")
203
+ self.expression1 = expression1
204
+ self.operator = operator
205
+ self.expression2 = expression2
206
+
207
+ def __repr__(self):
208
+ return f"({self.expression1} {self.operator} {self.expression2})"
209
+
210
+ def __add__(self, expression):
211
+ return LevelExpr(expression1=self, operator=Add(), expression2=expression)
212
+
213
+ def __sub__(self, expression):
214
+ return LevelExpr(expression1=self, operator=Subtract(), expression2=expression)
215
+
216
+ def __floordiv__(self, divisor):
217
+ return LevelExpr(expression1=self, operator=Divide(), expression2=divisor)
218
+
219
+ def __mod__(self, modulus):
220
+ return LevelExpr(expression1=self, operator=Modulo(), expression2=modulus)
221
+
222
+ def evaluate(self, dimensions, dim_indices, as_size):
223
+ e1 = self.expression1.evaluate(dimensions, dim_indices, as_size)
224
+ e2 = (
225
+ self.expression2.evaluate(dimensions, dim_indices, as_size)
226
+ if not isinstance(self.expression2, int)
227
+ else self.expression2
228
+ )
229
+ return self.operator(e1, e2, as_size)
230
+
231
+ def invert(self, dimensions, levels, dim_indices, lvl_indices, idx):
232
+ self.operator.invert(
233
+ self.expression1,
234
+ self.expression2,
235
+ dimensions,
236
+ levels,
237
+ dim_indices,
238
+ lvl_indices,
239
+ idx,
240
+ )
241
+
242
+
243
+ class Dimension:
244
+ """
245
+ A dimension object encapsulates a dimension name.
246
+
247
+ Args:
248
+ dimension_name: A name for the dimension.
249
+ """
250
+
251
+ __slots__ = ("dimension_name",)
252
+
253
+ def __init__(self, *, dimension_name):
254
+ if not isinstance(dimension_name, str):
255
+ raise TypeError(f"The dimension name {dimension_name} must be a string.")
256
+
257
+ self.dimension_name = dimension_name
258
+
259
+ def __repr__(self):
260
+ return f"{self.dimension_name}"
261
+
262
+ def __add__(self, expression):
263
+ return LevelExpr(expression1=self, operator=Add(), expression2=expression)
264
+
265
+ def __sub__(self, expression):
266
+ return LevelExpr(expression1=self, operator=Subtract(), expression2=expression)
267
+
268
+ def __floordiv__(self, divisor):
269
+ return LevelExpr(expression1=self, operator=Divide(), expression2=divisor)
270
+
271
+ def __mod__(self, modulus):
272
+ return LevelExpr(expression1=self, operator=Modulo(), expression2=modulus)
273
+
274
+ def evaluate(self, dimensions, dim_indices, as_size):
275
+ return dim_indices[dimensions.index(self)]
276
+
277
+ def invert(self, dimensions, levels, dim_indices, lvl_indices, idx):
278
+ dim_indices[dimensions.index(self)] = lvl_indices[idx]
279
+
280
+
281
+ class TensorFormat:
282
+ """
283
+ A universal sparse tensor format maps dimension specifications
284
+ (dimensions for short) to level specifications (levels for short).
285
+
286
+ Args:
287
+ dimensions: a sequence of Dimension objects.
288
+ levels: an ordered dictionary from a LevelExpr or Dimension object
289
+ to a LevelFormat, or a (LevelFormat, LevelProperty) pair.
290
+ name: a name for the format as a string. If the format corresponds to an
291
+ existing format like CSR, COO, etc. use the canonical name. A name
292
+ will be generated based on the level specification if none is provided.
293
+ """
294
+
295
+ __slots__ = ("_dimensions", "_levels", "_name", "_is_identity", "_is_ordered", "_is_unique")
296
+
297
+ def __init__(self, dimensions, levels, *, name=None):
298
+ self._dimensions = dimensions
299
+ self._levels = levels
300
+
301
+ # TODO: create a better default name.
302
+ if name is None:
303
+ name = f"{levels}".replace("\n", " ")
304
+ if not isinstance(name, str):
305
+ raise TypeError(f"The name {name} must be a string.")
306
+ self._name = name
307
+
308
+ # Perform semantic checks on syntactic structure.
309
+ # Throws a TypeError on failure.
310
+ self._semantically_validate()
311
+
312
+ # Cached properties.
313
+ self._is_identity = (
314
+ all(isinstance(lvl, Dimension) and self.dimensions.index(lvl) == idx for idx, lvl in enumerate(levels))
315
+ if self.num_dimensions == self.num_levels
316
+ else False
317
+ )
318
+ self._is_ordered = all(is_ordered(lvl[1]) if isinstance(lvl, tuple) else True for lvl in levels.values())
319
+ self._is_unique = any(is_unique(lvl[1]) if isinstance(lvl, tuple) else True for lvl in levels.values())
320
+
321
+ @property
322
+ def name(self):
323
+ """
324
+ Get the name of the sparse tensor format.
325
+ """
326
+ return self._name
327
+
328
+ @property
329
+ def num_dimensions(self):
330
+ """
331
+ Get the number of dimensions (rank of tensor).
332
+ """
333
+ return len(self._dimensions)
334
+
335
+ @property
336
+ def num_levels(self):
337
+ """
338
+ Get the number of levels (rank of storage).
339
+ """
340
+ return len(self._levels)
341
+
342
+ @property
343
+ def dimensions(self):
344
+ """
345
+ Get the dimension specifications for this format.
346
+ """
347
+ return self._dimensions
348
+
349
+ @property
350
+ def levels(self):
351
+ """
352
+ Get the level specifications for this format.
353
+ """
354
+ return self._levels
355
+
356
+ @property
357
+ def is_identity(self):
358
+ """
359
+ Determine whether the format uses identity mapping between dimensions and levels.
360
+ """
361
+ return self._is_identity
362
+
363
+ @property
364
+ def is_ordered(self):
365
+ """
366
+ Determine whether the format is ordered.
367
+ """
368
+ return self._is_ordered
369
+
370
+ @property
371
+ def is_unique(self):
372
+ """
373
+ Determine whether the format is unique.
374
+ """
375
+ # TODO: imprecise, but works for expected cases like
376
+ # e.g. COO3 (compressed(!U), singleton(!U), singleton(U)) is still unique
377
+ # but COO3 (compressed(!U), singleton(!U), singleton(!U)) is nonunique
378
+ return self._is_unique
379
+
380
+ def _semantically_validate(self):
381
+ """
382
+ Semantically validates the sparse tensor format. The grammar allows for specifying
383
+ a very wide range of sparse tensor formats. However, not every syntactically
384
+ valid input is also semanticaly valid. This method throws a TypeError for
385
+ tensor formats where the following constraints are not satisfied :
386
+
387
+ (1) the input syntax has an actual implementation
388
+ (2) the dim-to-level mapping is easily invertible
389
+
390
+ Note that currently the checks are **stricter** than really required.
391
+ However, developers that relax the checks below are also responsible for
392
+ ensuring that constraints (1) and (2) are still satisfied.
393
+ """
394
+ # Reject incorrect dimension specifications types.
395
+ if not (isinstance(self.dimensions, Sequence) and all(isinstance(d, Dimension) for d in self.dimensions)):
396
+ raise TypeError(f"Dimension specifications {self.dimensions} must be a sequence of Dimension objects.")
397
+
398
+ # Reject dimension specifications that are not unique names (e.g. (i,i)).
399
+ all_dims = set(self.dimensions)
400
+ if len(all_dims) != len(self.dimensions):
401
+ raise TypeError(f"Dimension specifications {self.dimensions} has repeated identifiers.")
402
+
403
+ # Reject incorrect level specification types.
404
+ if not (isinstance(self.levels, dict)):
405
+ raise TypeError(f"Level specifications {self.levels} must be an ordered dictionary.")
406
+
407
+ # Reject incorrect level specification structure.
408
+ used_dims = set()
409
+ range_dims = {}
410
+ block_dims = {}
411
+ batch = 0
412
+ for idx, (k, v) in enumerate(self.levels.items()):
413
+ # Check the level expression.
414
+ if isinstance(k, Dimension):
415
+ if k not in self.dimensions:
416
+ raise TypeError(f"Dimension {k} does not appear in {self.dimensions}.")
417
+ used_dims.add(k)
418
+ elif isinstance(k, LevelExpr):
419
+ # Check for unnested level expressions and impose some constraints.
420
+ # We expect (Add, Subtract, Divide, Modulo) only.
421
+ if isinstance(k.operator, (Add, Subtract)):
422
+ # Only allow for direct expressions like i - j.
423
+ if k.expression1 not in self.dimensions:
424
+ raise TypeError(f"LHS {k.expression1} in {k} does not appear in {self.dimensions}.")
425
+ if k.expression2 not in self.dimensions:
426
+ raise TypeError(f"RHS {k.expression2} in {k} does not appear in {self.dimensions}.")
427
+ used_dims.add(k.expression1)
428
+ used_dims.add(k.expression2)
429
+ # Find matching range.
430
+ if k.expression1 in range_dims or k.expression2 in range_dims:
431
+ raise TypeError(f"Operation {k} reuses dimension of a prior range computation.")
432
+ range_dims[k.expression1] = k.expression2
433
+ range_dims[k.expression2] = k.expression1
434
+ elif isinstance(k.operator, (Divide, Modulo)):
435
+ # Only allow for direct expressions like i % 3.
436
+ if k.expression1 not in self.dimensions:
437
+ raise TypeError(f"LHS {k.expression1} in {k} does not appear in {self.dimensions}.")
438
+ if not isinstance(k.expression2, int):
439
+ raise TypeError(f"RHS {k.expression2} in {k} must be an integer.")
440
+ elif k.expression2 <= 0:
441
+ raise TypeError(f"RHS {k.expression2} in {k} must be strictly positive integer.")
442
+ used_dims.add(k.expression1)
443
+ # Find matching blocking.
444
+ if isinstance(k.operator, Divide):
445
+ if k.expression1 in block_dims:
446
+ raise TypeError(f"Division {k} reuses dimension of a prior division.")
447
+ block_dims[k.expression1] = k.expression2
448
+ elif isinstance(k.operator, Modulo):
449
+ if block_dims.get(k.expression1, 0) != k.expression2:
450
+ raise TypeError(f"Modulo {k} does not match any prior division.")
451
+ block_dims[k.expression1] = 0 # avoid further usage
452
+ else:
453
+ raise TypeError(f"Unexpected operator in level expression {k}.")
454
+ else:
455
+ raise TypeError(f"Level expression {k} must be a Dimension or LevelExpr object.")
456
+
457
+ # Inspect the level format for explicit or implicit properties.
458
+ if isinstance(v, tuple):
459
+ fmt, prop = v
460
+ else:
461
+ fmt, prop = v, LevelProperty.ORDERED
462
+
463
+ # Check level format.
464
+ if not isinstance(fmt, LevelFormat):
465
+ raise TypeError(f"Invalid level format {fmt}.")
466
+ elif fmt == LevelFormat.RANGE:
467
+ if not isinstance(k, Dimension):
468
+ raise TypeError(f"Range uses compound level expression {k}.")
469
+ other = range_dims.get(k, 0)
470
+ if other == 0:
471
+ raise TypeError(f"Range uses dimension {k} that is not uniquely defined.")
472
+ # Consume range tuple.
473
+ range_dims[k] = 0
474
+ range_dims[other] = 0
475
+
476
+ # Verify batching.
477
+ if fmt == LevelFormat.BATCH:
478
+ if k != self.dimensions[idx]:
479
+ raise TypeError(f"Batch uses non-identity {k} for {self.dimensions[idx]}.")
480
+ if batch == -1:
481
+ raise TypeError(f"Batch is used in inner level {idx}.")
482
+ batch += 1
483
+ elif batch > 0 and fmt != LevelFormat.DENSE:
484
+ raise TypeError("Batch levels must end in a dense level.")
485
+ else:
486
+ batch = -1
487
+
488
+ # Check level properties.
489
+ if isinstance(prop, Sequence):
490
+ invalid = []
491
+ for p_ in prop:
492
+ if not isinstance(p_, LevelProperty):
493
+ raise TypeError(f"Invalid level property {p_}.")
494
+ if LevelPropertyInverse[p_] in prop:
495
+ invalid += (p_,)
496
+ if invalid:
497
+ raise TypeError(f"Invalid level property combination: {invalid}.")
498
+ elif not isinstance(prop, LevelProperty) and not isinstance(prop, int):
499
+ raise TypeError(f"Invalid level property {prop}.")
500
+
501
+ # Check that every dimension is used eventually.
502
+ if len(all_dims) != len(used_dims):
503
+ raise TypeError(f"The following dimensions are not used: {all_dims - used_dims}.")
504
+
505
+ # Check that every div is matched by mod.
506
+ unmatched = [key for key, value in block_dims.items() if value != 0]
507
+ if len(unmatched) != 0:
508
+ raise TypeError(f"Some division dimensions are not matched by modulo: {unmatched}.")
509
+
510
+ # Check that every add/sub is matched by range.
511
+ unmatched = [key for key, value in range_dims.items() if value != 0]
512
+ if len(unmatched) != 0:
513
+ raise TypeError(f"Some add/sub dimensions are not matched by range: {unmatched}.")
514
+
515
+ # Check that batching ends in dense.
516
+ if batch > 0:
517
+ raise TypeError("Batch levels are not properly closed by a dense level.")
518
+
519
+ def dim2lvl(self, dim_indices, as_size=False):
520
+ """
521
+ Maps the dimension index list to the level index list.
522
+
523
+ Examples:
524
+ CSR: [0,4] -> [0,4]
525
+ CSC: [0,4] -> [4,0]
526
+ BSRRight(2,2): [2,1] -> [1,0,0,1]
527
+ """
528
+ return [ls.evaluate(self.dimensions, dim_indices, as_size) for ls in self.levels]
529
+
530
+ def lvl2dim(self, lvl_indices):
531
+ """
532
+ Maps the level index list to the dimension index list (the inverse of dim2lvl).
533
+ We can safely assume that the mapping is invertible given that the tensor format
534
+ passed validation.
535
+
536
+ Examples:
537
+ CSR: [0,4] -> [0,4]
538
+ CSC: [4,0] -> [0,4]
539
+ BSRRight(2,2): [1,0,0,1] -> [2,1]
540
+ """
541
+ dim_indices = [0] * self.num_dimensions # pre-populate
542
+ for idx, ls in enumerate(self.levels):
543
+ ls.invert(self.dimensions, self.levels, dim_indices, lvl_indices, idx)
544
+ return dim_indices
545
+
546
+ def __repr__(self):
547
+ return (
548
+ f"{self.dimensions} -> ("
549
+ + ", ".join([f"{k}: {v if isinstance(v, Sequence) else repr(v)}" for k, v in self.levels.items()])
550
+ + ")"
551
+ )
552
+
553
+
554
+ class NamedFormats:
555
+ """
556
+ A number of pre-defined common tensor formats (direct or using builders).
557
+ Clients can always construct these or other tensor formats directly.
558
+ """
559
+
560
+ i, j, k, b = (
561
+ Dimension(dimension_name="i"),
562
+ Dimension(dimension_name="j"),
563
+ Dimension(dimension_name="k"),
564
+ Dimension(dimension_name="batch"),
565
+ )
566
+
567
+ # Scalar format.
568
+ Scalar = TensorFormat([], {}, name="Scalar")
569
+
570
+ # Vector formats.
571
+ DenseVector = TensorFormat([i], {i: LevelFormat.DENSE}, name="DenseVector")
572
+ SparseVector = TensorFormat([i], {i: LevelFormat.COMPRESSED}, name="SparseVector")
573
+
574
+ # Dense matrix formats.
575
+ DenseMatrixRight = TensorFormat(
576
+ [i, j],
577
+ {i: LevelFormat.DENSE, j: LevelFormat.DENSE},
578
+ name="DenseMatrixRight",
579
+ )
580
+ DenseMatrixLeft = TensorFormat(
581
+ [i, j],
582
+ {j: LevelFormat.DENSE, i: LevelFormat.DENSE},
583
+ name="DenseMatrixLeft",
584
+ )
585
+
586
+ # Sparse matrix formats.
587
+ COO = TensorFormat(
588
+ [i, j],
589
+ {
590
+ i: (LevelFormat.COMPRESSED, LevelProperty.NONUNIQUE),
591
+ j: LevelFormat.SINGLETON,
592
+ },
593
+ name="COO",
594
+ )
595
+ CSR = TensorFormat([i, j], {i: LevelFormat.DENSE, j: LevelFormat.COMPRESSED}, name="CSR")
596
+ CSC = TensorFormat([i, j], {j: LevelFormat.DENSE, i: LevelFormat.COMPRESSED}, name="CSC")
597
+ DCSR = TensorFormat(
598
+ [i, j],
599
+ {i: LevelFormat.COMPRESSED, j: LevelFormat.COMPRESSED},
600
+ name="DCSR",
601
+ )
602
+ DCSC = TensorFormat(
603
+ [i, j],
604
+ {j: LevelFormat.COMPRESSED, i: LevelFormat.COMPRESSED},
605
+ name="DCSC",
606
+ )
607
+ CROW = TensorFormat([i, j], {i: LevelFormat.COMPRESSED, j: LevelFormat.DENSE}, name="CROW")
608
+ CCOL = TensorFormat([i, j], {j: LevelFormat.COMPRESSED, i: LevelFormat.DENSE}, name="CCOL")
609
+
610
+ # Diagonal matrix formats.
611
+ DIAI = TensorFormat(
612
+ [i, j],
613
+ {j - i: LevelFormat.COMPRESSED, i: LevelFormat.RANGE},
614
+ name="DIAI",
615
+ )
616
+ DIAJ = TensorFormat(
617
+ [i, j],
618
+ {j - i: LevelFormat.COMPRESSED, j: LevelFormat.RANGE},
619
+ name="DIAJ",
620
+ )
621
+ SkewDIAI = TensorFormat(
622
+ [i, j],
623
+ {i + j: LevelFormat.COMPRESSED, i: LevelFormat.RANGE},
624
+ name="SkewDIAI",
625
+ )
626
+ SkewDIAJ = TensorFormat(
627
+ [i, j],
628
+ {i + j: LevelFormat.COMPRESSED, j: LevelFormat.RANGE},
629
+ name="SkewDIAJ",
630
+ )
631
+
632
+ # Batched sparse matrices.
633
+ BatchedCSR = TensorFormat(
634
+ [b, i, j],
635
+ {b: LevelFormat.DENSE, i: LevelFormat.DENSE, j: LevelFormat.COMPRESSED},
636
+ name="BatchedCSR",
637
+ )
638
+ BatchedDIAINonUniform = TensorFormat(
639
+ [b, i, j],
640
+ {b: LevelFormat.DENSE, j - i: LevelFormat.COMPRESSED, i: LevelFormat.RANGE},
641
+ name="BatchedDIAINonUniform",
642
+ )
643
+ BatchedDIAIUniform = TensorFormat(
644
+ [b, i, j],
645
+ {j - i: LevelFormat.COMPRESSED, b: LevelFormat.DENSE, i: LevelFormat.RANGE},
646
+ name="BatchedDIAIUniform",
647
+ )
648
+
649
+ #
650
+ # Tensor format builders for vectors, matrices, and tensors.
651
+ #
652
+
653
+ @staticmethod
654
+ def BlockVector(blocksize):
655
+ """
656
+ Block vector format.
657
+
658
+ Args:
659
+ blocksize: an integer specifying the blocksize in the i'th dimension.
660
+ """
661
+ i = NamedFormats.i
662
+ name = f"BlockVector{blocksize}"
663
+ return TensorFormat(
664
+ [i],
665
+ {i // blocksize: LevelFormat.COMPRESSED, i % blocksize: LevelFormat.DENSE},
666
+ name=name,
667
+ )
668
+
669
+ @staticmethod
670
+ def BSRRight(blocksize):
671
+ """
672
+ BSRRight matrix format.
673
+
674
+ Args:
675
+ blocksize: a pair specifying the blocksize in the i'th and j'th dimensions.
676
+ """
677
+ i, j = NamedFormats.i, NamedFormats.j
678
+ m, n = blocksize
679
+ name = f"BSRRight{m}x{n}"
680
+ return TensorFormat(
681
+ [i, j],
682
+ {
683
+ i // m: LevelFormat.DENSE,
684
+ j // n: LevelFormat.COMPRESSED,
685
+ i % m: LevelFormat.DENSE,
686
+ j % n: LevelFormat.DENSE,
687
+ },
688
+ name=name,
689
+ )
690
+
691
+ @staticmethod
692
+ def BSRLeft(blocksize):
693
+ """
694
+ BSRLeft matrix format.
695
+
696
+ Args:
697
+ blocksize: a pair specifying the blocksize in the i'th and j'th dimensions.
698
+ """
699
+ i, j = NamedFormats.i, NamedFormats.j
700
+ m, n = blocksize
701
+ name = f"BSRLeft{m}x{n}"
702
+ return TensorFormat(
703
+ [i, j],
704
+ {
705
+ i // m: LevelFormat.DENSE,
706
+ j // n: LevelFormat.COMPRESSED,
707
+ j % n: LevelFormat.DENSE,
708
+ i % m: LevelFormat.DENSE,
709
+ },
710
+ name=name,
711
+ )
712
+
713
+ @staticmethod
714
+ def BSCRight(blocksize):
715
+ """
716
+ BSCRight matrix format.
717
+
718
+ Args:
719
+ blocksize: a pair specifying the blocksize in the i'th and j'th dimensions.
720
+ """
721
+ i, j = NamedFormats.i, NamedFormats.j
722
+ m, n = blocksize
723
+ name = f"BSCRow{m}x{n}"
724
+ return TensorFormat(
725
+ [i, j],
726
+ {
727
+ j // n: LevelFormat.DENSE,
728
+ i // m: LevelFormat.COMPRESSED,
729
+ i % m: LevelFormat.DENSE,
730
+ j % n: LevelFormat.DENSE,
731
+ },
732
+ name=name,
733
+ )
734
+
735
+ @staticmethod
736
+ def BSCLeft(blocksize):
737
+ """
738
+ BSCLeft matrix format.
739
+
740
+ Args:
741
+ blocksize: a pair specifying the blocksize in the i'th and j'th dimensions.
742
+ """
743
+ i, j = NamedFormats.i, NamedFormats.j
744
+ m, n = blocksize
745
+ name = f"BSCCol{m}x{n}"
746
+ return TensorFormat(
747
+ [i, j],
748
+ {
749
+ j // n: LevelFormat.DENSE,
750
+ i // m: LevelFormat.COMPRESSED,
751
+ j % n: LevelFormat.DENSE,
752
+ i % m: LevelFormat.DENSE,
753
+ },
754
+ name=name,
755
+ )
756
+
757
+ @staticmethod
758
+ def DELTA(delta):
759
+ """
760
+ Delta compression matrix format.
761
+
762
+ Args:
763
+ delta: number of bits for delta
764
+ """
765
+ if delta <= 0:
766
+ raise ValueError(f"Invalid DELTA parameter: delta={delta}. Require 0 < delta.")
767
+ i, j = NamedFormats.i, NamedFormats.j
768
+ name = f"Delta{delta}"
769
+ return TensorFormat(
770
+ [i, j],
771
+ {i: LevelFormat.DENSE, j: (LevelFormat.DELTA, delta)},
772
+ name=name,
773
+ )
774
+
775
+ @staticmethod
776
+ def Structured(N, M):
777
+ """
778
+ N:M Matrices (structured sparsity), e.g. 2:4
779
+
780
+ Args:
781
+ N: number of nonzeros per strip
782
+ M: number of elements in a strip
783
+ """
784
+ if not (0 < N <= M):
785
+ raise ValueError(f"Invalid N:M parameters: N={N}, M={M}. Require 0 < N <= M.")
786
+ i, j = NamedFormats.i, NamedFormats.j
787
+ name = f"Structured{N}:{M}"
788
+ return TensorFormat(
789
+ [i, j],
790
+ {i: LevelFormat.DENSE, j // M: LevelFormat.DENSE, j % M: (LevelFormat.STRUCTURED, N)},
791
+ name=name,
792
+ )
793
+
794
+ @staticmethod
795
+ def BSR3(blocksize):
796
+ """
797
+ 3D BSR format.
798
+
799
+ Args:
800
+ blocksize: a triple specifying the blocksize in the i'th, j'th, and k'th
801
+ dimensions.
802
+ """
803
+ i, j, k = NamedFormats.i, NamedFormats.j, NamedFormats.k
804
+ m, n, o = blocksize
805
+ name = f"BSR3{m}x{n}x{o}"
806
+ return TensorFormat(
807
+ [i, j, k],
808
+ {
809
+ i // m: LevelFormat.DENSE,
810
+ j // n: LevelFormat.COMPRESSED,
811
+ k // o: LevelFormat.COMPRESSED,
812
+ i % m: LevelFormat.DENSE,
813
+ j % n: LevelFormat.DENSE,
814
+ k % o: LevelFormat.DENSE,
815
+ },
816
+ name=name,
817
+ )
818
+
819
+ @staticmethod
820
+ def DensedRight(dim):
821
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
822
+ return TensorFormat(
823
+ dims,
824
+ {dims[d]: LevelFormat.DENSE for d in range(dim)},
825
+ name=f"Dense{dim}Right",
826
+ )
827
+
828
+ @staticmethod
829
+ def DensedLeft(dim):
830
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
831
+ return TensorFormat(
832
+ dims,
833
+ {dims[dim - d - 1]: LevelFormat.DENSE for d in range(dim)},
834
+ name=f"Dense{dim}Left",
835
+ )
836
+
837
+ @staticmethod
838
+ def COOd(sparse_dim, dense_dim=0):
839
+ dim = sparse_dim + dense_dim
840
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
841
+ return TensorFormat(
842
+ dims,
843
+ {
844
+ dims[d]: (
845
+ (LevelFormat.COMPRESSED if sparse_dim == 1 else (LevelFormat.COMPRESSED, LevelProperty.NONUNIQUE))
846
+ if d == 0
847
+ else LevelFormat.SINGLETON
848
+ if d < sparse_dim
849
+ else LevelFormat.DENSE
850
+ )
851
+ for d in range(dim)
852
+ },
853
+ name=("COO" if dim == 2 else f"COO{dim}") if dense_dim == 0 else None,
854
+ )
855
+
856
+ @staticmethod
857
+ def CSRd(batch_dim=0, dense_dim=0):
858
+ dim = batch_dim + 2 + dense_dim
859
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
860
+
861
+ name = "CSR"
862
+ if batch_dim > 0:
863
+ name += f"-b{batch_dim}"
864
+ if dense_dim > 0:
865
+ name += f"-d{dense_dim}"
866
+
867
+ return TensorFormat(
868
+ dims,
869
+ {
870
+ dims[d]:
871
+ # Format
872
+ LevelFormat.BATCH if d < batch_dim else LevelFormat.COMPRESSED if d == batch_dim + 1 else LevelFormat.DENSE
873
+ for d in range(dim)
874
+ },
875
+ name=name,
876
+ )
877
+
878
+ @staticmethod
879
+ def CSCd(batch_dim=0, dense_dim=0):
880
+ dim = batch_dim + 2 + dense_dim
881
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
882
+
883
+ name = "CSC"
884
+ if batch_dim > 0:
885
+ name += f"-b{batch_dim}"
886
+ if dense_dim > 0:
887
+ name += f"-d{dense_dim}"
888
+
889
+ return TensorFormat(
890
+ dims,
891
+ {
892
+ dims[d + 1 if d == batch_dim else d - 1 if d == batch_dim + 1 else d]:
893
+ # Format
894
+ LevelFormat.BATCH if d < batch_dim else LevelFormat.COMPRESSED if d == batch_dim + 1 else LevelFormat.DENSE
895
+ for d in range(dim)
896
+ },
897
+ name=name,
898
+ )
899
+
900
+ @staticmethod
901
+ def BSRRightd(blocksize, batch_dim=0, dense_dim=0):
902
+ m, n = blocksize
903
+ dim = batch_dim + 2 + dense_dim
904
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
905
+
906
+ name = f"BSRRight{m}x{n}"
907
+ if batch_dim > 0:
908
+ name += f"-b{batch_dim}"
909
+ if dense_dim > 0:
910
+ name += f"-d{dense_dim}"
911
+
912
+ return TensorFormat(
913
+ dims,
914
+ {dims[d]: LevelFormat.BATCH for d in range(batch_dim)}
915
+ | {
916
+ dims[batch_dim] // m: LevelFormat.DENSE,
917
+ dims[batch_dim + 1] // n: LevelFormat.COMPRESSED,
918
+ dims[batch_dim] % m: LevelFormat.DENSE,
919
+ dims[batch_dim + 1] % n: LevelFormat.DENSE,
920
+ }
921
+ | {dims[d]: LevelFormat.DENSE for d in range(batch_dim + 2, dim)},
922
+ name=name,
923
+ )
924
+
925
+ @staticmethod
926
+ def BSCRightd(blocksize, batch_dim=0, dense_dim=0):
927
+ m, n = blocksize
928
+ dim = batch_dim + 2 + dense_dim
929
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
930
+
931
+ name = f"BSCRight{m}x{n}"
932
+ if batch_dim > 0:
933
+ name += f"-b{batch_dim}"
934
+ if dense_dim > 0:
935
+ name += f"-d{dense_dim}"
936
+
937
+ return TensorFormat(
938
+ dims,
939
+ {dims[d]: LevelFormat.BATCH for d in range(batch_dim)}
940
+ | {
941
+ dims[batch_dim + 1] // n: LevelFormat.DENSE,
942
+ dims[batch_dim] // m: LevelFormat.COMPRESSED,
943
+ dims[batch_dim] % m: LevelFormat.DENSE,
944
+ dims[batch_dim + 1] % n: LevelFormat.DENSE,
945
+ }
946
+ | {dims[d]: LevelFormat.DENSE for d in range(batch_dim + 2, dim)},
947
+ name=name,
948
+ )
949
+
950
+ @staticmethod
951
+ def CSFd(dim):
952
+ dims = [Dimension(dimension_name=f"{chr(ord('i') + d)}") for d in range(dim)]
953
+ return TensorFormat(
954
+ dims,
955
+ {dims[d]: LevelFormat.COMPRESSED for d in range(dim)},
956
+ name=f"CSF{dim}",
957
+ )