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.
- nvmath/__init__.pxd +0 -0
- nvmath/__init__.py +45 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/attribute_ifc_factory.py +330 -0
- nvmath/_internal/layout.py +70 -0
- nvmath/_internal/templates.py +130 -0
- nvmath/_internal/threadsafe.py +106 -0
- nvmath/_internal/utils.py +43 -0
- nvmath/_internal/workspace.py +490 -0
- nvmath/_utils.py +147 -0
- nvmath/bindings/__init__.py +60 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/common_types.pxd +31 -0
- nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +54 -0
- nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusolverMp.pxd +71 -0
- nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverSp.pxd +75 -0
- nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +471 -0
- nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +174 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +812 -0
- nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1461 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +267 -0
- nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +98 -0
- nvmath/bindings/cudss.pyi +443 -0
- nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +301 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +326 -0
- nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +189 -0
- nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +320 -0
- nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +422 -0
- nvmath/bindings/cusolverMp.pxd +98 -0
- nvmath/bindings/cusolverMp.pyi +114 -0
- nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverSp.pxd +95 -0
- nvmath/bindings/cusolverSp.pyi +70 -0
- nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +546 -0
- nvmath/bindings/cusparse.pyi +1017 -0
- nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +252 -0
- nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +324 -0
- nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +664 -0
- nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1045 -0
- nvmath/bindings/cycublasMp.pxd +171 -0
- nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +277 -0
- nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +333 -0
- nvmath/bindings/cycufftMp.pxd +342 -0
- nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +141 -0
- nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +137 -0
- nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +443 -0
- nvmath/bindings/cycusolverMp.pxd +107 -0
- nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverSp.pxd +93 -0
- nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +679 -0
- nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +135 -0
- nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +189 -0
- nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +118 -0
- nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1562 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +13 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/blas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
- nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +131 -0
- nvmath/bindings/nvpl/blas.pyi +168 -0
- nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +280 -0
- nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +93 -0
- nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +168 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +191 -0
- nvmath/device/__init__.py +38 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +315 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +300 -0
- nvmath/device/common_numba_cuda_mlir.py +202 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1606 -0
- nvmath/device/cublasdx_backend.py +860 -0
- nvmath/device/cublasdx_numba.py +1534 -0
- nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
- nvmath/device/cufftdx.py +373 -0
- nvmath/device/cufftdx_backend.py +220 -0
- nvmath/device/cufftdx_numba.py +140 -0
- nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2708 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +567 -0
- nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
- nvmath/device/cusolverdx_overload_backend.py +1029 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +441 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +138 -0
- nvmath/device/vector_types_numba.py +259 -0
- nvmath/distributed/__init__.py +200 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nccl.py +86 -0
- nvmath/distributed/_internal/nvshmem.py +307 -0
- nvmath/distributed/_internal/symmetric_memory.py +35 -0
- nvmath/distributed/_internal/tensor_ifc.py +70 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
- nvmath/distributed/_internal/tensor_wrapper.py +81 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution/__init__.py +30 -0
- nvmath/distributed/distribution/_configuration.py +39 -0
- nvmath/distributed/distribution/distributions.py +1024 -0
- nvmath/distributed/distribution/redistribute.py +1284 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +82 -0
- nvmath/distributed/fft/fft.py +2742 -0
- nvmath/distributed/linalg/__init__.py +22 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -0
- nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/distributed/linalg/advanced/__init__.py +8 -0
- nvmath/distributed/linalg/advanced/_configuration.py +171 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
- nvmath/distributed/linalg/generic/__init__.py +8 -0
- nvmath/distributed/linalg/generic/_caching.py +66 -0
- nvmath/distributed/linalg/generic/_configuration.py +61 -0
- nvmath/distributed/linalg/generic/_factorization.py +172 -0
- nvmath/distributed/linalg/generic/_initialization.py +966 -0
- nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
- nvmath/distributed/linalg/generic/solvermod.py +1368 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +189 -0
- nvmath/fft/_exec_utils.py +82 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +3122 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +18 -0
- nvmath/internal/_device_utils.py +45 -0
- nvmath/internal/_layout/__init__.pxd +3 -0
- nvmath/internal/_layout/__init__.py +7 -0
- nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_layout/_layout.pxd +1303 -0
- nvmath/internal/_layout/_layout.pyi +1145 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +13 -0
- nvmath/internal/memory.pyi +50 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +9 -0
- nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
- nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_jit.pxd +7 -0
- nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
- nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -0
- nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +242 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
- nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
- nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
- nvmath/internal/package_ifc.py +168 -0
- nvmath/internal/package_ifc_cuda.py +57 -0
- nvmath/internal/package_ifc_cupy.py +67 -0
- nvmath/internal/package_ifc_torch.py +69 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +179 -0
- nvmath/internal/tensor_ifc_cupy.py +234 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
- nvmath/internal/tensor_ifc_numpy.py +184 -0
- nvmath/internal/tensor_ifc_torch.py +178 -0
- nvmath/internal/tensor_wrapper.py +160 -0
- nvmath/internal/typemaps.py +113 -0
- nvmath/internal/utils.py +805 -0
- nvmath/linalg/__init__.py +56 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
- nvmath/linalg/_internal/algo_config_ifc.py +43 -0
- nvmath/linalg/_internal/batch.py +234 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +766 -0
- nvmath/linalg/_internal/layout.py +624 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
- nvmath/linalg/_internal/solver_utils.py +432 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +157 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +170 -0
- nvmath/linalg/advanced/_configuration.py +351 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1316 -0
- nvmath/linalg/advanced/matmulmod.py +3734 -0
- nvmath/linalg/generic/__init__.py +53 -0
- nvmath/linalg/generic/_configuration/__init__.py +39 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +734 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
- nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +2094 -0
- nvmath/linalg/generic/solvermod.py +1301 -0
- nvmath/memory.py +279 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +147 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +506 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +227 -0
- nvmath/sparse/advanced/direct_solver.py +2069 -0
- nvmath/sparse/generic/__init__.py +7 -0
- nvmath/sparse/generic/_configuration.py +129 -0
- nvmath/sparse/generic/_helpers.py +137 -0
- nvmath/sparse/generic/_thunks.py +21 -0
- nvmath/sparse/generic/matmulmod.py +2353 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +422 -0
- nvmath/sparse/ust/_cpp.py +28 -0
- nvmath/sparse/ust/_drawer.py +565 -0
- nvmath/sparse/ust/_emitter.py +1033 -0
- nvmath/sparse/ust/_jit.py +188 -0
- nvmath/sparse/ust/_kernel.py +282 -0
- nvmath/sparse/ust/_utils.py +149 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/tensor.py +1016 -0
- nvmath/sparse/ust/tensor_format.py +957 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +120 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
- nvmath/tensor/_internal/cutensor_utils.py +230 -0
- nvmath/tensor/_internal/data.py +43 -0
- nvmath/tensor/_internal/einsum_parser.py +444 -0
- nvmath/tensor/_internal/typemaps.py +96 -0
- nvmath/tensor/contract.py +1900 -0
- nvmath_python-1.0.0.dist-info/METADATA +134 -0
- nvmath_python-1.0.0.dist-info/RECORD +332 -0
- nvmath_python-1.0.0.dist-info/WHEEL +5 -0
- nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-1.0.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,565 @@
|
|
|
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
|
+
from ._utils import resolve_stream
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RequiredPackageError(Exception):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
WHITE = (0xFF, 0xFF, 0xFF)
|
|
24
|
+
BLACK = (0x00, 0x00, 0x00)
|
|
25
|
+
GRAY = (0xF0, 0xF0, 0xF0)
|
|
26
|
+
RED = (0xFF, 0x80, 0x80)
|
|
27
|
+
GREEN = (0x80, 0xFF, 0x80)
|
|
28
|
+
BLUE = (0x80, 0x80, 0xFF)
|
|
29
|
+
YELLOW = (0xFF, 0xFF, 0x80)
|
|
30
|
+
PURPLE = (0xFF, 0x08, 0xFF)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _pos_length(tensor, i):
|
|
34
|
+
pos = tensor._pos.get(i)
|
|
35
|
+
if pos is not None:
|
|
36
|
+
return pos.size
|
|
37
|
+
return 0
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _crd_length(tensor, i):
|
|
41
|
+
crd = tensor._crd.get(i)
|
|
42
|
+
if crd is not None:
|
|
43
|
+
return crd.size
|
|
44
|
+
return 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _max_length(tensor):
|
|
48
|
+
length = tensor.nse
|
|
49
|
+
for i in range(tensor.num_levels):
|
|
50
|
+
length = max(length, _pos_length(tensor, i))
|
|
51
|
+
length = max(length, _crd_length(tensor, i))
|
|
52
|
+
return length
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _scale_font(txt, w):
|
|
56
|
+
try:
|
|
57
|
+
from PIL import ImageFont # type: ignore[import-not-found]
|
|
58
|
+
except ImportError as e:
|
|
59
|
+
raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
|
|
60
|
+
|
|
61
|
+
length = len(txt)
|
|
62
|
+
f = max(8, w - length - 1)
|
|
63
|
+
off = 2 + max(0, 4 - length) * w // 4
|
|
64
|
+
try:
|
|
65
|
+
font = ImageFont.truetype("UbuntuMono-B.ttf", f)
|
|
66
|
+
except:
|
|
67
|
+
font = ImageFont.load_default(size=f)
|
|
68
|
+
return off, font
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def draw_tensor(tensor, name=None, stream=None):
|
|
72
|
+
"""
|
|
73
|
+
Draws tensor contents (1D, 2D, 3D).
|
|
74
|
+
|
|
75
|
+
This method is useful to illustrate tensor contents of smaller examples.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
tensor: tensor to draw
|
|
79
|
+
name: filename to save to if not None
|
|
80
|
+
stream: the stream used to order any access to GPU-resident data
|
|
81
|
+
Returns:
|
|
82
|
+
Image, can be displayed with show()
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
from PIL import Image, ImageDraw, ImageFont # type: ignore[import-not-found]
|
|
87
|
+
except ImportError as e:
|
|
88
|
+
raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
|
|
89
|
+
|
|
90
|
+
if tensor.num_dimensions == 1:
|
|
91
|
+
M = 1
|
|
92
|
+
N = tensor.extents[0] # as row vector
|
|
93
|
+
K = 1
|
|
94
|
+
L1 = None
|
|
95
|
+
L2 = "i"
|
|
96
|
+
L3 = None
|
|
97
|
+
elif tensor.num_dimensions == 2:
|
|
98
|
+
M = tensor.extents[0]
|
|
99
|
+
N = tensor.extents[1]
|
|
100
|
+
K = 1
|
|
101
|
+
L1 = "i"
|
|
102
|
+
L2 = "j"
|
|
103
|
+
L3 = None
|
|
104
|
+
elif tensor.num_dimensions == 3:
|
|
105
|
+
M = tensor.extents[1]
|
|
106
|
+
N = tensor.extents[2]
|
|
107
|
+
K = tensor.extents[0] # i is batch, drawn horizontally
|
|
108
|
+
L1 = "j"
|
|
109
|
+
L2 = "k"
|
|
110
|
+
L3 = "i"
|
|
111
|
+
else:
|
|
112
|
+
raise TypeError(f"Cannot draw {tensor.num_dimensions}-dimensional tensor")
|
|
113
|
+
|
|
114
|
+
B = 8 # border
|
|
115
|
+
W = 32 # width unit
|
|
116
|
+
S = W // 4 # shadow unit
|
|
117
|
+
F = W // 2 # font unit
|
|
118
|
+
X = W + 2 * B + (S + S + N * W) * K - S
|
|
119
|
+
Y = W + 2 * B + S + M * W
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
font = ImageFont.truetype("UbuntuMono-B.ttf", F)
|
|
123
|
+
except:
|
|
124
|
+
font = ImageFont.load_default(size=F)
|
|
125
|
+
|
|
126
|
+
img = Image.new("RGB", (X, Y), color=WHITE)
|
|
127
|
+
draw = ImageDraw.Draw(img)
|
|
128
|
+
|
|
129
|
+
def drawGrid(k):
|
|
130
|
+
xo = k * (N * W + S + S)
|
|
131
|
+
xs = B + W + xo
|
|
132
|
+
ys = B + W
|
|
133
|
+
xe = xs + N * W
|
|
134
|
+
ye = ys + M * W
|
|
135
|
+
draw.rectangle([xs + S, ys + S, xe + S, ye + S], fill=BLACK, outline=BLACK, width=1)
|
|
136
|
+
draw.rectangle([xs, ys, xe, ye], fill=WHITE, outline=BLACK, width=1)
|
|
137
|
+
x = xs
|
|
138
|
+
for _ in range(1, N):
|
|
139
|
+
x = x + W
|
|
140
|
+
draw.line([x, ys, x, ye], fill=BLACK, width=1)
|
|
141
|
+
y = ys
|
|
142
|
+
for _ in range(1, M):
|
|
143
|
+
y = y + W
|
|
144
|
+
draw.line([xs, y, xe, y], fill=BLACK, width=1)
|
|
145
|
+
|
|
146
|
+
def drawGridCell(i, j, k, txt, color=GRAY):
|
|
147
|
+
xo = k * (N * W + S + S)
|
|
148
|
+
xs = B + W + j * W + xo
|
|
149
|
+
ys = B + W + i * W
|
|
150
|
+
xe = xs + W
|
|
151
|
+
ye = ys + W
|
|
152
|
+
if False: # conditional cell coloring goes here
|
|
153
|
+
color = RED
|
|
154
|
+
draw.rectangle([xs, ys, xe, ye], fill=color, outline=BLACK, width=1)
|
|
155
|
+
off, vfont = _scale_font(txt, F)
|
|
156
|
+
draw.text([xs + off, ys + S], txt, fill=BLACK, font=vfont)
|
|
157
|
+
|
|
158
|
+
def visit123d(idx, val):
|
|
159
|
+
if len(idx) == 1:
|
|
160
|
+
drawGridCell(0, idx[0], 0, str(val))
|
|
161
|
+
elif len(idx) == 2:
|
|
162
|
+
drawGridCell(idx[0], idx[1], 0, str(val))
|
|
163
|
+
else:
|
|
164
|
+
drawGridCell(idx[1], idx[2], idx[0], str(val))
|
|
165
|
+
|
|
166
|
+
# Draw coordinate system.
|
|
167
|
+
draw.line([B, B, B + W, B + W], fill=BLACK, width=3)
|
|
168
|
+
if L1 is not None:
|
|
169
|
+
draw.text([B, B + F], L1, fill=BLACK, font=font)
|
|
170
|
+
for i in range(M):
|
|
171
|
+
draw.text([B + S, F + (i + 1) * W], str(i), fill=BLACK, font=font)
|
|
172
|
+
if L2 is not None:
|
|
173
|
+
draw.text([B + F + S, B], L2, fill=BLACK, font=font)
|
|
174
|
+
for i in range(N):
|
|
175
|
+
draw.text([F + (i + 1) * W, B + S], str(i), fill=BLACK, font=font)
|
|
176
|
+
if L3 is not None:
|
|
177
|
+
for i in range(K):
|
|
178
|
+
draw.text([B + W + i * (N * W + S + S), 0], f"{L3}={i}", fill=BLACK, font=font)
|
|
179
|
+
|
|
180
|
+
for k in range(K):
|
|
181
|
+
drawGrid(k)
|
|
182
|
+
|
|
183
|
+
TensorDecomposer(tensor, visit123d).run(stream=stream)
|
|
184
|
+
|
|
185
|
+
if name is not None:
|
|
186
|
+
img.save(name)
|
|
187
|
+
return img
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def draw_tensor_storage(tensor, name=None, stream=None):
|
|
191
|
+
"""
|
|
192
|
+
Draws tensor storage (UST).
|
|
193
|
+
|
|
194
|
+
This method is useful to illustrate the UST storage of smaller examples.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
tensor: tensor to draw
|
|
198
|
+
name: filename to save to if not None
|
|
199
|
+
stream: the stream used to order any access to GPU-resident data
|
|
200
|
+
Returns:
|
|
201
|
+
Image, can be displayed with show()
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
from PIL import Image, ImageDraw, ImageFont # type: ignore[import-not-found]
|
|
206
|
+
except ImportError as e:
|
|
207
|
+
raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
|
|
208
|
+
|
|
209
|
+
# This method indexes single elements of the pos/crd/val arrays, so for
|
|
210
|
+
# GPU-resident data we copy to the host first (ordered on the provided stream).
|
|
211
|
+
if tensor.device_id != "cpu":
|
|
212
|
+
stream_holder = resolve_stream(stream, tensor)
|
|
213
|
+
tensor = tensor._to("cpu", stream_holder)
|
|
214
|
+
|
|
215
|
+
M = tensor.num_levels * 2 + 1
|
|
216
|
+
N = _max_length(tensor)
|
|
217
|
+
B = 8 # border
|
|
218
|
+
W = 32 # width unit
|
|
219
|
+
S = W // 4 # shadow unit
|
|
220
|
+
F = W // 2 # font unit
|
|
221
|
+
X = 2 * B + N * W + S + 2 * W
|
|
222
|
+
Y = 2 * B + M * (W + S + S) - S
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
font = ImageFont.truetype("UbuntuMono-B.ttf", F)
|
|
226
|
+
except:
|
|
227
|
+
font = ImageFont.load_default(size=F)
|
|
228
|
+
|
|
229
|
+
img = Image.new("RGB", (X, Y), color=WHITE)
|
|
230
|
+
draw = ImageDraw.Draw(img)
|
|
231
|
+
|
|
232
|
+
def drawRow(i, txt, length, color=WHITE):
|
|
233
|
+
xs = B
|
|
234
|
+
ys = B + i * (W + S + S)
|
|
235
|
+
draw.text([xs, ys + S], txt, fill=BLACK, font=font)
|
|
236
|
+
xs = xs + 2 * W
|
|
237
|
+
xe = xs + (S if length == 0 else length * W)
|
|
238
|
+
ye = ys + W
|
|
239
|
+
draw.rectangle([xs + S, ys + S, xe + S, ye + S], fill=BLACK, outline=BLACK, width=1)
|
|
240
|
+
draw.rectangle([xs, ys, xe, ye], fill=color, outline=BLACK, width=1)
|
|
241
|
+
for _ in range(1, length):
|
|
242
|
+
xs = xs + W
|
|
243
|
+
draw.line([xs, ys, xs, ye], fill=BLACK, width=1)
|
|
244
|
+
|
|
245
|
+
def drawRowCell(i, j, txt, color=BLACK):
|
|
246
|
+
xs = B + 2 * W + j * W
|
|
247
|
+
ys = B + i * (W + S + S)
|
|
248
|
+
off, vfont = _scale_font(txt, F)
|
|
249
|
+
if False: # conditional cell coloring goes here
|
|
250
|
+
draw.rectangle([xs, ys, xs + W, ys + W], fill=RED, outline=BLACK, width=1)
|
|
251
|
+
draw.text([xs + off, ys + S], txt, fill=color, font=vfont)
|
|
252
|
+
|
|
253
|
+
for level in range(tensor.num_levels):
|
|
254
|
+
p = _pos_length(tensor, level)
|
|
255
|
+
drawRow(2 * level, f"pos[{level}]", p)
|
|
256
|
+
for j in range(p):
|
|
257
|
+
drawRowCell(2 * level, j, str(tensor._pos[level].tensor[j].item()))
|
|
258
|
+
c = _crd_length(tensor, level)
|
|
259
|
+
drawRow(2 * level + 1, f"crd[{level}]", c)
|
|
260
|
+
for j in range(c):
|
|
261
|
+
drawRowCell(2 * level + 1, j, str(tensor._crd[level].tensor[j].item()))
|
|
262
|
+
drawRow(M - 1, "values", tensor.nse)
|
|
263
|
+
for j in range(tensor.nse):
|
|
264
|
+
drawRowCell(M - 1, j, str(tensor._val.tensor[j].item()))
|
|
265
|
+
|
|
266
|
+
if name is not None:
|
|
267
|
+
img.save(name)
|
|
268
|
+
return img
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def draw_tensor_raw(tensor, name=None, stream=None):
|
|
272
|
+
"""
|
|
273
|
+
Draws tensor nonzero structure (2D, 3D).
|
|
274
|
+
|
|
275
|
+
This method scales to larger tensors.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
tensor: tensor to draw
|
|
279
|
+
name: filename to save to if not None
|
|
280
|
+
stream: the stream used to order any access to GPU-resident data
|
|
281
|
+
Returns:
|
|
282
|
+
Image, can be displayed with show()
|
|
283
|
+
"""
|
|
284
|
+
try:
|
|
285
|
+
from PIL import Image, ImageDraw, ImageFont # type: ignore[import-not-found]
|
|
286
|
+
except ImportError as e:
|
|
287
|
+
raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
|
|
288
|
+
|
|
289
|
+
if tensor.num_dimensions == 2:
|
|
290
|
+
m, n, k = tensor.extents[1], tensor.extents[0], 0 # X goes down
|
|
291
|
+
elif tensor.num_dimensions == 3:
|
|
292
|
+
m, n, k = tensor.extents[0], tensor.extents[2], tensor.extents[1] # Z goes up
|
|
293
|
+
else:
|
|
294
|
+
raise TypeError(f"Cannot draw raw {tensor.num_dimensions}-dimensional tensor")
|
|
295
|
+
|
|
296
|
+
S = 0
|
|
297
|
+
while (m >> S) > 512:
|
|
298
|
+
S += 1
|
|
299
|
+
while (n >> S) > 512:
|
|
300
|
+
S += 1
|
|
301
|
+
while (k >> S) > 512:
|
|
302
|
+
S += 1
|
|
303
|
+
X = min(m, m >> S)
|
|
304
|
+
Y = min(n, n >> S)
|
|
305
|
+
Z = min(k, k >> S)
|
|
306
|
+
if ((m >> S) << S) != m:
|
|
307
|
+
X += 1
|
|
308
|
+
if ((n >> S) << S) != n:
|
|
309
|
+
Y += 1
|
|
310
|
+
if ((k >> S) << S) != k:
|
|
311
|
+
Z += 1
|
|
312
|
+
F = 16
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
font = ImageFont.truetype("UbuntuMono-B.ttf", F)
|
|
316
|
+
except:
|
|
317
|
+
font = ImageFont.load_default(size=F)
|
|
318
|
+
|
|
319
|
+
img = Image.new("RGB", (X, Y), color=WHITE)
|
|
320
|
+
draw = ImageDraw.Draw(img)
|
|
321
|
+
|
|
322
|
+
if tensor.num_dimensions == 2:
|
|
323
|
+
|
|
324
|
+
def visit2d(idx, val):
|
|
325
|
+
img.putpixel((idx[1] >> S, idx[0] >> S), BLACK)
|
|
326
|
+
|
|
327
|
+
draw.line([0, 0, X - 1, 0], fill=RED, width=1)
|
|
328
|
+
draw.line([0, 0, 0, Y - 1], fill=RED, width=1)
|
|
329
|
+
draw.line([X - 1, 0, X - 1, Y - 1], fill=RED, width=1)
|
|
330
|
+
draw.line([0, Y - 1, X - 1, Y - 1], fill=RED, width=1)
|
|
331
|
+
|
|
332
|
+
TensorDecomposer(tensor, visit2d).run(stream=stream)
|
|
333
|
+
|
|
334
|
+
draw.text([0, Y / 2], "I", fill=BLUE, font=font, stroke_width=1.2)
|
|
335
|
+
draw.text([X / 2, 0], "J", fill=BLUE, font=font, stroke_width=1.2)
|
|
336
|
+
else:
|
|
337
|
+
# Fixed rotation around center in X/Z plane.
|
|
338
|
+
XR = 0
|
|
339
|
+
ZR = Z
|
|
340
|
+
|
|
341
|
+
# Fixed eye for projection.
|
|
342
|
+
D = Z * 2
|
|
343
|
+
|
|
344
|
+
# Rotation and translation (variable).
|
|
345
|
+
PHI = 45
|
|
346
|
+
XO = X // 2
|
|
347
|
+
YO = Y // 2
|
|
348
|
+
ZO = Z // 2
|
|
349
|
+
|
|
350
|
+
def project(x, y, z):
|
|
351
|
+
# Translate into view.
|
|
352
|
+
x = x - XO
|
|
353
|
+
y = y - YO
|
|
354
|
+
z = z + ZO
|
|
355
|
+
# Rotate [x,z,1].
|
|
356
|
+
co = math.cos(PHI)
|
|
357
|
+
si = math.sin(PHI)
|
|
358
|
+
xr = co * x - si * z + ((1 - co) * XR + si * ZR)
|
|
359
|
+
zr = si * x + co * z + ((1 - co) * ZR - si * XR)
|
|
360
|
+
x = xr
|
|
361
|
+
y = y
|
|
362
|
+
z = zr
|
|
363
|
+
# Project (if not in plane).
|
|
364
|
+
if z == -D:
|
|
365
|
+
x = x
|
|
366
|
+
y = y
|
|
367
|
+
else:
|
|
368
|
+
x = x * (D / (z + D))
|
|
369
|
+
y = y * (D / (z + D))
|
|
370
|
+
# Translate back.
|
|
371
|
+
x = int(x + XO)
|
|
372
|
+
y = int(y + YO)
|
|
373
|
+
return x, y, 0
|
|
374
|
+
|
|
375
|
+
def line(x1, y1, z1, x2, y2, z2):
|
|
376
|
+
(xp1, yp1, zp) = project(x1, y1, z1)
|
|
377
|
+
(xp2, yp2, zp) = project(x2, y2, z2)
|
|
378
|
+
draw.line([xp1, Y - yp1, xp2, Y - yp2], fill=RED, width=3)
|
|
379
|
+
|
|
380
|
+
def visit3d(idx, val):
|
|
381
|
+
x, y, z = project(idx[0] >> S, idx[2] >> S, idx[1] >> S)
|
|
382
|
+
# Guarded put pixel.
|
|
383
|
+
if x >= 0 and x < X and y >= 0 and y < Y:
|
|
384
|
+
img.putpixel((x, Y - y - 1), BLACK)
|
|
385
|
+
|
|
386
|
+
line(0, 0, 0, X, 0, 0)
|
|
387
|
+
line(0, 0, 0, 0, 0, Z)
|
|
388
|
+
line(X, 0, 0, X, 0, Z)
|
|
389
|
+
line(0, 0, Z, X, 0, Z)
|
|
390
|
+
line(0, Y, 0, X, Y, 0)
|
|
391
|
+
line(0, Y, 0, 0, Y, Z)
|
|
392
|
+
line(X, Y, 0, X, Y, Z)
|
|
393
|
+
line(0, Y, Z, X, Y, Z)
|
|
394
|
+
line(0, 0, 0, 0, Y, 0)
|
|
395
|
+
line(X, 0, 0, X, Y, 0)
|
|
396
|
+
line(0, 0, Z, 0, Y, Z)
|
|
397
|
+
line(X, 0, Z, X, Y, Z)
|
|
398
|
+
|
|
399
|
+
TensorDecomposer(tensor, visit3d).run(stream=stream)
|
|
400
|
+
|
|
401
|
+
(x, y, z) = project(X / 2, 0, 0)
|
|
402
|
+
draw.text([x, Y - y - 1], "I", fill=BLUE, font=font, stroke_width=1.2)
|
|
403
|
+
(x, y, z) = project(0, 0, Z / 2)
|
|
404
|
+
draw.text([x, Y - y - 1], "J", fill=BLUE, font=font, stroke_width=1.2)
|
|
405
|
+
(x, y, z) = project(0, Y / 2, 0)
|
|
406
|
+
draw.text([x, Y - y - 1], "K", fill=BLUE, font=font, stroke_width=1.2)
|
|
407
|
+
|
|
408
|
+
if name is not None:
|
|
409
|
+
img.save(name)
|
|
410
|
+
return img
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def animate_tensor(tensor, name=None, stream=None):
|
|
414
|
+
"""
|
|
415
|
+
Animates tensor nonzero structure (3D).
|
|
416
|
+
|
|
417
|
+
This method scales to larger tensors.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
tensor: tensor to animate
|
|
421
|
+
name: filename to save to if not None
|
|
422
|
+
stream: the stream used to order any access to GPU-resident data
|
|
423
|
+
Returns:
|
|
424
|
+
HTML if name is None (to embed in other output)
|
|
425
|
+
"""
|
|
426
|
+
try:
|
|
427
|
+
import matplotlib.pyplot as plt # type: ignore
|
|
428
|
+
from IPython.display import HTML # type: ignore
|
|
429
|
+
from matplotlib.animation import FuncAnimation, PillowWriter # type: ignore
|
|
430
|
+
except ImportError as e:
|
|
431
|
+
raise RequiredPackageError("Animation packages are required for visualizing UST.") from e
|
|
432
|
+
|
|
433
|
+
if tensor.num_dimensions == 3:
|
|
434
|
+
X, Y, Z = tensor.extents[0], tensor.extents[1], tensor.extents[2]
|
|
435
|
+
else:
|
|
436
|
+
raise TypeError(f"Cannot animate {tensor.num_dimensions}-dimensional tensor")
|
|
437
|
+
|
|
438
|
+
# Map largest to [0,1].
|
|
439
|
+
U = float(max(X, Y, Z))
|
|
440
|
+
X = X / U
|
|
441
|
+
Y = Y / U
|
|
442
|
+
Z = Z / U
|
|
443
|
+
|
|
444
|
+
points = np.empty((tensor.nse, 3), dtype=np.float32)
|
|
445
|
+
index = 0
|
|
446
|
+
|
|
447
|
+
def visit3d(idx, val):
|
|
448
|
+
nonlocal index
|
|
449
|
+
x, y, z = idx[0], idx[1], idx[2]
|
|
450
|
+
points[index, 0] = x / U
|
|
451
|
+
points[index, 1] = y / U
|
|
452
|
+
points[index, 2] = z / U
|
|
453
|
+
index += 1
|
|
454
|
+
|
|
455
|
+
TensorDecomposer(tensor, visit3d).run(stream=stream)
|
|
456
|
+
|
|
457
|
+
# Set up frame.
|
|
458
|
+
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]])
|
|
459
|
+
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]])
|
|
460
|
+
fig = plt.figure(figsize=(5, 5), dpi=72)
|
|
461
|
+
ax = fig.add_subplot(111, projection="3d")
|
|
462
|
+
|
|
463
|
+
def update(frame):
|
|
464
|
+
ax.cla()
|
|
465
|
+
ax.set_axis_off()
|
|
466
|
+
ax.set_xlim(0, 1)
|
|
467
|
+
ax.set_ylim(0, 1)
|
|
468
|
+
ax.set_zlim(0, 1)
|
|
469
|
+
|
|
470
|
+
# Set the animation view.
|
|
471
|
+
elev = 45
|
|
472
|
+
azim = frame * 2 # degrees per frame
|
|
473
|
+
ax.view_init(elev=elev, azim=azim)
|
|
474
|
+
|
|
475
|
+
# Draw cube edges in red.
|
|
476
|
+
for edge in cube_edges:
|
|
477
|
+
v = cube_vertices[edge]
|
|
478
|
+
ax.plot3D(v[:, 0], v[:, 1], v[:, 2], color="red", linewidth=3, alpha=1)
|
|
479
|
+
|
|
480
|
+
# Draw points.
|
|
481
|
+
ax.scatter(points[:, 0], points[:, 1], points[:, 2], c="black", s=0.15, alpha=0.4, depthshade=True)
|
|
482
|
+
|
|
483
|
+
# Add labels at each axis
|
|
484
|
+
ax.text(X / 2, 0, 0, "I", fontsize=12, fontweight="bold", color="blue")
|
|
485
|
+
ax.text(0, Y / 2, 0, "J", fontsize=12, fontweight="bold", color="blue")
|
|
486
|
+
ax.text(0, 0, Z / 2, "K", fontsize=12, fontweight="bold", color="blue")
|
|
487
|
+
|
|
488
|
+
fig.subplots_adjust(left=0, right=1, top=1, bottom=0)
|
|
489
|
+
|
|
490
|
+
anim = FuncAnimation(fig, update, frames=180, interval=50)
|
|
491
|
+
plt.close()
|
|
492
|
+
|
|
493
|
+
if name is not None:
|
|
494
|
+
anim.save(name, writer=PillowWriter(fps=20))
|
|
495
|
+
else:
|
|
496
|
+
return HTML(anim.to_html5_video())
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def draw_network(tensors, name=None):
|
|
500
|
+
"""
|
|
501
|
+
Draws network consisting of linear layer weight matrices.
|
|
502
|
+
|
|
503
|
+
Args:
|
|
504
|
+
tensor: list of tensors to draw
|
|
505
|
+
name: filename to save to if not None
|
|
506
|
+
Returns:
|
|
507
|
+
Image, can be displayed with show()
|
|
508
|
+
"""
|
|
509
|
+
|
|
510
|
+
try:
|
|
511
|
+
from PIL import Image, ImageDraw # type: ignore[import-not-found]
|
|
512
|
+
except ImportError as e:
|
|
513
|
+
raise RequiredPackageError("The PIL package is required for visualizing UST.") from e
|
|
514
|
+
|
|
515
|
+
CELLS = [tensor.shape[0] for tensor in tensors]
|
|
516
|
+
CELLS.append(tensors[-1].shape[1])
|
|
517
|
+
B = 8 # border
|
|
518
|
+
W = 32 # width unit
|
|
519
|
+
C1 = 4 # cell spacing start
|
|
520
|
+
C2 = W - C1 # cell spacing end
|
|
521
|
+
CO = W // 2
|
|
522
|
+
CL = len(CELLS)
|
|
523
|
+
CM = max(CELLS)
|
|
524
|
+
D = CM * W
|
|
525
|
+
X = 2 * B + D * (CL - 1) + W
|
|
526
|
+
Y = 2 * B + D
|
|
527
|
+
|
|
528
|
+
img = Image.new("RGB", (X, Y), color=WHITE)
|
|
529
|
+
draw = ImageDraw.Draw(img)
|
|
530
|
+
|
|
531
|
+
def drawCircle(i, cl, color=BLUE):
|
|
532
|
+
m = (CM - CELLS[cl]) / 2
|
|
533
|
+
x = B + cl * D
|
|
534
|
+
y = B + (i + m) * W
|
|
535
|
+
draw.ellipse((x + C1, y + C1, x + C2, y + C2), width=2, fill=color, outline=BLACK)
|
|
536
|
+
|
|
537
|
+
def drawLine(i, j, cl, color=BLACK):
|
|
538
|
+
m1 = (CM - CELLS[cl]) / 2
|
|
539
|
+
m2 = (CM - CELLS[cl + 1]) / 2
|
|
540
|
+
xs = B + cl * D + CO
|
|
541
|
+
ys = B + (i + m1) * W + CO
|
|
542
|
+
xe = xs + D
|
|
543
|
+
ye = B + (j + m2) * W + CO
|
|
544
|
+
draw.line([xs, ys, xe, ye], fill=color, width=1)
|
|
545
|
+
|
|
546
|
+
for cl in range(0, CL):
|
|
547
|
+
for i in range(0, CELLS[cl]):
|
|
548
|
+
drawCircle(i, cl)
|
|
549
|
+
|
|
550
|
+
for cl in range(0, CL - 1):
|
|
551
|
+
|
|
552
|
+
def visit(tensor, transposed, lvl):
|
|
553
|
+
def visit2d(idx, val):
|
|
554
|
+
if transposed:
|
|
555
|
+
drawLine(idx[1], idx[0], lvl)
|
|
556
|
+
else:
|
|
557
|
+
drawLine(idx[0], idx[1], lvl)
|
|
558
|
+
|
|
559
|
+
TensorDecomposer(tensor, visit2d).run()
|
|
560
|
+
|
|
561
|
+
visit(tensors[cl].ust, tensors[cl].transposed, cl)
|
|
562
|
+
|
|
563
|
+
if name is not None:
|
|
564
|
+
img.save(name)
|
|
565
|
+
return img
|