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.
- 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 +383 -0
- nvmath/_utils.py +150 -0
- nvmath/bindings/__init__.py +51 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +47 -0
- nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +277 -0
- nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +179 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +746 -0
- nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1337 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +219 -0
- nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +86 -0
- nvmath/bindings/cudss.pyi +282 -0
- nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +241 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +260 -0
- nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +159 -0
- nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +242 -0
- nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +416 -0
- nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +338 -0
- nvmath/bindings/cusparse.pyi +659 -0
- nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +198 -0
- nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +294 -0
- nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +684 -0
- nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1055 -0
- nvmath/bindings/cycublasMp.pxd +183 -0
- nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +224 -0
- nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +326 -0
- nvmath/bindings/cycufftMp.pxd +334 -0
- nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +146 -0
- nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +154 -0
- nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +446 -0
- nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +470 -0
- nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +150 -0
- nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +192 -0
- nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +126 -0
- nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1244 -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.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
- nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +85 -0
- nvmath/bindings/nvpl/blas.pyi +122 -0
- nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +166 -0
- nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +92 -0
- nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +100 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +179 -0
- nvmath/device/__init__.py +21 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +313 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +310 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1805 -0
- nvmath/device/cublasdx_backend.py +807 -0
- nvmath/device/cublasdx_numba.py +1612 -0
- nvmath/device/cufftdx.py +510 -0
- nvmath/device/cufftdx_backend.py +196 -0
- nvmath/device/cufftdx_numba.py +196 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2690 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +1624 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +445 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +147 -0
- nvmath/device/vector_types_numba.py +203 -0
- nvmath/distributed/__init__.py +205 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nvshmem.py +302 -0
- nvmath/distributed/_internal/tensor_ifc.py +67 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
- nvmath/distributed/_internal/tensor_wrapper.py +78 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution.py +770 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +79 -0
- nvmath/distributed/fft/fft.py +2801 -0
- nvmath/distributed/linalg/__init__.py +12 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -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 +166 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/distributed/reshape/__init__.py +6 -0
- nvmath/distributed/reshape/_configuration.py +39 -0
- nvmath/distributed/reshape/reshape.py +1256 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +208 -0
- nvmath/fft/_exec_utils.py +109 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +2903 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +12 -0
- nvmath/internal/_device_utils.py +54 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +10 -0
- nvmath/internal/memory.pyi +46 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +7 -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 +240 -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/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
- nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
- nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/data_layout.pxd +72 -0
- nvmath/internal/ndbuffer/data_layout.pyi +23 -0
- nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/jit.pxd +7 -0
- nvmath/internal/ndbuffer/jit.pyi +6 -0
- nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
- nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
- nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/package_utils.pxd +11 -0
- nvmath/internal/ndbuffer/package_utils.pyi +12 -0
- nvmath/internal/package_ifc.py +147 -0
- nvmath/internal/package_ifc_cuda.py +49 -0
- nvmath/internal/package_ifc_cupy.py +49 -0
- nvmath/internal/package_ifc_torch.py +31 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +194 -0
- nvmath/internal/tensor_ifc_cupy.py +241 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
- nvmath/internal/tensor_ifc_numpy.py +183 -0
- nvmath/internal/tensor_ifc_torch.py +176 -0
- nvmath/internal/tensor_wrapper.py +157 -0
- nvmath/internal/typemaps.py +162 -0
- nvmath/internal/utils.py +771 -0
- nvmath/linalg/__init__.py +46 -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 +217 -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/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +134 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +149 -0
- nvmath/linalg/advanced/_configuration.py +349 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1348 -0
- nvmath/linalg/advanced/matmulmod.py +3937 -0
- nvmath/linalg/generic/__init__.py +43 -0
- nvmath/linalg/generic/_configuration/__init__.py +37 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +609 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +1060 -0
- nvmath/memory.py +282 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +144 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +445 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +230 -0
- nvmath/sparse/advanced/direct_solver.py +1884 -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 +2426 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +378 -0
- nvmath/sparse/ust/_drawer.py +552 -0
- nvmath/sparse/ust/_emitter.py +553 -0
- nvmath/sparse/ust/_jit.py +212 -0
- nvmath/sparse/ust/_kernel.py +346 -0
- nvmath/sparse/ust/_semiring.py +71 -0
- nvmath/sparse/ust/_utils.py +102 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/semiring_ops.py +71 -0
- nvmath/sparse/ust/tensor.py +1027 -0
- nvmath/sparse/ust/tensor_drawer.py +552 -0
- nvmath/sparse/ust/tensor_emitter.py +558 -0
- nvmath/sparse/ust/tensor_format.py +935 -0
- nvmath/sparse/ust/tensor_jit.py +212 -0
- nvmath/sparse/ust/tensor_kernel.py +348 -0
- nvmath/sparse/ust/tensor_utils.py +380 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +95 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
- nvmath/tensor/_internal/cutensor_utils.py +162 -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 +1861 -0
- nvmath_python-0.9.0.dist-info/METADATA +127 -0
- nvmath_python-0.9.0.dist-info/RECORD +309 -0
- nvmath_python-0.9.0.dist-info/WHEEL +5 -0
- nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface to seamlessly use tensors (or ndarray-like objects) from different libraries.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations # allows typehint of class methods to return the self class
|
|
10
|
+
|
|
11
|
+
from abc import ABC, abstractmethod
|
|
12
|
+
from collections.abc import Callable, Sequence
|
|
13
|
+
from types import ModuleType
|
|
14
|
+
from typing import Any, Generic, Literal, Protocol, TypeVar
|
|
15
|
+
|
|
16
|
+
from . import typemaps
|
|
17
|
+
from .ndbuffer import ndbuffer
|
|
18
|
+
from .package_ifc import StreamHolder
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AnyTensor(Protocol):
|
|
22
|
+
"""Any supported external tensor object such as NumPy, CuPy, and PyTorch arrays."""
|
|
23
|
+
|
|
24
|
+
# This empty protocol class is just a placeholder to make type checking more helpful.
|
|
25
|
+
# Since the class is empty, it doesn't assume anything is true about the implementation
|
|
26
|
+
# classes. Used to type hint any object that TensorHolder knows how to wrap.
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
A generic type for the third-party Tensor which a given TensorHolder implementation wraps
|
|
32
|
+
around.
|
|
33
|
+
"""
|
|
34
|
+
Tensor = TypeVar("Tensor")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TensorHolder(ABC, Generic[Tensor]):
|
|
38
|
+
"""
|
|
39
|
+
A simple wrapper type for tensors to make the API package-agnostic.
|
|
40
|
+
|
|
41
|
+
Methods of a TensorHolder should always return a TensorHolder instead of a Tensor (one
|
|
42
|
+
of the wrapped classes) in order to prevent implementation details from the various
|
|
43
|
+
Tensor implementations from leaking into nvmath-python.
|
|
44
|
+
|
|
45
|
+
Tensors from the user should be immediately wrapped with a TensorHolder and should
|
|
46
|
+
remain wrapped until just before returning to the user.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
name: str
|
|
50
|
+
module: ModuleType
|
|
51
|
+
name_to_dtype: dict[str, Any]
|
|
52
|
+
|
|
53
|
+
def __init__(self, tensor: Tensor):
|
|
54
|
+
self.tensor: Tensor = tensor
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def data_ptr(self) -> int:
|
|
59
|
+
raise NotImplementedError
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
@abstractmethod
|
|
63
|
+
def device(self) -> Literal["cuda"] | Literal["cpu"]:
|
|
64
|
+
"""The type of the device which stores the tensor."""
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
@abstractmethod
|
|
69
|
+
def device_id(self) -> int | Literal["cpu"]:
|
|
70
|
+
"""The device ordinal of the device storing the tensor."""
|
|
71
|
+
raise NotImplementedError
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
@abstractmethod
|
|
75
|
+
def dtype(self) -> str:
|
|
76
|
+
"""Name of the data type"""
|
|
77
|
+
raise NotImplementedError
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
@abstractmethod
|
|
81
|
+
def itemsize(self) -> int:
|
|
82
|
+
"""The size of the data type in bytes."""
|
|
83
|
+
raise NotImplementedError
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
@abstractmethod
|
|
87
|
+
def empty(cls, shape: Sequence[int], device_id: int | Literal["cpu"], **context: Any) -> TensorHolder[Tensor]:
|
|
88
|
+
"""Create an empty TensorHolder of the specified shape and data type."""
|
|
89
|
+
raise NotImplementedError
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
@abstractmethod
|
|
93
|
+
def shape(self) -> Sequence[int]:
|
|
94
|
+
"""The extent of each dimension in number of elements."""
|
|
95
|
+
raise NotImplementedError
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
@abstractmethod
|
|
99
|
+
def size(self) -> int:
|
|
100
|
+
"""The total number of elements in the tensor."""
|
|
101
|
+
raise NotImplementedError
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
@abstractmethod
|
|
105
|
+
def strides(self) -> Sequence[int]:
|
|
106
|
+
"""The stride of each dimension in number of elements."""
|
|
107
|
+
raise NotImplementedError
|
|
108
|
+
|
|
109
|
+
@abstractmethod
|
|
110
|
+
def to(self, device_id: int | Literal["cpu"], stream_holder: StreamHolder | None) -> TensorHolder:
|
|
111
|
+
"""Copy the TensorHolder to a different device.
|
|
112
|
+
|
|
113
|
+
No copy is performed if the TensorHolder is already on the requested device.
|
|
114
|
+
"""
|
|
115
|
+
raise NotImplementedError
|
|
116
|
+
|
|
117
|
+
@abstractmethod
|
|
118
|
+
def asndbuffer(self) -> ndbuffer.NDBuffer:
|
|
119
|
+
"""Wraps the package tensor as a ndbuffer.NDBuffer object."""
|
|
120
|
+
raise NotImplementedError
|
|
121
|
+
|
|
122
|
+
@abstractmethod
|
|
123
|
+
def copy_(self, src: TensorHolder, stream_holder: StreamHolder | None) -> None:
|
|
124
|
+
"""Overwrite self.tensor (in-place) with a copy of src."""
|
|
125
|
+
raise NotImplementedError
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def create_name_dtype_map(conversion_function: Callable[[str], Any], exception_type: type[Exception]) -> dict[str, Any]:
|
|
129
|
+
"""
|
|
130
|
+
Create a map between CUDA data type names and the corresponding package dtypes for
|
|
131
|
+
supported data types.
|
|
132
|
+
"""
|
|
133
|
+
names = typemaps.NAME_TO_DATA_TYPE.keys()
|
|
134
|
+
name_to_dtype = {}
|
|
135
|
+
for name in names:
|
|
136
|
+
try:
|
|
137
|
+
name_to_dtype[name] = conversion_function(name)
|
|
138
|
+
except exception_type:
|
|
139
|
+
pass
|
|
140
|
+
return name_to_dtype
|
|
141
|
+
|
|
142
|
+
@abstractmethod
|
|
143
|
+
def istensor(self) -> bool:
|
|
144
|
+
"""Return whether self.tensor is the expected type."""
|
|
145
|
+
raise NotImplementedError
|
|
146
|
+
|
|
147
|
+
@abstractmethod
|
|
148
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None) -> TensorHolder[Tensor]:
|
|
149
|
+
"""Reshapes tensor without changing its data.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
shape: a new shape compatible with the original shape.
|
|
153
|
+
|
|
154
|
+
copy (Optional[bool]): whether or not to copy the input tensor. If True, the
|
|
155
|
+
function must always copy. If False, the function must never copy. If None,
|
|
156
|
+
the function must avoid copying, if possible, and may copy otherwise.
|
|
157
|
+
"""
|
|
158
|
+
raise NotImplementedError
|
|
159
|
+
|
|
160
|
+
@abstractmethod
|
|
161
|
+
def memory_buffer(self) -> TensorHolder[Tensor]:
|
|
162
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
163
|
+
raise NotImplementedError
|
|
164
|
+
|
|
165
|
+
@abstractmethod
|
|
166
|
+
def memory_buffer_to_tensor(self, shape, strides) -> TensorHolder[Tensor]:
|
|
167
|
+
"""
|
|
168
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
169
|
+
shape and strides.
|
|
170
|
+
"""
|
|
171
|
+
raise NotImplementedError
|
|
172
|
+
|
|
173
|
+
def _broadcast_to(self, shape: Sequence[int]) -> TensorHolder[Tensor]:
|
|
174
|
+
"""Returns a view of the tensor broadcast to the desired shape.
|
|
175
|
+
|
|
176
|
+
.. deprecated:: 0.8.0
|
|
177
|
+
This method is private, and should not be used. It will be removed in the
|
|
178
|
+
future once NDBuffer supports broadcasting-aware copy.
|
|
179
|
+
|
|
180
|
+
Like reshape, but raises an error if the tensor is not broadcastable to the desired
|
|
181
|
+
shape.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
shape: a new shape compatible with the original shape.
|
|
185
|
+
"""
|
|
186
|
+
raise NotImplementedError
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def is_conjugate(self) -> bool:
|
|
190
|
+
"""Return True when self.tensor has a no-op conjugation flag enabled.
|
|
191
|
+
|
|
192
|
+
The default implementation always returns False.
|
|
193
|
+
"""
|
|
194
|
+
return False
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface to seamlessly use Cupy ndarray objects.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["CupyTensor", "HostTensor"]
|
|
10
|
+
|
|
11
|
+
from collections.abc import Sequence
|
|
12
|
+
|
|
13
|
+
import cupy
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
from nvmath.internal.memory import _MemoryPointer
|
|
17
|
+
|
|
18
|
+
from . import utils
|
|
19
|
+
from .ndbuffer import ndbuffer, package_utils
|
|
20
|
+
from .package_ifc import StreamHolder
|
|
21
|
+
from .tensor_ifc import TensorHolder
|
|
22
|
+
from .tensor_ifc_ndbuffer import NDBufferTensor
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class HostTensor(NDBufferTensor):
|
|
26
|
+
"""
|
|
27
|
+
Wraps ndbuffer with data residing on the host.
|
|
28
|
+
It serves as a host counterpart for CupyTensor.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
name = "cupy_host"
|
|
32
|
+
device_tensor_class: type["CupyTensor"] # set once CupyTensor is defined
|
|
33
|
+
|
|
34
|
+
def __init__(self, tensor):
|
|
35
|
+
super().__init__(tensor)
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def create_host_from(cls, tensor: TensorHolder, stream_holder: StreamHolder):
|
|
39
|
+
src_nd = tensor.asndbuffer()
|
|
40
|
+
# empty_like (and not empty_numpy_like) is used as we don't need
|
|
41
|
+
# full-fledged numpy array (with proper layout)
|
|
42
|
+
dst_nd = ndbuffer.empty_like(src_nd, device_id=ndbuffer.CPU_DEVICE_ID)
|
|
43
|
+
ndbuffer.copy_into(dst_nd, src_nd, stream_holder)
|
|
44
|
+
return cls(dst_nd)
|
|
45
|
+
|
|
46
|
+
def to(self, device_id, stream_holder):
|
|
47
|
+
if device_id == "cpu":
|
|
48
|
+
return self
|
|
49
|
+
elif isinstance(device_id, int):
|
|
50
|
+
return self.device_tensor_class.create_from_host(self, device_id, stream_holder)
|
|
51
|
+
else:
|
|
52
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class _CupyAllocatorAdapter:
|
|
56
|
+
def allocate(self, size, stream):
|
|
57
|
+
# we accept the stream, because the ndbuffer.empty_like
|
|
58
|
+
# passes it to the allocator, but we don't use it:
|
|
59
|
+
# cupy.cuda.alloc does not accept the stream, we make sure to set
|
|
60
|
+
# the correct current stream when calling ndbuffer.empty_like
|
|
61
|
+
alloc = cupy.cuda.alloc(size)
|
|
62
|
+
# Once we require cuda.core >= 0.5.0,
|
|
63
|
+
# use Buffer.from_handle(alloc.ptr, owner=alloc)
|
|
64
|
+
return _MemoryPointer.from_handle(alloc.ptr, alloc)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
_cupy_allocator = _CupyAllocatorAdapter()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class CupyTensor(TensorHolder[cupy.ndarray]):
|
|
71
|
+
"""
|
|
72
|
+
TensorHolder for cupy ndarrays.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
name = "cupy"
|
|
76
|
+
module = cupy
|
|
77
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(
|
|
78
|
+
conversion_function=lambda name: np.dtype(name), exception_type=TypeError
|
|
79
|
+
)
|
|
80
|
+
host_tensor_class = HostTensor
|
|
81
|
+
|
|
82
|
+
def __init__(self, tensor):
|
|
83
|
+
super().__init__(tensor)
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def data_ptr(self):
|
|
87
|
+
return self.tensor.data.ptr
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def device(self):
|
|
91
|
+
return "cuda"
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def device_id(self):
|
|
95
|
+
return self.tensor.device.id
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def dtype(self):
|
|
99
|
+
"""Name of the data type"""
|
|
100
|
+
return self.tensor.dtype.name
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def itemsize(self):
|
|
104
|
+
return self.tensor.itemsize
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def shape(self):
|
|
108
|
+
return tuple(self.tensor.shape)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def size(self):
|
|
112
|
+
return self.tensor.size
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def strides(self):
|
|
116
|
+
return tuple(stride_in_bytes // self.tensor.itemsize for stride_in_bytes in self.tensor.strides)
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def empty(
|
|
120
|
+
cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
|
|
121
|
+
):
|
|
122
|
+
"""
|
|
123
|
+
Create an empty tensor of the specified shape and data type.
|
|
124
|
+
|
|
125
|
+
Note, that the strides, if specified, MUST correspond to a dense (possibly permuted)
|
|
126
|
+
tensor, otherwise the created tensor may be corrupted.
|
|
127
|
+
"""
|
|
128
|
+
assert isinstance(device_id, int), "Internal Error: Cupy tensors must be allocated with an integer device_id."
|
|
129
|
+
dtype = CupyTensor.name_to_dtype[dtype]
|
|
130
|
+
|
|
131
|
+
# When using the strides, we need an explicit allocation (see below).
|
|
132
|
+
# If the strides are simple enough, we can still avoid this overhead.
|
|
133
|
+
order = "C"
|
|
134
|
+
if strides is not None:
|
|
135
|
+
if len(strides) == 1 and strides[0] == 1:
|
|
136
|
+
strides = None
|
|
137
|
+
elif len(strides) == 2:
|
|
138
|
+
if strides[0] == 1 and strides[1] == shape[0]:
|
|
139
|
+
strides = None
|
|
140
|
+
order = "F"
|
|
141
|
+
elif strides[0] == shape[1] and strides[1] == 1:
|
|
142
|
+
strides = None
|
|
143
|
+
|
|
144
|
+
assert isinstance(stream_holder, StreamHolder), "Internal Error: CupyTensors must be allocated on a stream."
|
|
145
|
+
with utils.device_ctx(device_id), stream_holder.ctx:
|
|
146
|
+
if strides:
|
|
147
|
+
# need an explicit allocation due to cupy/cupy#7818
|
|
148
|
+
size = dtype.itemsize
|
|
149
|
+
for s in shape:
|
|
150
|
+
size = size * s
|
|
151
|
+
ptr = cupy.cuda.alloc(size)
|
|
152
|
+
# when strides is not None, it should be of unit counts not bytes
|
|
153
|
+
strides = tuple(s * dtype.itemsize for s in strides)
|
|
154
|
+
tensor = cupy.ndarray(shape, dtype=dtype, strides=strides, memptr=ptr)
|
|
155
|
+
else:
|
|
156
|
+
tensor = cupy.ndarray(shape, dtype=dtype, order=order)
|
|
157
|
+
|
|
158
|
+
return cls(tensor)
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
def create_from_host(cls, tensor: TensorHolder, device_id: int, stream_holder: StreamHolder):
|
|
162
|
+
with utils.device_ctx(device_id), stream_holder.ctx:
|
|
163
|
+
src_nd = tensor.asndbuffer()
|
|
164
|
+
dst_nd = ndbuffer.empty_like(
|
|
165
|
+
src_nd,
|
|
166
|
+
device_id=device_id,
|
|
167
|
+
stream=stream_holder,
|
|
168
|
+
device_memory_pool=_cupy_allocator,
|
|
169
|
+
)
|
|
170
|
+
ndbuffer.copy_into(dst_nd, src_nd, stream_holder)
|
|
171
|
+
dst = cupy.ndarray(dst_nd.shape, dtype=dst_nd.dtype_name, strides=dst_nd.strides_in_bytes, memptr=dst_nd.data.owner)
|
|
172
|
+
return cls(dst)
|
|
173
|
+
|
|
174
|
+
def asndbuffer(self):
|
|
175
|
+
return package_utils.wrap_cupy_array(self.tensor)
|
|
176
|
+
|
|
177
|
+
def to(self, device_id, stream_holder):
|
|
178
|
+
if device_id == "cpu":
|
|
179
|
+
with utils.device_ctx(self.device_id):
|
|
180
|
+
return self.host_tensor_class.create_host_from(self, stream_holder)
|
|
181
|
+
elif device_id == self.device_id:
|
|
182
|
+
return self
|
|
183
|
+
elif isinstance(device_id, int):
|
|
184
|
+
raise ValueError(f"Unsupported copy between different devices {self.device_id} and {device_id}.")
|
|
185
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
186
|
+
|
|
187
|
+
def copy_(self, src, stream_holder):
|
|
188
|
+
"""
|
|
189
|
+
Inplace copy of src (copy the data from src into self).
|
|
190
|
+
"""
|
|
191
|
+
with utils.device_ctx(self.device_id):
|
|
192
|
+
ndbuffer.copy_into(self.asndbuffer(), src._broadcast_to(self.shape).asndbuffer(), stream_holder)
|
|
193
|
+
|
|
194
|
+
def istensor(self):
|
|
195
|
+
"""
|
|
196
|
+
Check if the object is ndarray-like.
|
|
197
|
+
"""
|
|
198
|
+
return isinstance(self.tensor, cupy.ndarray)
|
|
199
|
+
|
|
200
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
201
|
+
if copy:
|
|
202
|
+
raise NotImplementedError("reshape with copy=True not implemented")
|
|
203
|
+
if copy is False:
|
|
204
|
+
try:
|
|
205
|
+
reshaped_tensor = self.tensor.view()
|
|
206
|
+
reshaped_tensor.shape = shape
|
|
207
|
+
except AttributeError as e:
|
|
208
|
+
raise ValueError(
|
|
209
|
+
f"Could not reshape cupy array without copy: current shape={self.shape}, new shape={shape}"
|
|
210
|
+
) from e
|
|
211
|
+
else:
|
|
212
|
+
reshaped_tensor = self.tensor.reshape(shape)
|
|
213
|
+
return self.__class__(reshaped_tensor)
|
|
214
|
+
|
|
215
|
+
def memory_buffer(self):
|
|
216
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
217
|
+
m = cupy.cuda.UnownedMemory(self.data_ptr, self.size * self.itemsize, owner=self.tensor, device_id=self.device_id)
|
|
218
|
+
p = cupy.cuda.MemoryPointer(m, 0)
|
|
219
|
+
# TODO: ensure tensor is dense for now, and later support linear
|
|
220
|
+
# memory with constant stride.
|
|
221
|
+
t = cupy.ndarray(shape=(self.size,), dtype=self.dtype, memptr=p)
|
|
222
|
+
return CupyTensor(t)
|
|
223
|
+
|
|
224
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
225
|
+
"""
|
|
226
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
227
|
+
shape and strides.
|
|
228
|
+
"""
|
|
229
|
+
assert len(self.shape) == 1, "Internal error."
|
|
230
|
+
m = cupy.cuda.UnownedMemory(self.data_ptr, self.size * self.itemsize, owner=self.tensor)
|
|
231
|
+
p = cupy.cuda.MemoryPointer(m, 0)
|
|
232
|
+
strides = [s * self.itemsize for s in strides]
|
|
233
|
+
t = cupy.ndarray(shape=shape, dtype=self.dtype, memptr=p, strides=strides)
|
|
234
|
+
return CupyTensor(t)
|
|
235
|
+
|
|
236
|
+
def _broadcast_to(self, shape):
|
|
237
|
+
reshaped_tensor = cupy.broadcast_to(self.tensor, shape)
|
|
238
|
+
return self.__class__(reshaped_tensor)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
HostTensor.device_tensor_class = CupyTensor
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
TensorHolder implementation that adapts ndbuffer for use with
|
|
7
|
+
the tensor_ifc interface. The class is meant for internal use only
|
|
8
|
+
(e.g. for internal operands of host APIs), but the NDBufferTensor
|
|
9
|
+
or underlying ndbuffer should never be returned to the user, because
|
|
10
|
+
1. the ndbuffer is opaque, i.e. it missies most of typical tensor functionality, and
|
|
11
|
+
2. we make no guarantees about the ndbuffer's API stability.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__all__ = ["NDBufferTensor"]
|
|
15
|
+
|
|
16
|
+
from collections.abc import Sequence
|
|
17
|
+
|
|
18
|
+
from . import typemaps, utils
|
|
19
|
+
from .ndbuffer import ndbuffer
|
|
20
|
+
from .package_ifc import StreamHolder
|
|
21
|
+
from .tensor_ifc import TensorHolder
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class NDBufferTensor(TensorHolder[ndbuffer.NDBuffer]):
|
|
25
|
+
"""
|
|
26
|
+
TensorHolder for ndbuffer ndarrays.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
name = "ndbuffer"
|
|
30
|
+
module = ndbuffer
|
|
31
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(conversion_function=lambda name: name, exception_type=TypeError)
|
|
32
|
+
|
|
33
|
+
def __init__(self, tensor):
|
|
34
|
+
super().__init__(tensor)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def data_ptr(self):
|
|
38
|
+
return self.tensor.data_ptr
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def device(self):
|
|
42
|
+
return self.tensor.device
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def device_id(self):
|
|
46
|
+
return self.tensor.device_id
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def dtype(self):
|
|
50
|
+
"""Name of the data type"""
|
|
51
|
+
return self.tensor.dtype_name
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def itemsize(self):
|
|
55
|
+
return self.tensor.itemsize
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def shape(self):
|
|
59
|
+
return self.tensor.shape
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def size(self):
|
|
63
|
+
return self.tensor.size
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def strides(self):
|
|
67
|
+
return self.tensor.strides
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def empty(
|
|
71
|
+
cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
|
|
72
|
+
):
|
|
73
|
+
"""
|
|
74
|
+
Create an empty tensor of the specified shape and data type.
|
|
75
|
+
|
|
76
|
+
Note, that the strides, if specified, MUST correspond to a dense (possibly permuted)
|
|
77
|
+
tensor, otherwise the created tensor may be corrupted.
|
|
78
|
+
"""
|
|
79
|
+
itemsize = typemaps.NAME_TO_ITEM_SIZE[dtype]
|
|
80
|
+
if device_id == "cpu":
|
|
81
|
+
tensor = ndbuffer.empty(
|
|
82
|
+
shape, ndbuffer.CPU_DEVICE_ID, dtype, itemsize, strides=strides, stream=stream_holder, **context
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
assert isinstance(device_id, int), "Internal Error: Cuda tensors must be allocated with an integer device_id."
|
|
86
|
+
with utils.device_ctx(device_id):
|
|
87
|
+
tensor = ndbuffer.empty(shape, device_id, dtype, itemsize, strides=strides, stream=stream_holder, **context)
|
|
88
|
+
return cls(tensor)
|
|
89
|
+
|
|
90
|
+
def asndbuffer(self):
|
|
91
|
+
return self.tensor
|
|
92
|
+
|
|
93
|
+
def to(self, device_id, stream_holder):
|
|
94
|
+
src_device_id = self.tensor.device_id
|
|
95
|
+
if src_device_id == device_id:
|
|
96
|
+
return self
|
|
97
|
+
|
|
98
|
+
if stream_holder is None:
|
|
99
|
+
raise ValueError("Stream holder is required for h2d/d2h transfers.")
|
|
100
|
+
|
|
101
|
+
if device_id == "cpu":
|
|
102
|
+
with utils.device_ctx(src_device_id):
|
|
103
|
+
tensor = ndbuffer.empty_like(self.tensor, device_id=ndbuffer.CPU_DEVICE_ID, stream=stream_holder)
|
|
104
|
+
ndbuffer.copy_into(tensor, self.tensor, stream_holder)
|
|
105
|
+
else:
|
|
106
|
+
with utils.device_ctx(device_id):
|
|
107
|
+
tensor = ndbuffer.empty_like(self.tensor, device_id=device_id, stream=stream_holder)
|
|
108
|
+
ndbuffer.copy_into(tensor, self.tensor, stream_holder)
|
|
109
|
+
|
|
110
|
+
return NDBufferTensor(tensor)
|
|
111
|
+
|
|
112
|
+
def copy_(self, src, stream_holder):
|
|
113
|
+
"""
|
|
114
|
+
Inplace copy of src (copy the data from src into self).
|
|
115
|
+
"""
|
|
116
|
+
device_id = self.tensor.device_id
|
|
117
|
+
src_nd = src._broadcast_to(self.shape).asndbuffer()
|
|
118
|
+
if device_id == "cpu":
|
|
119
|
+
device_id = src_nd.device_id
|
|
120
|
+
if device_id == "cpu":
|
|
121
|
+
ndbuffer.copy_into(self.tensor, src_nd, stream_holder)
|
|
122
|
+
else:
|
|
123
|
+
with utils.device_ctx(device_id):
|
|
124
|
+
ndbuffer.copy_into(self.tensor, src_nd, stream_holder)
|
|
125
|
+
|
|
126
|
+
def istensor(self):
|
|
127
|
+
"""
|
|
128
|
+
Check if the object is ndarray-like.
|
|
129
|
+
"""
|
|
130
|
+
return isinstance(self.tensor, ndbuffer.NDBuffer)
|
|
131
|
+
|
|
132
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
133
|
+
if copy:
|
|
134
|
+
raise NotImplementedError("Reshape with copy is not supported for ndbuffer")
|
|
135
|
+
return self.__class__(ndbuffer.reshaped_view(self.tensor, shape))
|
|
136
|
+
|
|
137
|
+
def memory_buffer(self):
|
|
138
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
139
|
+
raise NotImplementedError
|
|
140
|
+
|
|
141
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
142
|
+
"""
|
|
143
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
144
|
+
shape and strides.
|
|
145
|
+
"""
|
|
146
|
+
raise NotImplementedError
|
|
147
|
+
|
|
148
|
+
def _broadcast_to(self, shape):
|
|
149
|
+
if self.tensor.shape == shape:
|
|
150
|
+
return self
|
|
151
|
+
raise NotImplementedError(
|
|
152
|
+
f"_broadcast_to is not supported for ndbuffer. Current shape: {self.tensor.shape}, requested shape: {shape}."
|
|
153
|
+
)
|