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
nvmath/device/nvrtc.py ADDED
@@ -0,0 +1,95 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import functools
6
+ import logging
7
+
8
+ from cuda.bindings import nvrtc
9
+
10
+ from .caching import disk_cache
11
+ from .common import check_in
12
+ from .common_cuda import ISAVersion
13
+ from .common_mathdx import CUDA_HOME
14
+
15
+
16
+ def CHECK_NVRTC(err, prog):
17
+ if err != nvrtc.nvrtcResult.NVRTC_SUCCESS:
18
+ err, logsize = nvrtc.nvrtcGetProgramLogSize(prog)
19
+ log = b" " * logsize
20
+ err = nvrtc.nvrtcGetProgramLog(prog, log)
21
+ raise RuntimeError(f"NVRTC error: {log.decode('ascii')}")
22
+
23
+
24
+ # cpp is the C++ source code
25
+ # cc is an instance of ComputeCapability
26
+ # rdc is true or false
27
+ # code is lto or ptx
28
+ # @cache
29
+ @functools.lru_cache(maxsize=32) # Always enabled
30
+ @disk_cache # Optional, see caching.py
31
+ def compile_impl(cpp, cc, rdc, code, cuda_home, nvrtc_path, nvrtc_version):
32
+ logging.debug(f"Compiling with CUDA_HOME={cuda_home}, and NVRTC {nvrtc_version}")
33
+
34
+ check_in("rdc", rdc, [True, False])
35
+ check_in("code", code, ["lto", "ptx"])
36
+
37
+ opts = (
38
+ [b"--std=c++17", b"--device-as-default-execution-space", b"-DCUFFTDX_DETAIL_USE_CUDA_STL=1"]
39
+ + [bytes(f"--include-path={h}/include", encoding="ascii") for h in cuda_home]
40
+ + [
41
+ bytes(f"--gpu-architecture=compute_{cc.major * 10 + cc.minor}", encoding="ascii"),
42
+ ]
43
+ )
44
+ if rdc:
45
+ opts += [b"--relocatable-device-code=true"]
46
+
47
+ if code == "lto":
48
+ opts += [b"-dlto"]
49
+
50
+ # Create program
51
+ err, prog = nvrtc.nvrtcCreateProgram(str.encode(cpp), b"code.cu", 0, [], [])
52
+ if err != nvrtc.nvrtcResult.NVRTC_SUCCESS:
53
+ raise RuntimeError(f"nvrtcCreateProgram error: {err}")
54
+
55
+ (err,) = nvrtc.nvrtcCompileProgram(prog, len(opts), opts)
56
+ CHECK_NVRTC(err, prog)
57
+
58
+ if code == "lto":
59
+ err, ltoSize = nvrtc.nvrtcGetLTOIRSize(prog)
60
+ CHECK_NVRTC(err, prog)
61
+
62
+ lto = b" " * ltoSize
63
+ (err,) = nvrtc.nvrtcGetLTOIR(prog, lto)
64
+ CHECK_NVRTC(err, prog)
65
+
66
+ (err,) = nvrtc.nvrtcDestroyProgram(prog)
67
+ CHECK_NVRTC(err, prog)
68
+
69
+ return lto
70
+
71
+ elif code == "ptx":
72
+ err, ptxSize = nvrtc.nvrtcGetPTXSize(prog)
73
+ CHECK_NVRTC(err, prog)
74
+
75
+ ptx = b" " * ptxSize
76
+ (err,) = nvrtc.nvrtcGetPTX(prog, ptx)
77
+ CHECK_NVRTC(err, prog)
78
+
79
+ (err,) = nvrtc.nvrtcDestroyProgram(prog)
80
+ CHECK_NVRTC(err, prog)
81
+
82
+ return ptx.decode("ascii")
83
+
84
+
85
+ def compile(**kwargs):
86
+ err, major, minor = nvrtc.nvrtcVersion()
87
+ if err != nvrtc.nvrtcResult.NVRTC_SUCCESS:
88
+ raise RuntimeError(f"nvrtcVersion error: {err}")
89
+ nvrtc_version = ISAVersion(major, minor)
90
+ return nvrtc_version, compile_impl(
91
+ **kwargs,
92
+ cuda_home=CUDA_HOME,
93
+ nvrtc_path=nvrtc.__file__,
94
+ nvrtc_version=nvrtc_version,
95
+ )
nvmath/device/patch.py ADDED
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ #
6
+ # Monkey-patching of Numba to:
7
+ # support LTO code generation and linking
8
+ # find libnvvm located in PYPI wheels
9
+ #
10
+ import functools
11
+
12
+ import numba
13
+ import numba.cuda as cuda
14
+ import numba_cuda
15
+
16
+
17
+ #
18
+ # Monkey patching
19
+ #
20
+
21
+
22
+ def patch_codegen():
23
+ # Check Numba version
24
+ required_numba_cuda_ver = (0, 9)
25
+ numba_cuda_ver = tuple(map(int, numba_cuda.__version__.split(".")))[:2]
26
+ if numba_cuda_ver < required_numba_cuda_ver:
27
+ raise RuntimeError(
28
+ f"numba-cuda version {required_numba_cuda_ver} is required, but got {numba_cuda.__version__} (aka {numba_cuda_ver})"
29
+ )
30
+
31
+ # Add new LTO-IR linker to Numba (from pynvjitlink)
32
+ numba.config.CUDA_ENABLE_PYNVJITLINK = True
33
+ # TODO: proper support for default lto value
34
+ # https://github.com/NVIDIA/numba-cuda/issues/162
35
+ cuda.jit = functools.partial(cuda.jit, lto=True)
@@ -0,0 +1,417 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Device APIs for RNGs: bit generators and distribution generators.
7
+
8
+ The APIs follow the cuRAND device APIs: https://docs.nvidia.com/cuda/curand/group__DEVICE.html
9
+ """
10
+
11
+ import functools
12
+ import re
13
+ import sys
14
+
15
+ import nvmath.device
16
+ from nvmath.device import curand_kernel, random_helpers
17
+ from nvmath.device import random_states as states
18
+
19
+ # Common APIs (initialization, bit generation).
20
+ _COMMON_APIS = ["init", "rand", "rand4"]
21
+ _COMMON_APIS_PREFIX = ["curand_", "cu", "cu"]
22
+ _INIT_DOC = """init(..., state)
23
+ Initialize the RNG state.
24
+
25
+ The arguments depend upon the selected bit generator (see the overloads of `curand_init`
26
+ in `cuRAND docs <https://docs.nvidia.com/cuda/curand/group__DEVICE.html>`_).
27
+
28
+ Example:
29
+
30
+ >>> from numba import cuda
31
+ >>> from nvmath.device import random
32
+ >>> compiled_apis = random.Compile(cc=None)
33
+
34
+ We will be working on a grid of 64 blocks, with 64 threads in each.
35
+
36
+ >>> threads = 64
37
+ >>> blocks = 64
38
+ >>> nthreads = blocks * threads
39
+
40
+ Let us show how to use `init` with :class:`nvmath.device.random.StatesPhilox4_32_10`
41
+ states. The same applies to :class:`nvmath.device.random.StatesMRG32k3a` and
42
+ :class:`nvmath.device.random.StatesXORWOW`.
43
+
44
+ First, create an array of states (one per thread) using
45
+ :class:`nvmath.device.random.StatesPhilox4_32_10` constructor.
46
+
47
+ >>> states = random.StatesPhilox4_32_10(nthreads)
48
+
49
+ Define a kernel to initialize the states. Each thread will initialize one element of
50
+ `states`. For the `Philox4_32_10
51
+ <https://docs.nvidia.com/cuda/curand/group__DEVICE.html#group__DEVICE_1ga613d37dacbc50494f2f859ef0d378b8>`_
52
+ generator, the `init` arguments are: `seed`, `subsequence`, `offset`.
53
+
54
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
55
+ ... def setup(states):
56
+ ... i = cuda.grid(1)
57
+ ... random.init(1234, i, 0, states[i])
58
+
59
+ Run the kernel to initialize the states:
60
+
61
+ >>> setup[blocks, threads](states)
62
+
63
+ Now, you can use the `states` array to generate random numbers using the random
64
+ samplers available.
65
+
66
+ For Sobol' family of quasirandom number generators, initialization is a bit more
67
+ complex as it requires preparing a set of *direction vectors* and *scramble
68
+ constants*. In this example, we will setup
69
+ :class:`nvmath.device.random.StatesScrambledSobol64` states.
70
+
71
+ Direction vectors can be obtained with
72
+ :func:`nvmath.device.random_helpers.get_direction_vectors64`:
73
+
74
+ >>> from nvmath.device import random_helpers
75
+ >>> hostVectors = random_helpers.get_direction_vectors64(
76
+ ... random.random_helpers.DirectionVectorSet.SCRAMBLED_DIRECTION_VECTORS_64_JOEKUO6, nthreads)
77
+ >>> sobolDirectionVectors = cuda.to_device(hostVectors)
78
+
79
+ To get scramble constants, use
80
+ :func:`nvmath.device.random_helpers.get_scramble_constants64`:
81
+
82
+ >>> hostScrambleConstants = random_helpers.get_scramble_constants64(nthreads)
83
+ >>> sobolScrambleConstants = cuda.to_device(hostScrambleConstants)
84
+
85
+ As `init` expects a pointer to direction vectors, we will use `cffi` to obtain it.
86
+
87
+ >>> states = random.StatesScrambledSobol64(nthreads)
88
+ >>>
89
+ >>> import cffi
90
+ >>> ffi = cffi.FFI()
91
+ >>>
92
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
93
+ ... def setup(sobolDirectionVectors, sobolScrambleConstants, states):
94
+ ... id = cuda.grid(1)
95
+ ... dirptr = ffi.from_buffer(sobolDirectionVectors[id:])
96
+ ... random.init(dirptr, sobolScrambleConstants[id], 1234, states[id])
97
+ """
98
+ _RAND_DOC = """rand(state)
99
+ Generate 32 or 64 bits of randomness depending on the provided bit generator.
100
+
101
+ Args:
102
+ state: a state object corresponding to one of the bit generators.
103
+
104
+ Returns:
105
+ 32 or 64 bits of randomness depending on the provided bit generator.
106
+ """
107
+ _RAND4_DOC = """rand4(state)
108
+ Generate a 4-tuple of 32-bits of randomness from a Philox4_32_10 generator.
109
+
110
+ Args:
111
+ state: a state object corresponding to the Philox4_32_10 generator.
112
+
113
+ Returns:
114
+ A 4-tuple of 32-bits of randomness from a Philox4_32_10 generator as an uint32x4 object.
115
+ """
116
+ _COMMON_APIS_DOC = [_INIT_DOC, _RAND_DOC, _RAND4_DOC]
117
+
118
+ # Bit generator state types.
119
+ _STATES = [
120
+ "StatesMRG32k3a",
121
+ "StatesPhilox4_32_10",
122
+ "StatesSobol32",
123
+ "StatesSobol64",
124
+ "StatesScrambledSobol32",
125
+ "StatesScrambledSobol64",
126
+ "StatesTest",
127
+ "StatesXORWOW",
128
+ ]
129
+
130
+ # Sampling from distributions.
131
+ _SAMPLERS_NORMAL = ["normal", "normal_double", "normal2", "normal2_double", "normal4"]
132
+ _SAMPLERS_LOG_NORMAL = ["log_normal", "log_normal_double", "log_normal2", "log_normal2_double", "log_normal4"]
133
+ _SAMPLERS_POISSON = ["poisson", "poisson4"]
134
+ _SAMPLERS_UNIFORM = ["uniform", "uniform_double", "uniform2_double", "uniform4"]
135
+ _SAMPLERS = _SAMPLERS_NORMAL + _SAMPLERS_LOG_NORMAL + _SAMPLERS_POISSON + _SAMPLERS_UNIFORM
136
+
137
+ # Skip ahead functions.
138
+ _SKIPPERS = ["skipahead", "skipahead_sequence", "skipahead_subsequence"]
139
+
140
+ # Templates.
141
+ _NUMBER_TO_WORD = {"": "a", "2": "two", "4": "four"}
142
+
143
+ _DTYPE_NAME_MAP = {"uint": "uint32", "float": "float32", "double": "float64"}
144
+
145
+ _SAMPLER_DESCRIPTION_TEMPLATE = r"""{name}(state{extra_arguments_str})
146
+ Sample {num_values_word} {dtype_word} from {distribution_word} distribution using the specified bit generator state.
147
+ {arg_docs}
148
+ {sampler_return}
149
+
150
+ Example:
151
+
152
+ The `states` parameter of the kernel below should be an array of already initialized bit generator states.
153
+ See the documentation of :func:`nvmath.device.random.init` for more details on how to create and initialize the
154
+ bit generator states.
155
+
156
+ >>> from numba import cuda
157
+ >>> from nvmath.device import random
158
+ >>> compiled_apis = random.Compile()
159
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
160
+ ... def kernel(states{extra_arguments_str}):
161
+ ... i = cuda.grid(1)
162
+ ... value = random.{name}(states[i]{extra_arguments_str})
163
+ """
164
+
165
+ _DISTRIBUTION_NAME_SPECIAL_CASES = {
166
+ "poisson": "Poisson",
167
+ "log_normal": "log-normal",
168
+ }
169
+
170
+ _SAMPLER_COMMON_ARGS_TEMPLATE = r"""
171
+
172
+ Args:
173
+ state: a state object corresponding to one of the bit generators.
174
+ """
175
+
176
+ _SAMPLER_RETURN_TEMPLATE = r"""
177
+
178
+ Returns:
179
+ A value of type :class:`{vector_type_description}`.
180
+ """
181
+
182
+ _STATES_DESCRIPTION_TEMPLATE = r"""
183
+ States of {generator_name} bit generator.
184
+
185
+ Once created, the states can be initialized by :func:`nvmath.device.random.init` function.
186
+ See the documentation of :func:`nvmath.device.random.init` for details and examples.
187
+ """
188
+
189
+
190
+ def _wrap(module, orig_name, new_name):
191
+ global functools
192
+
193
+ function = getattr(module, orig_name)
194
+ wrapped = functools.wraps(function)(function)
195
+ wrapped.__name__ = new_name
196
+ return wrapped
197
+
198
+
199
+ def _wrap_sampler(new_name, *, extra_arguments_list: list | None = None, extra_arguments_doc: list[str] | None = None):
200
+ global re
201
+ global curand_kernel
202
+
203
+ if extra_arguments_list is None:
204
+ extra_arguments_list = []
205
+ if extra_arguments_doc is None:
206
+ extra_arguments_doc = []
207
+ # Additional arguments for sampler, if any, other than 'state'.
208
+ num_extra_arguments = len(extra_arguments_list)
209
+ extra_arguments_str = "" if num_extra_arguments == 0 else ", {}".format(", ".join(extra_arguments_list))
210
+
211
+ # Infer data needed for the description template from the name.
212
+ m = re.match(r"([a-z_]+)([24])?(_([\w]+))?", new_name)
213
+ if m is None:
214
+ raise AssertionError(
215
+ f"Random sampler name '{new_name}' is invalid or unexpected. "
216
+ "The regex in nvmath.device.random.py should be updated."
217
+ )
218
+ # Distribution type.
219
+ distribution = m.group(1)
220
+ # Number of return values.
221
+ num_values = "" if m.group(2) is None else m.group(2)
222
+ num_values_word = _NUMBER_TO_WORD[num_values]
223
+ # The dtype of the return values.
224
+ dtype = m.group(4)
225
+ if match_dtype_in_name := re.match("(.*)_(float|double)", distribution):
226
+ # If dtype was parsed as a part of distribution name, extract it.
227
+ distribution = match_dtype_in_name.group(1)
228
+ dtype = match_dtype_in_name.group(2)
229
+ if not dtype:
230
+ # If dtype is not qualified in the name, uint for Poisson, float otherwise.
231
+ dtype = "uint" if distribution == "poisson" else "float"
232
+ distribution_word = _DISTRIBUTION_NAME_SPECIAL_CASES.get(distribution, distribution)
233
+ dtype_word = dtype + "s" if num_values else dtype
234
+
235
+ # Wrap function.
236
+ wrapped = _wrap(curand_kernel, "curand_" + new_name, new_name)
237
+
238
+ # Argument docs
239
+ arg_docs = _SAMPLER_COMMON_ARGS_TEMPLATE
240
+ for extra_argument, extra_argument_doc in zip(extra_arguments_list, extra_arguments_doc, strict=False):
241
+ arg_docs += f" {extra_argument}: {extra_argument_doc}.\n"
242
+
243
+ # Return docs
244
+ vector_type_description = _DTYPE_NAME_MAP[dtype]
245
+ if num_values:
246
+ vector_type_description = "nvmath.device." + vector_type_description + "x" + num_values
247
+ sampler_return = _SAMPLER_RETURN_TEMPLATE.format(vector_type_description=vector_type_description)
248
+
249
+ # Update docstring.
250
+ description = _SAMPLER_DESCRIPTION_TEMPLATE.format(
251
+ name=new_name,
252
+ extra_arguments_str=extra_arguments_str,
253
+ num_values_word=num_values_word,
254
+ distribution_word=distribution_word,
255
+ dtype_word=dtype_word,
256
+ arg_docs=arg_docs,
257
+ sampler_return=sampler_return,
258
+ )
259
+ wrapped.__doc__ = description
260
+
261
+ return wrapped
262
+
263
+
264
+ def _wrap_skipahead(name):
265
+ global re
266
+ global curand_kernel
267
+
268
+ # Infer data needed for the description template from the name.
269
+ m = re.match("skipahead(_([a-z]+))?", name)
270
+ skiptype = "element" if m.group(2) is None else m.group(2)
271
+
272
+ # Wrap function.
273
+ wrapped = _wrap(curand_kernel, name, name)
274
+
275
+ description = f"""{name}(n, state)
276
+ Update the bit generator state to skip ahead ``n`` {skiptype}s.
277
+
278
+ Args:
279
+ n: The number of {skiptype}s to skip ahead.
280
+ state: The bit generator state to update.
281
+ """
282
+ if skiptype != "element":
283
+ description += """
284
+ .. note::
285
+ For the XORWOW and Philox4_32_10 bit generators, the term *sequence* used in the API name and the argument `n`
286
+ essentially refers to the notion of *subsequence* in these algorithms.
287
+ """
288
+
289
+ # Update docstring.
290
+ wrapped.__doc__ = description
291
+
292
+ return wrapped
293
+
294
+
295
+ def _create_symbols():
296
+ global sys
297
+ global curand_kernel
298
+ global c_ext_shim_source
299
+
300
+ random_module = sys.modules[__name__]
301
+
302
+ # Wrap shim function.
303
+ c_ext_shim_source = _wrap(curand_kernel, "c_ext_shim_source", "c_ext_shim_source")
304
+
305
+ # Wrap common APIs.
306
+ for api, prefix, doc in zip(_COMMON_APIS, _COMMON_APIS_PREFIX, _COMMON_APIS_DOC, strict=True):
307
+ function = _wrap(curand_kernel, prefix + api, api)
308
+ function.__doc__ = doc
309
+ setattr(random_module, api, function)
310
+ # TODO: Update doc string for
311
+
312
+ # Wrap skipahead APIs.
313
+ for skipper in _SKIPPERS:
314
+ function = _wrap_skipahead(skipper)
315
+ setattr(random_module, skipper, function)
316
+
317
+ # Samplers with no extra arguments.
318
+ for sampler in _SAMPLERS_NORMAL + _SAMPLERS_UNIFORM:
319
+ function = _wrap_sampler(sampler)
320
+ setattr(random_module, sampler, function)
321
+
322
+ # The log_normal distribution requires two extra arguments.
323
+ extra_arguments_list = ["mean", "stddev"]
324
+ extra_arguments_doc = ["The mean value", "The standard deviation"]
325
+ for sampler in _SAMPLERS_LOG_NORMAL:
326
+ function = _wrap_sampler(sampler, extra_arguments_list=extra_arguments_list, extra_arguments_doc=extra_arguments_doc)
327
+ setattr(random_module, sampler, function)
328
+
329
+ # The poisson distribution requires an extra argument.
330
+ extra_arguments_list = ["Lambda"]
331
+ extra_arguments_doc = ["The parameter characterizing the Poisson distribution"]
332
+ for sampler in _SAMPLERS_POISSON:
333
+ function = _wrap_sampler(sampler, extra_arguments_list=extra_arguments_list, extra_arguments_doc=extra_arguments_doc)
334
+ setattr(random_module, sampler, function)
335
+
336
+
337
+ _create_symbols()
338
+
339
+
340
+ def _wrap_states():
341
+ global sys
342
+ global re
343
+ global states
344
+ global states_arg_handlers
345
+
346
+ random_module = sys.modules[__name__]
347
+
348
+ # Wrap arg handlers extension.
349
+ states_arg_handlers = states.states_arg_handlers
350
+
351
+ for s in _STATES:
352
+ setattr(random_module, s, getattr(states, "curand" + s))
353
+ state = getattr(random_module, s)
354
+ generator_name = re.match("States(.*)", s).group(1)
355
+ state.__doc__ = _STATES_DESCRIPTION_TEMPLATE.format(generator_name=generator_name)
356
+ state.__name__ = s
357
+
358
+
359
+ _wrap_states()
360
+
361
+
362
+ class Compile:
363
+ """
364
+ Compile the random device APIs with the specified compute capability.
365
+
366
+ The ``files`` and ``extension`` attributes should be used as the arguments for
367
+ :py:func:`numba.cuda.jit` decorator in Numba kernels which use random device APIs.
368
+
369
+ Args:
370
+ cc: (optional) the compute capability specified as an object of type
371
+ :py:class:`nvmath.device.ComputeCapability`. If not specified, the default
372
+ compute capability will be used.
373
+
374
+ Example:
375
+ >>> from numba import cuda
376
+ >>> from nvmath.device import random
377
+ >>> compiled_apis = random.Compile()
378
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
379
+ ... def kernel():
380
+ ... pass # use random device APIs here
381
+ """
382
+
383
+ def __init__(self, cc: nvmath.device.ComputeCapability | None = None):
384
+ global c_ext_shim_source
385
+
386
+ if cc is None:
387
+ cc = nvmath.device.common_cuda.get_default_code_type().cc
388
+ elif not isinstance(cc, nvmath.device.ComputeCapability):
389
+ raise ValueError(
390
+ f"The specified compute capability {cc} is not valid. "
391
+ "It must be an object of type :py:class:`nvmath.device.ComputeCapability`."
392
+ )
393
+ self.cc = cc
394
+
395
+ # Compile APIs to LTO-IR and materialize in 'files' for linking into Numba kernels.
396
+ _, self._lto = nvmath.device.nvrtc.compile(cpp=c_ext_shim_source.data, cc=self.cc, rdc=True, code="lto") # type: ignore
397
+ self._files = [nvmath.device.common.make_binary_tempfile(self._lto, ".ltoir")]
398
+
399
+ @property
400
+ def files(self):
401
+ """
402
+ The data needed to link random device APIs with Numba kernels.
403
+ """
404
+ return [f.name for f in self._files]
405
+
406
+ @property
407
+ def extension(self):
408
+ """
409
+ The extension needed to use random device APIs with Numba kernels.
410
+ """
411
+ global states_arg_handlers
412
+ return states_arg_handlers
413
+
414
+
415
+ __all__ = ["Compile", "random_helpers"] + _COMMON_APIS + _SAMPLERS + _SKIPPERS + _STATES
416
+
417
+ del functools, re, curand_kernel, states
@@ -0,0 +1,23 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Helper host APIs for random device APIs.
7
+ """
8
+
9
+ __all__ = [
10
+ "DirectionVectorSet",
11
+ "get_direction_vectors32",
12
+ "get_scramble_constants32",
13
+ "get_direction_vectors64",
14
+ "get_scramble_constants64",
15
+ ]
16
+
17
+ from nvmath.bindings.curand import ( # type: ignore
18
+ DirectionVectorSet,
19
+ get_direction_vectors32,
20
+ get_scramble_constants32,
21
+ get_direction_vectors64,
22
+ get_scramble_constants64,
23
+ )