nvmath-python 0.5.0__cp313-cp313-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 +37 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/layout.py +58 -0
- nvmath/_utils.py +363 -0
- nvmath/bindings/__init__.pxd +0 -0
- nvmath/bindings/__init__.py +44 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/cublas.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +518 -0
- nvmath/bindings/_internal/cublasLt.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +54 -0
- nvmath/bindings/_internal/cudss.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +44 -0
- nvmath/bindings/_internal/cufft.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +69 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +386 -0
- nvmath/bindings/_internal/cusparse.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +270 -0
- nvmath/bindings/_internal/mathdx.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +79 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +186 -0
- nvmath/bindings/cublas.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +545 -0
- nvmath/bindings/cublas.pyi +18 -0
- nvmath/bindings/cublasLt.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +99 -0
- nvmath/bindings/cudss.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +83 -0
- nvmath/bindings/cudss.pyi +249 -0
- nvmath/bindings/cufft.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +114 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/curand.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/cusolver.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +60 -0
- nvmath/bindings/cusolverDn.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +410 -0
- nvmath/bindings/cusparse.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +329 -0
- nvmath/bindings/cycublas.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +657 -0
- nvmath/bindings/cycublasLt.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1010 -0
- nvmath/bindings/cycudss.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +191 -0
- nvmath/bindings/cycufft.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +320 -0
- nvmath/bindings/cycufftMp.pxd +333 -0
- nvmath/bindings/cycurand.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +146 -0
- nvmath/bindings/cycusolver.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +143 -0
- nvmath/bindings/cycusolverDn.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +414 -0
- nvmath/bindings/cycusparse.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +476 -0
- nvmath/bindings/cymathdx.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +363 -0
- nvmath/bindings/cynvshmem.pxd +126 -0
- nvmath/bindings/mathdx.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +131 -0
- nvmath/bindings/mathdx.pyi +686 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +11 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/cyfft.pxd +87 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/device/__init__.py +23 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/caching.py +51 -0
- nvmath/device/common.py +131 -0
- nvmath/device/common_backend.py +125 -0
- nvmath/device/common_cuda.py +156 -0
- nvmath/device/common_mathdx.py +97 -0
- nvmath/device/common_numba.py +159 -0
- nvmath/device/common_opaque_tensor.py +128 -0
- nvmath/device/cublasdx.py +1085 -0
- nvmath/device/cublasdx_backend.py +552 -0
- nvmath/device/cublasdx_numba.py +528 -0
- nvmath/device/cufftdx.py +551 -0
- nvmath/device/cufftdx_backend.py +194 -0
- nvmath/device/cufftdx_numba.py +123 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/nvrtc.py +95 -0
- nvmath/device/patch.py +35 -0
- nvmath/device/random.py +417 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +189 -0
- nvmath/device/types.py +11 -0
- nvmath/device/vector_types_numba.py +203 -0
- nvmath/distributed/__init__.py +117 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nvshmem.py +243 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +111 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +53 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +108 -0
- nvmath/distributed/_internal/tensor_wrapper.py +59 -0
- nvmath/distributed/_utils.py +152 -0
- nvmath/distributed/fft/__init__.py +6 -0
- nvmath/distributed/fft/_configuration.py +86 -0
- nvmath/distributed/fft/fft.py +1737 -0
- nvmath/distributed/reshape/__init__.py +6 -0
- nvmath/distributed/reshape/_configuration.py +39 -0
- nvmath/distributed/reshape/reshape.py +1249 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +208 -0
- nvmath/fft/_exec_utils.py +116 -0
- nvmath/fft/_helpers.py +260 -0
- nvmath/fft/fft.py +2346 -0
- nvmath/internal/__init__.py +5 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/package_ifc.py +119 -0
- nvmath/internal/package_ifc_cuda.py +43 -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 +143 -0
- nvmath/internal/tensor_ifc_cupy.py +185 -0
- nvmath/internal/tensor_ifc_numpy.py +157 -0
- nvmath/internal/tensor_ifc_torch.py +115 -0
- nvmath/internal/tensor_wrapper.py +160 -0
- nvmath/internal/typemaps.py +154 -0
- nvmath/internal/utils.py +634 -0
- nvmath/linalg/__init__.py +11 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +86 -0
- nvmath/linalg/_internal/algo_config_ifc.py +87 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +738 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +72 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +65 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +59 -0
- nvmath/linalg/_internal/typemaps.py +135 -0
- nvmath/linalg/_internal/utils.py +96 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +142 -0
- nvmath/linalg/advanced/_configuration.py +320 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +173 -0
- nvmath/linalg/advanced/matmulmod.py +2855 -0
- nvmath/memory.py +266 -0
- nvmath/sparse/__init__.py +18 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +81 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +584 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +291 -0
- nvmath/sparse/_internal/cudss_utils.py +398 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +154 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +88 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +80 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +150 -0
- nvmath/sparse/advanced/direct_solver.py +1705 -0
- nvmath_python-0.5.0.dist-info/METADATA +122 -0
- nvmath_python-0.5.0.dist-info/RECORD +174 -0
- nvmath_python-0.5.0.dist-info/WHEEL +5 -0
- nvmath_python-0.5.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-0.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import operator
|
|
6
|
+
|
|
7
|
+
from nvmath.device import curand_kernel
|
|
8
|
+
from nvmath.device.common_mathdx import CURAND_HOME # noqa: F401
|
|
9
|
+
|
|
10
|
+
from numba import cuda, types
|
|
11
|
+
from numba.extending import models, register_model, typeof_impl
|
|
12
|
+
from numba.cuda.cudadecl import register_global
|
|
13
|
+
from numba.cuda.cudaimpl import lower
|
|
14
|
+
from numba.core.typing.templates import AbstractTemplate, signature
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from llvmlite import ir
|
|
18
|
+
|
|
19
|
+
xorwow_dtype = np.dtype(
|
|
20
|
+
[
|
|
21
|
+
("d", np.uint32),
|
|
22
|
+
("v", np.uint32, (5,)),
|
|
23
|
+
("boxmuller_flag", np.int32),
|
|
24
|
+
("boxmuller_flag_double", np.int32),
|
|
25
|
+
("boxmuller_extra", np.float32),
|
|
26
|
+
("boxmuller_extra_double", np.float64),
|
|
27
|
+
],
|
|
28
|
+
align=True,
|
|
29
|
+
)
|
|
30
|
+
test_dtype = np.dtype([("v", np.uint32)], align=True)
|
|
31
|
+
mrg32k3a_dtype = np.dtype(
|
|
32
|
+
[
|
|
33
|
+
("s1", np.uint32, (3,)),
|
|
34
|
+
("s2", np.uint32, (3,)),
|
|
35
|
+
("boxmuller_flag", np.int32),
|
|
36
|
+
("boxmuller_flag_double", np.int32),
|
|
37
|
+
("boxmuller_extra", np.float32),
|
|
38
|
+
("boxmuller_extra_double", np.float64),
|
|
39
|
+
],
|
|
40
|
+
align=True,
|
|
41
|
+
)
|
|
42
|
+
sobol32_dtype = np.dtype(
|
|
43
|
+
[("i", np.uint32), ("x", np.uint32), ("c", np.uint32), ("direction_vectors", np.int32, (32,))], align=True
|
|
44
|
+
)
|
|
45
|
+
scrambled_sobol32_dtype = np.dtype(
|
|
46
|
+
[("i", np.uint32), ("x", np.uint32), ("c", np.uint32), ("direction_vectors", np.int32, (32,))], align=True
|
|
47
|
+
)
|
|
48
|
+
sobol64_dtype = np.dtype(
|
|
49
|
+
[("i", np.uint64), ("x", np.uint64), ("c", np.uint64), ("direction_vectors", np.int64, (64,))], align=True
|
|
50
|
+
)
|
|
51
|
+
scrambled_sobol64_dtype = np.dtype(
|
|
52
|
+
[("i", np.uint64), ("x", np.uint64), ("c", np.uint64), ("direction_vectors", np.int64, (64,))], align=True
|
|
53
|
+
)
|
|
54
|
+
philox4_32_10_dtype = np.dtype(
|
|
55
|
+
[
|
|
56
|
+
("ctr", np.uint32, (4,)),
|
|
57
|
+
("output", np.uint32, (4,)),
|
|
58
|
+
("key", np.uint32, (2,)),
|
|
59
|
+
("STATE", np.uint32),
|
|
60
|
+
("boxmuller_flag", np.int32),
|
|
61
|
+
("boxmuller_flag_double", np.int32),
|
|
62
|
+
("boxmuller_extra", np.float32),
|
|
63
|
+
("boxmuller_extra_double", np.float64),
|
|
64
|
+
],
|
|
65
|
+
align=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
NP_DTYPES = {
|
|
69
|
+
"curandStateXORWOW": xorwow_dtype,
|
|
70
|
+
"curandStateTest": test_dtype,
|
|
71
|
+
"curandStateMRG32k3a": mrg32k3a_dtype,
|
|
72
|
+
"curandStateSobol32": sobol32_dtype,
|
|
73
|
+
"curandStateScrambledSobol32": scrambled_sobol32_dtype,
|
|
74
|
+
"curandStateSobol64": sobol64_dtype,
|
|
75
|
+
"curandStateScrambledSobol64": scrambled_sobol64_dtype,
|
|
76
|
+
"curandStatePhilox4_32_10": philox4_32_10_dtype,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def make_curand_states(name: str):
|
|
81
|
+
"""Create a boxed curand states object to represent an array of curand state.
|
|
82
|
+
Should invoke after creating the numba types for each curand state.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
curand_state_name = name
|
|
86
|
+
|
|
87
|
+
state_ty = getattr(curand_kernel, f"_type_{curand_state_name}")
|
|
88
|
+
|
|
89
|
+
curand_states_name = curand_state_name.replace("State", "States")
|
|
90
|
+
|
|
91
|
+
# cuRAND state type as a NumPy dtype - this mirrors the state defined in
|
|
92
|
+
# curand_kernel.h. Can be used to inspect the state through the device array
|
|
93
|
+
# held by CurandStates.
|
|
94
|
+
|
|
95
|
+
curandStateDtype = NP_DTYPES[curand_state_name]
|
|
96
|
+
|
|
97
|
+
# Hold an array of cuRAND states - somewhat analogous to a curandState* in
|
|
98
|
+
# C/C++.
|
|
99
|
+
|
|
100
|
+
class CurandStates:
|
|
101
|
+
def __init__(self, n):
|
|
102
|
+
self._array = cuda.device_array(n, dtype=curandStateDtype)
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def data(self):
|
|
106
|
+
return self._array.__cuda_array_interface__["data"][0]
|
|
107
|
+
|
|
108
|
+
CurandStates.__name__ = curand_states_name
|
|
109
|
+
|
|
110
|
+
class CurandStatePointer(types.Type):
|
|
111
|
+
def __init__(self, name):
|
|
112
|
+
self.dtype = state_ty
|
|
113
|
+
super().__init__(name=name)
|
|
114
|
+
|
|
115
|
+
curand_state_pointer = CurandStatePointer(curand_states_name + "*")
|
|
116
|
+
|
|
117
|
+
@typeof_impl.register(CurandStates)
|
|
118
|
+
def typeof_curand_states(val, c):
|
|
119
|
+
return curand_state_pointer
|
|
120
|
+
|
|
121
|
+
@register_global(operator.getitem)
|
|
122
|
+
class CurandStatesPointerGetItem(AbstractTemplate):
|
|
123
|
+
def generic(self, args, kws):
|
|
124
|
+
assert not kws
|
|
125
|
+
[ptr, idx] = args
|
|
126
|
+
if ptr == curand_state_pointer:
|
|
127
|
+
return signature(types.CPointer(state_ty), curand_state_pointer, types.int64)
|
|
128
|
+
|
|
129
|
+
register_model(CurandStatePointer)(models.PointerModel)
|
|
130
|
+
|
|
131
|
+
@lower(operator.getitem, curand_state_pointer, types.int64)
|
|
132
|
+
def lower_curand_states_getitem(context, builder, sig, args):
|
|
133
|
+
[ptr, idx] = args
|
|
134
|
+
|
|
135
|
+
# Working out my own GEP
|
|
136
|
+
ptrint = builder.ptrtoint(ptr, ir.IntType(64))
|
|
137
|
+
itemsize = curandStateDtype.itemsize
|
|
138
|
+
offset = builder.mul(idx, context.get_constant(types.int64, itemsize))
|
|
139
|
+
ptrint = builder.add(ptrint, offset)
|
|
140
|
+
ptr = builder.inttoptr(ptrint, ptr.type)
|
|
141
|
+
return ptr
|
|
142
|
+
|
|
143
|
+
# Argument handling. When a CurandStatePointer is passed into a kernel, we
|
|
144
|
+
# really only need to pass the pointer to the data, not the whole underlying
|
|
145
|
+
# array structure. Our handler here transforms these arguments into a uint64
|
|
146
|
+
# holding the pointer.
|
|
147
|
+
|
|
148
|
+
class CurandStateArgHandler:
|
|
149
|
+
def prepare_args(self, ty, val, **kwargs):
|
|
150
|
+
if isinstance(val, CurandStates):
|
|
151
|
+
assert ty == curand_state_pointer
|
|
152
|
+
return types.uint64, val.data
|
|
153
|
+
else:
|
|
154
|
+
return ty, val
|
|
155
|
+
|
|
156
|
+
curand_state_arg_handler = CurandStateArgHandler()
|
|
157
|
+
|
|
158
|
+
return CurandStates, curand_state_arg_handler
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
curandStates = [
|
|
162
|
+
"curandStateTest",
|
|
163
|
+
"curandStateXORWOW",
|
|
164
|
+
"curandStateMRG32k3a",
|
|
165
|
+
"curandStateSobol32",
|
|
166
|
+
"curandStateScrambledSobol32",
|
|
167
|
+
"curandStateSobol64",
|
|
168
|
+
"curandStateScrambledSobol64",
|
|
169
|
+
"curandStatePhilox4_32_10",
|
|
170
|
+
# Require additional type parsing of mtgp32_params_fast and mtgp32_kernel_params
|
|
171
|
+
# "curandStateMtgp32",
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
numpy_curand_states = []
|
|
175
|
+
states_arg_handlers = []
|
|
176
|
+
|
|
177
|
+
for state in curandStates:
|
|
178
|
+
states_obj, arg_handler = make_curand_states(state)
|
|
179
|
+
numpy_curand_states.append(states_obj)
|
|
180
|
+
states_arg_handlers.append(arg_handler)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# Export
|
|
184
|
+
globals().update({s.__name__: s for s in numpy_curand_states})
|
|
185
|
+
globals().update({"states_arg_handlers": states_arg_handlers})
|
|
186
|
+
|
|
187
|
+
__all__ = list( # noqa: F822
|
|
188
|
+
{s.__name__ for s in numpy_curand_states} | {"states_arg_handlers"}
|
|
189
|
+
)
|
nvmath/device/types.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
np_float16x2 = np.dtype([("x", np.float16), ("y", np.float16)], align=True)
|
|
8
|
+
np_float16x4 = np.dtype([("x", np.float16), ("y", np.float16), ("z", np.float16), ("w", np.float16)], align=True)
|
|
9
|
+
|
|
10
|
+
REAL_NP_TYPES: list = [np.float16, np.float32, np.float64]
|
|
11
|
+
INT_NP_TYPES: list = [np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64]
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"float16x2",
|
|
7
|
+
"float16x4",
|
|
8
|
+
"float32x2",
|
|
9
|
+
"float64x2",
|
|
10
|
+
"float16x2_type",
|
|
11
|
+
"float16x4_type",
|
|
12
|
+
"float32x2_type",
|
|
13
|
+
"float64x2_type",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
import typing
|
|
17
|
+
|
|
18
|
+
from numba.core import types
|
|
19
|
+
|
|
20
|
+
from numba.extending import overload, models, register_model, lower_builtin, as_numba_type, type_callable, lower_cast
|
|
21
|
+
from numba.core.typeconv import Conversion
|
|
22
|
+
from llvmlite import ir
|
|
23
|
+
from numba.core.typing.templates import AttributeTemplate
|
|
24
|
+
from numba.cuda.cudadecl import registry as cuda_registry
|
|
25
|
+
from numba.cuda.cudaimpl import lower_attr as cuda_lower_attr
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def make_vector(
|
|
29
|
+
float_bitwidth: int, numba_float_type: types.scalars.Float, llvm_float_type, vector_length: typing.Literal[2, 4]
|
|
30
|
+
):
|
|
31
|
+
assert vector_length == 2 or vector_length == 4
|
|
32
|
+
vector_bitwidth = vector_length * float_bitwidth
|
|
33
|
+
|
|
34
|
+
# User visible types and functions
|
|
35
|
+
class vector:
|
|
36
|
+
def __init__(self, *args):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
def create(input):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
# FE types
|
|
43
|
+
class vectorType(types.Number):
|
|
44
|
+
def __init__(self):
|
|
45
|
+
super().__init__(name=f"vector({numba_float_type.name}x{vector_length})")
|
|
46
|
+
self.dtype = numba_float_type
|
|
47
|
+
self.count = vector_length
|
|
48
|
+
self.bitwidth = vector_bitwidth
|
|
49
|
+
self.make = vector
|
|
50
|
+
|
|
51
|
+
def can_convert_from(self, typingctx, other):
|
|
52
|
+
if vector_length == 2 and isinstance(other, types.Complex):
|
|
53
|
+
if other.bitwidth == vector_bitwidth:
|
|
54
|
+
return Conversion.exact
|
|
55
|
+
elif other.bitwidth < vector_bitwidth:
|
|
56
|
+
return Conversion.safe
|
|
57
|
+
elif other.bitwidth > vector_bitwidth:
|
|
58
|
+
return Conversion.unsafe
|
|
59
|
+
|
|
60
|
+
def can_convert_to(self, typingctx, other):
|
|
61
|
+
if vector_length == 2 and isinstance(other, types.Complex):
|
|
62
|
+
if other.bitwidth == vector_bitwidth:
|
|
63
|
+
return Conversion.exact
|
|
64
|
+
elif other.bitwidth < vector_bitwidth:
|
|
65
|
+
return Conversion.unsafe
|
|
66
|
+
elif other.bitwidth > vector_bitwidth:
|
|
67
|
+
return Conversion.safe
|
|
68
|
+
|
|
69
|
+
def __name__(self):
|
|
70
|
+
return f"vector({numba_float_type.name}x{vector_length})"
|
|
71
|
+
|
|
72
|
+
vector_type = vectorType()
|
|
73
|
+
|
|
74
|
+
types.number_domain = types.number_domain | frozenset([vector_type])
|
|
75
|
+
|
|
76
|
+
# Type inference (Python --> FE type)
|
|
77
|
+
as_numba_type.register(vector, vector_type)
|
|
78
|
+
|
|
79
|
+
# How to build a vectorType from individual elements
|
|
80
|
+
@type_callable(vector)
|
|
81
|
+
def type(context):
|
|
82
|
+
def typer(x, y=None, z=None, w=None):
|
|
83
|
+
if (
|
|
84
|
+
(vector_length == 2 and isinstance(x, types.Complex) and y is None and z is None and w is None)
|
|
85
|
+
or (vector_length == 2 and all(isinstance(v, types.Float) for v in [x, y]) and z is None and w is None)
|
|
86
|
+
or (vector_length == 4 and all(isinstance(v, types.Float) for v in [x, y, z, w]))
|
|
87
|
+
):
|
|
88
|
+
return vector_type
|
|
89
|
+
|
|
90
|
+
return typer
|
|
91
|
+
|
|
92
|
+
# How to represent vectorType in Memory?
|
|
93
|
+
@register_model(vectorType)
|
|
94
|
+
class vectorTypeModel(models.PrimitiveModel):
|
|
95
|
+
def __init__(self, dmm, fe_type):
|
|
96
|
+
be_type = ir.IntType(vector_bitwidth)
|
|
97
|
+
super().__init__(dmm, fe_type, be_type)
|
|
98
|
+
|
|
99
|
+
# How to build a vectorType from individual float values?
|
|
100
|
+
@lower_builtin(vector, *(vector_length * [types.Float])) # FIXME
|
|
101
|
+
def vector_ctor(context, builder, sig, args):
|
|
102
|
+
typ = sig.return_type
|
|
103
|
+
args = list(args)
|
|
104
|
+
assert len(args) == vector_length
|
|
105
|
+
for i in range(vector_length):
|
|
106
|
+
args[i] = context.cast(builder, args[i], sig.args[i], numba_float_type)
|
|
107
|
+
|
|
108
|
+
vt = ir.VectorType(llvm_float_type, vector_length)
|
|
109
|
+
val = ir.Constant(vt, ir.Undefined)
|
|
110
|
+
|
|
111
|
+
for i in range(vector_length):
|
|
112
|
+
val = builder.insert_element(val, args[i], context.get_constant(types.int32, i))
|
|
113
|
+
|
|
114
|
+
return builder.bitcast(val, context.get_value_type(typ))
|
|
115
|
+
|
|
116
|
+
# How to access .x, .y, .z, .w
|
|
117
|
+
@cuda_registry.register_attr
|
|
118
|
+
class complex_attrs(AttributeTemplate):
|
|
119
|
+
key = vectorType
|
|
120
|
+
|
|
121
|
+
def resolve_x(self, mod):
|
|
122
|
+
return numba_float_type
|
|
123
|
+
|
|
124
|
+
def resolve_y(self, mod):
|
|
125
|
+
return numba_float_type
|
|
126
|
+
|
|
127
|
+
def resolve_z(self, mod):
|
|
128
|
+
return numba_float_type
|
|
129
|
+
|
|
130
|
+
def resolve_w(self, mod):
|
|
131
|
+
return numba_float_type
|
|
132
|
+
|
|
133
|
+
def complex_get(context, builder, typ, val, i):
|
|
134
|
+
vt = ir.VectorType(llvm_float_type, vector_length)
|
|
135
|
+
vec = builder.bitcast(val, vt)
|
|
136
|
+
index = context.get_constant(types.int32, i)
|
|
137
|
+
return builder.extract_element(vec, index)
|
|
138
|
+
|
|
139
|
+
# This cannot be done with a loop
|
|
140
|
+
@cuda_lower_attr(vectorType, "x")
|
|
141
|
+
def complex_get_x(context, builder, typ, val):
|
|
142
|
+
return complex_get(context, builder, typ, val, 0)
|
|
143
|
+
|
|
144
|
+
@cuda_lower_attr(vectorType, "y")
|
|
145
|
+
def complex_get_y(context, builder, typ, val):
|
|
146
|
+
return complex_get(context, builder, typ, val, 1)
|
|
147
|
+
|
|
148
|
+
if vector_length == 4:
|
|
149
|
+
|
|
150
|
+
@cuda_lower_attr(vectorType, "z")
|
|
151
|
+
def complex_get_z(context, builder, typ, val):
|
|
152
|
+
return complex_get(context, builder, typ, val, 2)
|
|
153
|
+
|
|
154
|
+
@cuda_lower_attr(vectorType, "w")
|
|
155
|
+
def complex_get_w(context, builder, typ, val):
|
|
156
|
+
return complex_get(context, builder, typ, val, 3)
|
|
157
|
+
|
|
158
|
+
# Conversions from types.Complex
|
|
159
|
+
if vector_length == 2:
|
|
160
|
+
|
|
161
|
+
@overload(create)
|
|
162
|
+
def make_complex(cplx):
|
|
163
|
+
if isinstance(cplx, types.Complex):
|
|
164
|
+
|
|
165
|
+
def impl(cplx):
|
|
166
|
+
return vector(cplx.real, cplx.imag)
|
|
167
|
+
|
|
168
|
+
return impl
|
|
169
|
+
|
|
170
|
+
@lower_cast(types.Complex, vector_type)
|
|
171
|
+
def np_complex_to_complex(context, builder, fromty, toty, val):
|
|
172
|
+
src = context.make_complex(builder, fromty, value=val)
|
|
173
|
+
src_float_ty = fromty.underlying_float
|
|
174
|
+
ctor_sig = toty(src_float_ty, src_float_ty)
|
|
175
|
+
ctor_args = (src.real, src.imag)
|
|
176
|
+
return vector_ctor(context, builder, ctor_sig, ctor_args)
|
|
177
|
+
|
|
178
|
+
@lower_cast(vector_type, types.Complex)
|
|
179
|
+
def complex_to_np_complex(context, builder, fromty, toty, val):
|
|
180
|
+
dst_float_ty = toty.underlying_float
|
|
181
|
+
x = complex_get(context, builder, fromty, val, 0)
|
|
182
|
+
y = complex_get(context, builder, fromty, val, 1)
|
|
183
|
+
x = context.cast(builder, x, numba_float_type, dst_float_ty)
|
|
184
|
+
y = context.cast(builder, y, numba_float_type, dst_float_ty)
|
|
185
|
+
vt = context.get_value_type(toty)
|
|
186
|
+
val = ir.Constant(vt, ir.Undefined)
|
|
187
|
+
val = builder.insert_value(val, x, [0])
|
|
188
|
+
val = builder.insert_value(val, y, [1])
|
|
189
|
+
return val
|
|
190
|
+
|
|
191
|
+
vector.__name__ = f"float{float_bitwidth}x{vector_length}"
|
|
192
|
+
vector.__doc__ = f"""
|
|
193
|
+
float{float_bitwidth}x{vector_length}({"x, y" if vector_length == 2 else "x, y, z, w"})
|
|
194
|
+
|
|
195
|
+
Create a Numba compliant vector object for float{float_bitwidth} with vector length {vector_length}.
|
|
196
|
+
"""
|
|
197
|
+
return vector, vector_type
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
float16x2, float16x2_type = make_vector(16, types.float16, ir.IntType(16), 2)
|
|
201
|
+
float16x4, float16x4_type = make_vector(16, types.float16, ir.IntType(16), 4)
|
|
202
|
+
float32x2, float32x2_type = make_vector(32, types.float32, ir.FloatType(), 2)
|
|
203
|
+
float64x2, float64x2_type = make_vector(64, types.float64, ir.DoubleType(), 2)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import mpi4py # noqa: F401
|
|
9
|
+
except ImportError as e:
|
|
10
|
+
# TODO: point to documentation with ways to install mpi4py
|
|
11
|
+
raise ImportError("nvmath.distributed requires mpi4py for bootstrapping. See [LINK] for installation guide.") from e
|
|
12
|
+
|
|
13
|
+
import atexit
|
|
14
|
+
import re
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from threading import Lock
|
|
17
|
+
|
|
18
|
+
from ._internal import nvshmem
|
|
19
|
+
from ._utils import allocate_symmetric_memory, free_symmetric_memory
|
|
20
|
+
|
|
21
|
+
from nvmath.distributed import fft
|
|
22
|
+
from nvmath.distributed import reshape
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"initialize",
|
|
26
|
+
"finalize",
|
|
27
|
+
"get_context",
|
|
28
|
+
"allocate_symmetric_memory",
|
|
29
|
+
"free_symmetric_memory",
|
|
30
|
+
"fft",
|
|
31
|
+
"reshape",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
_initialize_mutex = Lock()
|
|
35
|
+
_atexit_registered = False
|
|
36
|
+
_ctx = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class DistributedContext:
|
|
41
|
+
"""
|
|
42
|
+
Context of initialized nvmath.distributed runtime.
|
|
43
|
+
|
|
44
|
+
Attributes:
|
|
45
|
+
device_id: CUDA device ID associated with the distributed runtime.
|
|
46
|
+
communicator: MPI communicator of participating processes.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
device_id: int
|
|
50
|
+
communicator: mpi4py.MPI.Comm
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def initialize(device_id: int, communicator: mpi4py.MPI.Comm | None = None) -> None:
|
|
54
|
+
"""Initialize nvmath.distributed. This is required before any distributed operations can
|
|
55
|
+
be performed. **Note that this is a collective operation and must be called by all
|
|
56
|
+
processes.**
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
device_id: CUDA device ID to associate with the nvmath.distributed runtime.
|
|
60
|
+
communicator: MPI communicator specifying the participating processes. If None, will
|
|
61
|
+
use MPI.COMM_WORLD.
|
|
62
|
+
"""
|
|
63
|
+
if not isinstance(device_id, int):
|
|
64
|
+
raise TypeError(
|
|
65
|
+
"The device ID used to initialize the nvmath.distributed module "
|
|
66
|
+
f"must be an integer. The provided device ID is {device_id}."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
with _initialize_mutex:
|
|
70
|
+
global _atexit_registered, _ctx
|
|
71
|
+
|
|
72
|
+
if _ctx is not None:
|
|
73
|
+
raise RuntimeError("nvmath.distributed has already been initialized")
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
# This initializes MPI if it hasn't been initialized yet.
|
|
77
|
+
from mpi4py import MPI
|
|
78
|
+
except RuntimeError as e:
|
|
79
|
+
if re.search(r"[Cc]annot load MPI library", str(e)):
|
|
80
|
+
raise RuntimeError("mpi4py could not find the MPI library. See [LINK] for installation tips") from e
|
|
81
|
+
raise
|
|
82
|
+
|
|
83
|
+
if not _atexit_registered:
|
|
84
|
+
# mpi4py's atexit handler is registered during `import MPI`, and to finalize
|
|
85
|
+
# NVSHMEM *before* MPI, we need to make sure that we register our exit handler
|
|
86
|
+
# *after* mpi4py's.
|
|
87
|
+
atexit.register(finalize)
|
|
88
|
+
_atexit_registered = True
|
|
89
|
+
|
|
90
|
+
if communicator is None:
|
|
91
|
+
communicator = MPI.COMM_WORLD
|
|
92
|
+
elif not isinstance(communicator, mpi4py.MPI.Comm):
|
|
93
|
+
raise TypeError(
|
|
94
|
+
"The provided communicator object should be of type mpi4py.MPI communicator, but "
|
|
95
|
+
f"got object of type {type(communicator)}."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
nvshmem.initialize(device_id, communicator)
|
|
99
|
+
|
|
100
|
+
_ctx = DistributedContext(device_id=device_id, communicator=communicator)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def finalize() -> None:
|
|
104
|
+
"""Finalize nvmath.distributed runtime. **Note that this is a collective operation and
|
|
105
|
+
must be called by all processes.**"""
|
|
106
|
+
global _ctx
|
|
107
|
+
with _initialize_mutex:
|
|
108
|
+
if _ctx is None:
|
|
109
|
+
return
|
|
110
|
+
nvshmem.finalize(_ctx.device_id)
|
|
111
|
+
|
|
112
|
+
_ctx = None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_context() -> DistributedContext | None:
|
|
116
|
+
"""Return the distributed runtime's context or None if not initialized."""
|
|
117
|
+
return _ctx
|
|
File without changes
|