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,552 @@
1
+ # Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ This module defines drawing methods for the universal sparse tensor (UST).
7
+ """
8
+
9
+ __all__ = []
10
+
11
+ import math
12
+
13
+ import numpy as np
14
+
15
+ from ._converters import TensorDecomposer
16
+
17
+
18
+ class RequiredPackageError(Exception):
19
+ pass
20
+
21
+
22
+ WHITE = (0xFF, 0xFF, 0xFF)
23
+ BLACK = (0x00, 0x00, 0x00)
24
+ GRAY = (0xF0, 0xF0, 0xF0)
25
+ RED = (0xFF, 0x80, 0x80)
26
+ GREEN = (0x80, 0xFF, 0x80)
27
+ BLUE = (0x80, 0x80, 0xFF)
28
+ YELLOW = (0xFF, 0xFF, 0x80)
29
+ PURPLE = (0xFF, 0x08, 0xFF)
30
+
31
+
32
+ def _pos_length(tensor, i):
33
+ if tensor.pos(i) is not None:
34
+ return tensor.pos(i).size
35
+ return 0
36
+
37
+
38
+ def _crd_length(tensor, i):
39
+ if tensor.crd(i) is not None:
40
+ return tensor.crd(i).size
41
+ return 0
42
+
43
+
44
+ def _max_length(tensor):
45
+ length = tensor.nse
46
+ for i in range(tensor.num_levels):
47
+ length = max(length, _pos_length(tensor, i))
48
+ length = max(length, _crd_length(tensor, i))
49
+ return length
50
+
51
+
52
+ def _scale_font(txt, w):
53
+ try:
54
+ from PIL import ImageFont # type: ignore[import-not-found]
55
+ except ImportError as e:
56
+ raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
57
+
58
+ length = len(txt)
59
+ f = max(8, w - length - 1)
60
+ off = 2 + max(0, 4 - length) * w // 4
61
+ try:
62
+ font = ImageFont.truetype("UbuntuMono-B.ttf", f)
63
+ except:
64
+ font = ImageFont.load_default(size=f)
65
+ return off, font
66
+
67
+
68
+ def draw_tensor(tensor, name=None):
69
+ """
70
+ Draws tensor contents (1D, 2D, 3D).
71
+
72
+ This method is useful to illustrate tensor contents of smaller examples.
73
+
74
+ Args:
75
+ tensor: tensor to draw
76
+ name: filename to save to if not None
77
+ Returns:
78
+ Image, can be displayed with show()
79
+ """
80
+
81
+ try:
82
+ from PIL import Image, ImageDraw, ImageFont # type: ignore[import-not-found]
83
+ except ImportError as e:
84
+ raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
85
+
86
+ if tensor.num_dimensions == 1:
87
+ M = 1
88
+ N = tensor.extents[0] # as row vector
89
+ K = 1
90
+ L1 = None
91
+ L2 = "i"
92
+ L3 = None
93
+ elif tensor.num_dimensions == 2:
94
+ M = tensor.extents[0]
95
+ N = tensor.extents[1]
96
+ K = 1
97
+ L1 = "i"
98
+ L2 = "j"
99
+ L3 = None
100
+ elif tensor.num_dimensions == 3:
101
+ M = tensor.extents[1]
102
+ N = tensor.extents[2]
103
+ K = tensor.extents[0] # i is batch, drawn horizontally
104
+ L1 = "j"
105
+ L2 = "k"
106
+ L3 = "i"
107
+ else:
108
+ raise TypeError(f"Cannot draw {tensor.num_dimensions}-dimensional tensor")
109
+
110
+ B = 8 # border
111
+ W = 32 # width unit
112
+ S = W // 4 # shadow unit
113
+ F = W // 2 # font unit
114
+ X = W + 2 * B + (S + S + N * W) * K - S
115
+ Y = W + 2 * B + S + M * W
116
+
117
+ try:
118
+ font = ImageFont.truetype("UbuntuMono-B.ttf", F)
119
+ except:
120
+ font = ImageFont.load_default(size=F)
121
+
122
+ img = Image.new("RGB", (X, Y), color=WHITE)
123
+ draw = ImageDraw.Draw(img)
124
+
125
+ def drawGrid(k):
126
+ xo = k * (N * W + S + S)
127
+ xs = B + W + xo
128
+ ys = B + W
129
+ xe = xs + N * W
130
+ ye = ys + M * W
131
+ draw.rectangle([xs + S, ys + S, xe + S, ye + S], fill=BLACK, outline=BLACK, width=1)
132
+ draw.rectangle([xs, ys, xe, ye], fill=WHITE, outline=BLACK, width=1)
133
+ x = xs
134
+ for _ in range(1, N):
135
+ x = x + W
136
+ draw.line([x, ys, x, ye], fill=BLACK, width=1)
137
+ y = ys
138
+ for _ in range(1, M):
139
+ y = y + W
140
+ draw.line([xs, y, xe, y], fill=BLACK, width=1)
141
+
142
+ def drawGridCell(i, j, k, txt, color=GRAY):
143
+ xo = k * (N * W + S + S)
144
+ xs = B + W + j * W + xo
145
+ ys = B + W + i * W
146
+ xe = xs + W
147
+ ye = ys + W
148
+ if False: # conditional cell coloring goes here
149
+ color = RED
150
+ draw.rectangle([xs, ys, xe, ye], fill=color, outline=BLACK, width=1)
151
+ off, vfont = _scale_font(txt, F)
152
+ draw.text([xs + off, ys + S], txt, fill=BLACK, font=vfont)
153
+
154
+ def visit123d(idx, val):
155
+ if len(idx) == 1:
156
+ drawGridCell(0, idx[0], 0, str(val))
157
+ elif len(idx) == 2:
158
+ drawGridCell(idx[0], idx[1], 0, str(val))
159
+ else:
160
+ drawGridCell(idx[1], idx[2], idx[0], str(val))
161
+
162
+ # Draw coordinate system.
163
+ draw.line([B, B, B + W, B + W], fill=BLACK, width=3)
164
+ if L1 is not None:
165
+ draw.text([B, B + F], L1, fill=BLACK, font=font)
166
+ for i in range(M):
167
+ draw.text([B + S, F + (i + 1) * W], str(i), fill=BLACK, font=font)
168
+ if L2 is not None:
169
+ draw.text([B + F + S, B], L2, fill=BLACK, font=font)
170
+ for i in range(N):
171
+ draw.text([F + (i + 1) * W, B + S], str(i), fill=BLACK, font=font)
172
+ if L3 is not None:
173
+ for i in range(K):
174
+ draw.text([B + W + i * (N * W + S + S), 0], f"{L3}={i}", fill=BLACK, font=font)
175
+
176
+ for k in range(K):
177
+ drawGrid(k)
178
+
179
+ TensorDecomposer(tensor, visit123d).run()
180
+
181
+ if name is not None:
182
+ img.save(name)
183
+ return img
184
+
185
+
186
+ def draw_tensor_storage(tensor, name=None):
187
+ """
188
+ Draws tensor storage (UST).
189
+
190
+ This method is useful to illustrate the UST storage of smaller examples.
191
+
192
+ Args:
193
+ tensor: tensor to draw
194
+ name: filename to save to if not None
195
+ Returns:
196
+ Image, can be displayed with show()
197
+ """
198
+
199
+ try:
200
+ from PIL import Image, ImageDraw, ImageFont # type: ignore[import-not-found]
201
+ except ImportError as e:
202
+ raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
203
+
204
+ M = tensor.num_levels * 2 + 1
205
+ N = _max_length(tensor)
206
+ B = 8 # border
207
+ W = 32 # width unit
208
+ S = W // 4 # shadow unit
209
+ F = W // 2 # font unit
210
+ X = 2 * B + N * W + S + 2 * W
211
+ Y = 2 * B + M * (W + S + S) - S
212
+
213
+ try:
214
+ font = ImageFont.truetype("UbuntuMono-B.ttf", F)
215
+ except:
216
+ font = ImageFont.load_default(size=F)
217
+
218
+ img = Image.new("RGB", (X, Y), color=WHITE)
219
+ draw = ImageDraw.Draw(img)
220
+
221
+ def drawRow(i, txt, length, color=WHITE):
222
+ xs = B
223
+ ys = B + i * (W + S + S)
224
+ draw.text([xs, ys + S], txt, fill=BLACK, font=font)
225
+ xs = xs + 2 * W
226
+ xe = xs + (S if length == 0 else length * W)
227
+ ye = ys + W
228
+ draw.rectangle([xs + S, ys + S, xe + S, ye + S], fill=BLACK, outline=BLACK, width=1)
229
+ draw.rectangle([xs, ys, xe, ye], fill=color, outline=BLACK, width=1)
230
+ for _ in range(1, length):
231
+ xs = xs + W
232
+ draw.line([xs, ys, xs, ye], fill=BLACK, width=1)
233
+
234
+ def drawRowCell(i, j, txt, color=BLACK):
235
+ xs = B + 2 * W + j * W
236
+ ys = B + i * (W + S + S)
237
+ off, vfont = _scale_font(txt, F)
238
+ if False: # conditional cell coloring goes here
239
+ draw.rectangle([xs, ys, xs + W, ys + W], fill=RED, outline=BLACK, width=1)
240
+ draw.text([xs + off, ys + S], txt, fill=color, font=vfont)
241
+
242
+ for level in range(tensor.num_levels):
243
+ p = _pos_length(tensor, level)
244
+ drawRow(2 * level, f"pos[{level}]", p)
245
+ for j in range(p):
246
+ drawRowCell(2 * level, j, str(tensor.pos(level).tensor[j].item()))
247
+ c = _crd_length(tensor, level)
248
+ drawRow(2 * level + 1, f"crd[{level}]", c)
249
+ for j in range(c):
250
+ drawRowCell(2 * level + 1, j, str(tensor.crd(level).tensor[j].item()))
251
+ drawRow(M - 1, "values", tensor.nse)
252
+ for j in range(tensor.nse):
253
+ drawRowCell(M - 1, j, str(tensor.val.tensor[j].item()))
254
+
255
+ if name is not None:
256
+ img.save(name)
257
+ return img
258
+
259
+
260
+ def draw_tensor_raw(tensor, name=None):
261
+ """
262
+ Draws tensor nonzero structure (2D, 3D).
263
+
264
+ This method scales to larger tensors.
265
+
266
+ Args:
267
+ tensor: tensor to draw
268
+ name: filename to save to if not None
269
+ Returns:
270
+ Image, can be displayed with show()
271
+ """
272
+ try:
273
+ from PIL import Image, ImageDraw, ImageFont # type: ignore[import-not-found]
274
+ except ImportError as e:
275
+ raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
276
+
277
+ if tensor.num_dimensions == 2:
278
+ m, n, k = tensor.extents[1], tensor.extents[0], 0 # X goes down
279
+ elif tensor.num_dimensions == 3:
280
+ m, n, k = tensor.extents[0], tensor.extents[2], tensor.extents[1] # Z goes up
281
+ else:
282
+ raise TypeError(f"Cannot draw raw {tensor.num_dimensions}-dimensional tensor")
283
+
284
+ S = 0
285
+ while (m >> S) > 512:
286
+ S += 1
287
+ while (n >> S) > 512:
288
+ S += 1
289
+ while (k >> S) > 512:
290
+ S += 1
291
+ X = min(m, m >> S)
292
+ Y = min(n, n >> S)
293
+ Z = min(k, k >> S)
294
+ if ((m >> S) << S) != m:
295
+ X += 1
296
+ if ((n >> S) << S) != n:
297
+ Y += 1
298
+ if ((k >> S) << S) != k:
299
+ Z += 1
300
+ F = 16
301
+
302
+ try:
303
+ font = ImageFont.truetype("UbuntuMono-B.ttf", F)
304
+ except:
305
+ font = ImageFont.load_default(size=F)
306
+
307
+ img = Image.new("RGB", (X, Y), color=WHITE)
308
+ draw = ImageDraw.Draw(img)
309
+
310
+ if tensor.num_dimensions == 2:
311
+
312
+ def visit2d(idx, val):
313
+ img.putpixel((idx[1] >> S, idx[0] >> S), BLACK)
314
+
315
+ draw.line([0, 0, X - 1, 0], fill=RED, width=1)
316
+ draw.line([0, 0, 0, Y - 1], fill=RED, width=1)
317
+ draw.line([X - 1, 0, X - 1, Y - 1], fill=RED, width=1)
318
+ draw.line([0, Y - 1, X - 1, Y - 1], fill=RED, width=1)
319
+
320
+ TensorDecomposer(tensor, visit2d).run()
321
+
322
+ draw.text([0, Y / 2], "I", fill=BLUE, font=font, stroke_width=1.2)
323
+ draw.text([X / 2, 0], "J", fill=BLUE, font=font, stroke_width=1.2)
324
+ else:
325
+ # Fixed rotation around center in X/Z plane.
326
+ XR = 0
327
+ ZR = Z
328
+
329
+ # Fixed eye for projection.
330
+ D = Z * 2
331
+
332
+ # Rotation and translation (variable).
333
+ PHI = 45
334
+ XO = X // 2
335
+ YO = Y // 2
336
+ ZO = Z // 2
337
+
338
+ def project(x, y, z):
339
+ # Translate into view.
340
+ x = x - XO
341
+ y = y - YO
342
+ z = z + ZO
343
+ # Rotate [x,z,1].
344
+ co = math.cos(PHI)
345
+ si = math.sin(PHI)
346
+ xr = co * x - si * z + ((1 - co) * XR + si * ZR)
347
+ zr = si * x + co * z + ((1 - co) * ZR - si * XR)
348
+ x = xr
349
+ y = y
350
+ z = zr
351
+ # Project (if not in plane).
352
+ if z == -D:
353
+ x = x
354
+ y = y
355
+ else:
356
+ x = x * (D / (z + D))
357
+ y = y * (D / (z + D))
358
+ # Translate back.
359
+ x = int(x + XO)
360
+ y = int(y + YO)
361
+ return x, y, 0
362
+
363
+ def line(x1, y1, z1, x2, y2, z2):
364
+ (xp1, yp1, zp) = project(x1, y1, z1)
365
+ (xp2, yp2, zp) = project(x2, y2, z2)
366
+ draw.line([xp1, Y - yp1, xp2, Y - yp2], fill=RED, width=3)
367
+
368
+ def visit3d(idx, val):
369
+ x, y, z = project(idx[0] >> S, idx[2] >> S, idx[1] >> S)
370
+ # Guarded put pixel.
371
+ if x >= 0 and x < X and y >= 0 and y < Y:
372
+ img.putpixel((x, Y - y - 1), BLACK)
373
+
374
+ line(0, 0, 0, X, 0, 0)
375
+ line(0, 0, 0, 0, 0, Z)
376
+ line(X, 0, 0, X, 0, Z)
377
+ line(0, 0, Z, X, 0, Z)
378
+ line(0, Y, 0, X, Y, 0)
379
+ line(0, Y, 0, 0, Y, Z)
380
+ line(X, Y, 0, X, Y, Z)
381
+ line(0, Y, Z, X, Y, Z)
382
+ line(0, 0, 0, 0, Y, 0)
383
+ line(X, 0, 0, X, Y, 0)
384
+ line(0, 0, Z, 0, Y, Z)
385
+ line(X, 0, Z, X, Y, Z)
386
+
387
+ TensorDecomposer(tensor, visit3d).run()
388
+
389
+ (x, y, z) = project(X / 2, 0, 0)
390
+ draw.text([x, Y - y - 1], "I", fill=BLUE, font=font, stroke_width=1.2)
391
+ (x, y, z) = project(0, 0, Z / 2)
392
+ draw.text([x, Y - y - 1], "J", fill=BLUE, font=font, stroke_width=1.2)
393
+ (x, y, z) = project(0, Y / 2, 0)
394
+ draw.text([x, Y - y - 1], "K", fill=BLUE, font=font, stroke_width=1.2)
395
+
396
+ if name is not None:
397
+ img.save(name)
398
+ return img
399
+
400
+
401
+ def animate_tensor(tensor, name=None):
402
+ """
403
+ Animates tensor nonzero structure (3D).
404
+
405
+ This method scales to larger tensors.
406
+
407
+ Args:
408
+ tensor: tensor to animate
409
+ name: filename to save to if not None
410
+ Returns:
411
+ HTML if name is None (to embed in other output)
412
+ """
413
+ try:
414
+ import matplotlib.pyplot as plt # type: ignore
415
+ from IPython.display import HTML # type: ignore
416
+ from matplotlib.animation import FuncAnimation, PillowWriter # type: ignore
417
+ except ImportError as e:
418
+ raise RequiredPackageError("Animation packages are required for visualizing UST.") from e
419
+
420
+ if tensor.num_dimensions == 3:
421
+ X, Y, Z = tensor.extents[0], tensor.extents[1], tensor.extents[2]
422
+ else:
423
+ raise TypeError(f"Cannot animate {tensor.num_dimensions}-dimensional tensor")
424
+
425
+ # Map largest to [0,1].
426
+ U = float(max(X, Y, Z))
427
+ X = X / U
428
+ Y = Y / U
429
+ Z = Z / U
430
+
431
+ points = np.empty((tensor.nse, 3), dtype=np.float32)
432
+ index = 0
433
+
434
+ def visit3d(idx, val):
435
+ nonlocal index
436
+ x, y, z = idx[0], idx[1], idx[2]
437
+ points[index, 0] = x / U
438
+ points[index, 1] = y / U
439
+ points[index, 2] = z / U
440
+ index += 1
441
+
442
+ TensorDecomposer(tensor, visit3d).run()
443
+
444
+ # Set up frame.
445
+ cube_vertices = np.array([[0, 0, 0], [X, 0, 0], [X, Y, 0], [0, Y, 0], [0, 0, Z], [X, 0, Z], [X, Y, Z], [0, Y, Z]])
446
+ cube_edges = np.array([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [1, 5], [2, 6], [3, 7]])
447
+ fig = plt.figure(figsize=(5, 5), dpi=72)
448
+ ax = fig.add_subplot(111, projection="3d")
449
+
450
+ def update(frame):
451
+ ax.cla()
452
+ ax.set_axis_off()
453
+ ax.set_xlim(0, 1)
454
+ ax.set_ylim(0, 1)
455
+ ax.set_zlim(0, 1)
456
+
457
+ # Set the animation view.
458
+ elev = 45
459
+ azim = frame * 2 # degrees per frame
460
+ ax.view_init(elev=elev, azim=azim)
461
+
462
+ # Draw cube edges in red.
463
+ for edge in cube_edges:
464
+ v = cube_vertices[edge]
465
+ ax.plot3D(v[:, 0], v[:, 1], v[:, 2], color="red", linewidth=3, alpha=1)
466
+
467
+ # Draw points.
468
+ ax.scatter(points[:, 0], points[:, 1], points[:, 2], c="black", s=0.15, alpha=0.4, depthshade=True)
469
+
470
+ # Add labels at each axis
471
+ ax.text(X / 2, 0, 0, "I", fontsize=12, fontweight="bold", color="blue")
472
+ ax.text(0, Y / 2, 0, "J", fontsize=12, fontweight="bold", color="blue")
473
+ ax.text(0, 0, Z / 2, "K", fontsize=12, fontweight="bold", color="blue")
474
+
475
+ fig.subplots_adjust(left=0, right=1, top=1, bottom=0)
476
+
477
+ anim = FuncAnimation(fig, update, frames=180, interval=50)
478
+ plt.close()
479
+
480
+ if name is not None:
481
+ anim.save(name, writer=PillowWriter(fps=20))
482
+ else:
483
+ return HTML(anim.to_html5_video())
484
+
485
+
486
+ def draw_network(tensors, name=None):
487
+ """
488
+ Draws network consisting of linear layer weight matrices.
489
+
490
+ Args:
491
+ tensor: list of tensors to draw
492
+ name: filename to save to if not None
493
+ Returns:
494
+ Image, can be displayed with show()
495
+ """
496
+
497
+ try:
498
+ from PIL import Image, ImageDraw # type: ignore[import-not-found]
499
+ except ImportError as e:
500
+ raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
501
+
502
+ CELLS = [tensor.shape[0] for tensor in tensors]
503
+ CELLS.append(tensors[-1].shape[1])
504
+ B = 8 # border
505
+ W = 32 # width unit
506
+ C1 = 4 # cell spacing start
507
+ C2 = W - C1 # cell spacing end
508
+ CO = W // 2
509
+ CL = len(CELLS)
510
+ CM = max(CELLS)
511
+ D = CM * W
512
+ X = 2 * B + D * (CL - 1) + W
513
+ Y = 2 * B + D
514
+
515
+ img = Image.new("RGB", (X, Y), color=WHITE)
516
+ draw = ImageDraw.Draw(img)
517
+
518
+ def drawCircle(i, cl, color=BLUE):
519
+ m = (CM - CELLS[cl]) / 2
520
+ x = B + cl * D
521
+ y = B + (i + m) * W
522
+ draw.ellipse((x + C1, y + C1, x + C2, y + C2), width=2, fill=color, outline=BLACK)
523
+
524
+ def drawLine(i, j, cl, color=BLACK):
525
+ m1 = (CM - CELLS[cl]) / 2
526
+ m2 = (CM - CELLS[cl + 1]) / 2
527
+ xs = B + cl * D + CO
528
+ ys = B + (i + m1) * W + CO
529
+ xe = xs + D
530
+ ye = B + (j + m2) * W + CO
531
+ draw.line([xs, ys, xe, ye], fill=color, width=1)
532
+
533
+ for cl in range(0, CL):
534
+ for i in range(0, CELLS[cl]):
535
+ drawCircle(i, cl)
536
+
537
+ for cl in range(0, CL - 1):
538
+
539
+ def visit(tensor, transposed, lvl):
540
+ def visit2d(idx, val):
541
+ if transposed:
542
+ drawLine(idx[1], idx[0], lvl)
543
+ else:
544
+ drawLine(idx[0], idx[1], lvl)
545
+
546
+ TensorDecomposer(tensor, visit2d).run()
547
+
548
+ visit(tensors[cl].ust, tensors[cl].transposed, cl)
549
+
550
+ if name is not None:
551
+ img.save(name)
552
+ return img