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.
Files changed (174) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +37 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/layout.py +58 -0
  5. nvmath/_utils.py +363 -0
  6. nvmath/bindings/__init__.pxd +0 -0
  7. nvmath/bindings/__init__.py +44 -0
  8. nvmath/bindings/_internal/__init__.pxd +0 -0
  9. nvmath/bindings/_internal/__init__.py +0 -0
  10. nvmath/bindings/_internal/cublas.cp313-win_amd64.pyd +0 -0
  11. nvmath/bindings/_internal/cublas.pxd +518 -0
  12. nvmath/bindings/_internal/cublasLt.cp313-win_amd64.pyd +0 -0
  13. nvmath/bindings/_internal/cublasLt.pxd +54 -0
  14. nvmath/bindings/_internal/cudss.cp313-win_amd64.pyd +0 -0
  15. nvmath/bindings/_internal/cudss.pxd +44 -0
  16. nvmath/bindings/_internal/cufft.cp313-win_amd64.pyd +0 -0
  17. nvmath/bindings/_internal/cufft.pxd +69 -0
  18. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  19. nvmath/bindings/_internal/curand.cp313-win_amd64.pyd +0 -0
  20. nvmath/bindings/_internal/curand.pxd +42 -0
  21. nvmath/bindings/_internal/cusolver.cp313-win_amd64.pyd +0 -0
  22. nvmath/bindings/_internal/cusolver.pxd +15 -0
  23. nvmath/bindings/_internal/cusolverDn.cp313-win_amd64.pyd +0 -0
  24. nvmath/bindings/_internal/cusolverDn.pxd +386 -0
  25. nvmath/bindings/_internal/cusparse.cp313-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/cusparse.pxd +270 -0
  27. nvmath/bindings/_internal/mathdx.cp313-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/mathdx.pxd +79 -0
  29. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  30. nvmath/bindings/_internal/utils.cp313-win_amd64.pyd +0 -0
  31. nvmath/bindings/_internal/utils.pxd +186 -0
  32. nvmath/bindings/cublas.cp313-win_amd64.pyd +0 -0
  33. nvmath/bindings/cublas.pxd +545 -0
  34. nvmath/bindings/cublas.pyi +18 -0
  35. nvmath/bindings/cublasLt.cp313-win_amd64.pyd +0 -0
  36. nvmath/bindings/cublasLt.pxd +99 -0
  37. nvmath/bindings/cudss.cp313-win_amd64.pyd +0 -0
  38. nvmath/bindings/cudss.pxd +83 -0
  39. nvmath/bindings/cudss.pyi +249 -0
  40. nvmath/bindings/cufft.cp313-win_amd64.pyd +0 -0
  41. nvmath/bindings/cufft.pxd +114 -0
  42. nvmath/bindings/cufftMp.pxd +124 -0
  43. nvmath/bindings/curand.cp313-win_amd64.pyd +0 -0
  44. nvmath/bindings/curand.pxd +71 -0
  45. nvmath/bindings/cusolver.cp313-win_amd64.pyd +0 -0
  46. nvmath/bindings/cusolver.pxd +60 -0
  47. nvmath/bindings/cusolverDn.cp313-win_amd64.pyd +0 -0
  48. nvmath/bindings/cusolverDn.pxd +410 -0
  49. nvmath/bindings/cusparse.cp313-win_amd64.pyd +0 -0
  50. nvmath/bindings/cusparse.pxd +329 -0
  51. nvmath/bindings/cycublas.cp313-win_amd64.pyd +0 -0
  52. nvmath/bindings/cycublas.pxd +657 -0
  53. nvmath/bindings/cycublasLt.cp313-win_amd64.pyd +0 -0
  54. nvmath/bindings/cycublasLt.pxd +1010 -0
  55. nvmath/bindings/cycudss.cp313-win_amd64.pyd +0 -0
  56. nvmath/bindings/cycudss.pxd +191 -0
  57. nvmath/bindings/cycufft.cp313-win_amd64.pyd +0 -0
  58. nvmath/bindings/cycufft.pxd +320 -0
  59. nvmath/bindings/cycufftMp.pxd +333 -0
  60. nvmath/bindings/cycurand.cp313-win_amd64.pyd +0 -0
  61. nvmath/bindings/cycurand.pxd +146 -0
  62. nvmath/bindings/cycusolver.cp313-win_amd64.pyd +0 -0
  63. nvmath/bindings/cycusolver.pxd +143 -0
  64. nvmath/bindings/cycusolverDn.cp313-win_amd64.pyd +0 -0
  65. nvmath/bindings/cycusolverDn.pxd +414 -0
  66. nvmath/bindings/cycusparse.cp313-win_amd64.pyd +0 -0
  67. nvmath/bindings/cycusparse.pxd +476 -0
  68. nvmath/bindings/cymathdx.cp313-win_amd64.pyd +0 -0
  69. nvmath/bindings/cymathdx.pxd +363 -0
  70. nvmath/bindings/cynvshmem.pxd +126 -0
  71. nvmath/bindings/mathdx.cp313-win_amd64.pyd +0 -0
  72. nvmath/bindings/mathdx.pxd +131 -0
  73. nvmath/bindings/mathdx.pyi +686 -0
  74. nvmath/bindings/nvpl/__init__.pxd +0 -0
  75. nvmath/bindings/nvpl/__init__.py +11 -0
  76. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  77. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  78. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  79. nvmath/bindings/nvpl/cyfft.pxd +87 -0
  80. nvmath/bindings/nvpl/fft.pxd +100 -0
  81. nvmath/bindings/nvshmem.pxd +54 -0
  82. nvmath/device/__init__.py +23 -0
  83. nvmath/device/_deprecated.py +33 -0
  84. nvmath/device/caching.py +51 -0
  85. nvmath/device/common.py +131 -0
  86. nvmath/device/common_backend.py +125 -0
  87. nvmath/device/common_cuda.py +156 -0
  88. nvmath/device/common_mathdx.py +97 -0
  89. nvmath/device/common_numba.py +159 -0
  90. nvmath/device/common_opaque_tensor.py +128 -0
  91. nvmath/device/cublasdx.py +1085 -0
  92. nvmath/device/cublasdx_backend.py +552 -0
  93. nvmath/device/cublasdx_numba.py +528 -0
  94. nvmath/device/cufftdx.py +551 -0
  95. nvmath/device/cufftdx_backend.py +194 -0
  96. nvmath/device/cufftdx_numba.py +123 -0
  97. nvmath/device/curand_kernel.py +9147 -0
  98. nvmath/device/nvrtc.py +95 -0
  99. nvmath/device/patch.py +35 -0
  100. nvmath/device/random.py +417 -0
  101. nvmath/device/random_helpers.py +23 -0
  102. nvmath/device/random_states.py +189 -0
  103. nvmath/device/types.py +11 -0
  104. nvmath/device/vector_types_numba.py +203 -0
  105. nvmath/distributed/__init__.py +117 -0
  106. nvmath/distributed/_internal/__init__.py +0 -0
  107. nvmath/distributed/_internal/nvshmem.py +243 -0
  108. nvmath/distributed/_internal/tensor_ifc_cupy.py +111 -0
  109. nvmath/distributed/_internal/tensor_ifc_numpy.py +53 -0
  110. nvmath/distributed/_internal/tensor_ifc_torch.py +108 -0
  111. nvmath/distributed/_internal/tensor_wrapper.py +59 -0
  112. nvmath/distributed/_utils.py +152 -0
  113. nvmath/distributed/fft/__init__.py +6 -0
  114. nvmath/distributed/fft/_configuration.py +86 -0
  115. nvmath/distributed/fft/fft.py +1737 -0
  116. nvmath/distributed/reshape/__init__.py +6 -0
  117. nvmath/distributed/reshape/_configuration.py +39 -0
  118. nvmath/distributed/reshape/reshape.py +1249 -0
  119. nvmath/fft/__init__.py +7 -0
  120. nvmath/fft/_configuration.py +208 -0
  121. nvmath/fft/_exec_utils.py +116 -0
  122. nvmath/fft/_helpers.py +260 -0
  123. nvmath/fft/fft.py +2346 -0
  124. nvmath/internal/__init__.py +5 -0
  125. nvmath/internal/enum_utils.py +142 -0
  126. nvmath/internal/formatters.py +87 -0
  127. nvmath/internal/mem_limit.py +51 -0
  128. nvmath/internal/package_ifc.py +119 -0
  129. nvmath/internal/package_ifc_cuda.py +43 -0
  130. nvmath/internal/package_ifc_cupy.py +49 -0
  131. nvmath/internal/package_ifc_torch.py +31 -0
  132. nvmath/internal/package_wrapper.py +14 -0
  133. nvmath/internal/tensor_ifc.py +143 -0
  134. nvmath/internal/tensor_ifc_cupy.py +185 -0
  135. nvmath/internal/tensor_ifc_numpy.py +157 -0
  136. nvmath/internal/tensor_ifc_torch.py +115 -0
  137. nvmath/internal/tensor_wrapper.py +160 -0
  138. nvmath/internal/typemaps.py +154 -0
  139. nvmath/internal/utils.py +634 -0
  140. nvmath/linalg/__init__.py +11 -0
  141. nvmath/linalg/_internal/__init__.py +3 -0
  142. nvmath/linalg/_internal/algo_cap_ifc.py +86 -0
  143. nvmath/linalg/_internal/algo_config_ifc.py +87 -0
  144. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  145. nvmath/linalg/_internal/epilog_protocol.py +738 -0
  146. nvmath/linalg/_internal/matmul_desc_ifc.py +72 -0
  147. nvmath/linalg/_internal/matmul_pref_ifc.py +65 -0
  148. nvmath/linalg/_internal/matrix_layout_ifc.py +59 -0
  149. nvmath/linalg/_internal/typemaps.py +135 -0
  150. nvmath/linalg/_internal/utils.py +96 -0
  151. nvmath/linalg/advanced/__init__.py +8 -0
  152. nvmath/linalg/advanced/_algorithmmod.py +142 -0
  153. nvmath/linalg/advanced/_configuration.py +320 -0
  154. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  155. nvmath/linalg/advanced/helpers/matmul.py +173 -0
  156. nvmath/linalg/advanced/matmulmod.py +2855 -0
  157. nvmath/memory.py +266 -0
  158. nvmath/sparse/__init__.py +18 -0
  159. nvmath/sparse/_internal/__init__.py +21 -0
  160. nvmath/sparse/_internal/common_utils.py +81 -0
  161. nvmath/sparse/_internal/cudss_config_ifc.py +584 -0
  162. nvmath/sparse/_internal/cudss_data_ifc.py +291 -0
  163. nvmath/sparse/_internal/cudss_utils.py +398 -0
  164. nvmath/sparse/_internal/sparse_csr_ifc.py +154 -0
  165. nvmath/sparse/_internal/sparse_format_helpers.py +88 -0
  166. nvmath/sparse/_internal/sparse_tensor_ifc.py +80 -0
  167. nvmath/sparse/advanced/__init__.py +7 -0
  168. nvmath/sparse/advanced/_configuration.py +150 -0
  169. nvmath/sparse/advanced/direct_solver.py +1705 -0
  170. nvmath_python-0.5.0.dist-info/METADATA +122 -0
  171. nvmath_python-0.5.0.dist-info/RECORD +174 -0
  172. nvmath_python-0.5.0.dist-info/WHEEL +5 -0
  173. nvmath_python-0.5.0.dist-info/licenses/LICENSE +177 -0
  174. 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