nvmath-python 1.0.0__cp314-cp314t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +45 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/attribute_ifc_factory.py +330 -0
  5. nvmath/_internal/layout.py +70 -0
  6. nvmath/_internal/templates.py +130 -0
  7. nvmath/_internal/threadsafe.py +106 -0
  8. nvmath/_internal/utils.py +43 -0
  9. nvmath/_internal/workspace.py +490 -0
  10. nvmath/_utils.py +147 -0
  11. nvmath/bindings/__init__.py +60 -0
  12. nvmath/bindings/_internal/__init__.pxd +0 -0
  13. nvmath/bindings/_internal/__init__.py +0 -0
  14. nvmath/bindings/_internal/common_types.pxd +31 -0
  15. nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
  16. nvmath/bindings/_internal/cublas.pxd +530 -0
  17. nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
  18. nvmath/bindings/_internal/cublasLt.pxd +59 -0
  19. nvmath/bindings/_internal/cublasMp.pxd +52 -0
  20. nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
  21. nvmath/bindings/_internal/cudss.pxd +54 -0
  22. nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
  23. nvmath/bindings/_internal/cufft.pxd +70 -0
  24. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  25. nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/curand.pxd +42 -0
  27. nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/cusolver.pxd +15 -0
  29. nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
  30. nvmath/bindings/_internal/cusolverDn.pxd +406 -0
  31. nvmath/bindings/_internal/cusolverMp.pxd +71 -0
  32. nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
  33. nvmath/bindings/_internal/cusolverSp.pxd +75 -0
  34. nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
  35. nvmath/bindings/_internal/cusparse.pxd +471 -0
  36. nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
  37. nvmath/bindings/_internal/cusparseLt.pxd +48 -0
  38. nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
  39. nvmath/bindings/_internal/cutensor.pxd +58 -0
  40. nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
  41. nvmath/bindings/_internal/mathdx.pxd +116 -0
  42. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  43. nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
  44. nvmath/bindings/_internal/utils.pxd +174 -0
  45. nvmath/bindings/_internal/utils.pyi +10 -0
  46. nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
  47. nvmath/bindings/cublas.pxd +558 -0
  48. nvmath/bindings/cublas.pyi +812 -0
  49. nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
  50. nvmath/bindings/cublasLt.pxd +109 -0
  51. nvmath/bindings/cublasLt.pyi +1461 -0
  52. nvmath/bindings/cublasMp.pxd +85 -0
  53. nvmath/bindings/cublasMp.pyi +267 -0
  54. nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
  55. nvmath/bindings/cudss.pxd +98 -0
  56. nvmath/bindings/cudss.pyi +443 -0
  57. nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
  58. nvmath/bindings/cufft.pxd +118 -0
  59. nvmath/bindings/cufft.pyi +301 -0
  60. nvmath/bindings/cufftMp.pxd +124 -0
  61. nvmath/bindings/cufftMp.pyi +326 -0
  62. nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
  63. nvmath/bindings/curand.pxd +71 -0
  64. nvmath/bindings/curand.pyi +189 -0
  65. nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
  66. nvmath/bindings/cusolver.pxd +62 -0
  67. nvmath/bindings/cusolver.pyi +320 -0
  68. nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
  69. nvmath/bindings/cusolverDn.pxd +430 -0
  70. nvmath/bindings/cusolverDn.pyi +422 -0
  71. nvmath/bindings/cusolverMp.pxd +98 -0
  72. nvmath/bindings/cusolverMp.pyi +114 -0
  73. nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
  74. nvmath/bindings/cusolverSp.pxd +95 -0
  75. nvmath/bindings/cusolverSp.pyi +70 -0
  76. nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
  77. nvmath/bindings/cusparse.pxd +546 -0
  78. nvmath/bindings/cusparse.pyi +1017 -0
  79. nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
  80. nvmath/bindings/cusparseLt.pxd +99 -0
  81. nvmath/bindings/cusparseLt.pyi +252 -0
  82. nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
  83. nvmath/bindings/cutensor.pxd +98 -0
  84. nvmath/bindings/cutensor.pyi +324 -0
  85. nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
  86. nvmath/bindings/cycublas.pxd +664 -0
  87. nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
  88. nvmath/bindings/cycublasLt.pxd +1045 -0
  89. nvmath/bindings/cycublasMp.pxd +171 -0
  90. nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
  91. nvmath/bindings/cycudss.pxd +277 -0
  92. nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
  93. nvmath/bindings/cycufft.pxd +333 -0
  94. nvmath/bindings/cycufftMp.pxd +342 -0
  95. nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
  96. nvmath/bindings/cycurand.pxd +141 -0
  97. nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
  98. nvmath/bindings/cycusolver.pxd +137 -0
  99. nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
  100. nvmath/bindings/cycusolverDn.pxd +443 -0
  101. nvmath/bindings/cycusolverMp.pxd +107 -0
  102. nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
  103. nvmath/bindings/cycusolverSp.pxd +93 -0
  104. nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
  105. nvmath/bindings/cycusparse.pxd +679 -0
  106. nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
  107. nvmath/bindings/cycusparseLt.pxd +135 -0
  108. nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
  109. nvmath/bindings/cycutensor.pxd +189 -0
  110. nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
  111. nvmath/bindings/cymathdx.pxd +552 -0
  112. nvmath/bindings/cynvshmem.pxd +118 -0
  113. nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
  114. nvmath/bindings/mathdx.pxd +182 -0
  115. nvmath/bindings/mathdx.pyi +1562 -0
  116. nvmath/bindings/nvpl/__init__.pxd +0 -0
  117. nvmath/bindings/nvpl/__init__.py +13 -0
  118. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  119. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  120. nvmath/bindings/nvpl/_internal/blas.cp314t-win_amd64.pyd +0 -0
  121. nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
  122. nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
  123. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  124. nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
  125. nvmath/bindings/nvpl/blas.pxd +131 -0
  126. nvmath/bindings/nvpl/blas.pyi +168 -0
  127. nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
  128. nvmath/bindings/nvpl/cyblas.pxd +280 -0
  129. nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
  130. nvmath/bindings/nvpl/cyfft.pxd +93 -0
  131. nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
  132. nvmath/bindings/nvpl/fft.pxd +100 -0
  133. nvmath/bindings/nvpl/fft.pyi +168 -0
  134. nvmath/bindings/nvshmem.pxd +54 -0
  135. nvmath/bindings/nvshmem.pyi +191 -0
  136. nvmath/device/__init__.py +38 -0
  137. nvmath/device/_deprecated.py +33 -0
  138. nvmath/device/common.py +315 -0
  139. nvmath/device/common_backend.py +131 -0
  140. nvmath/device/common_cuda.py +201 -0
  141. nvmath/device/common_numba.py +300 -0
  142. nvmath/device/common_numba_cuda_mlir.py +202 -0
  143. nvmath/device/common_opaque_tensor.py +201 -0
  144. nvmath/device/cublasdx.py +1606 -0
  145. nvmath/device/cublasdx_backend.py +860 -0
  146. nvmath/device/cublasdx_numba.py +1534 -0
  147. nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
  148. nvmath/device/cufftdx.py +373 -0
  149. nvmath/device/cufftdx_backend.py +220 -0
  150. nvmath/device/cufftdx_numba.py +140 -0
  151. nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
  152. nvmath/device/curand_kernel.py +9147 -0
  153. nvmath/device/cusolverdx.py +2708 -0
  154. nvmath/device/cusolverdx_backend.py +440 -0
  155. nvmath/device/cusolverdx_numba.py +567 -0
  156. nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
  157. nvmath/device/cusolverdx_overload_backend.py +1029 -0
  158. nvmath/device/llvm_array.py +29 -0
  159. nvmath/device/random.py +441 -0
  160. nvmath/device/random_helpers.py +23 -0
  161. nvmath/device/random_states.py +187 -0
  162. nvmath/device/types.py +138 -0
  163. nvmath/device/vector_types_numba.py +259 -0
  164. nvmath/distributed/__init__.py +200 -0
  165. nvmath/distributed/_internal/__init__.py +0 -0
  166. nvmath/distributed/_internal/nccl.py +86 -0
  167. nvmath/distributed/_internal/nvshmem.py +307 -0
  168. nvmath/distributed/_internal/symmetric_memory.py +35 -0
  169. nvmath/distributed/_internal/tensor_ifc.py +70 -0
  170. nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
  171. nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
  172. nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
  173. nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
  174. nvmath/distributed/_internal/tensor_wrapper.py +81 -0
  175. nvmath/distributed/_utils.py +167 -0
  176. nvmath/distributed/distribution/__init__.py +30 -0
  177. nvmath/distributed/distribution/_configuration.py +39 -0
  178. nvmath/distributed/distribution/distributions.py +1024 -0
  179. nvmath/distributed/distribution/redistribute.py +1284 -0
  180. nvmath/distributed/fft/__init__.py +7 -0
  181. nvmath/distributed/fft/_configuration.py +82 -0
  182. nvmath/distributed/fft/fft.py +2742 -0
  183. nvmath/distributed/linalg/__init__.py +22 -0
  184. nvmath/distributed/linalg/_internal/__init__.py +3 -0
  185. nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -0
  186. nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
  187. nvmath/distributed/linalg/advanced/__init__.py +8 -0
  188. nvmath/distributed/linalg/advanced/_configuration.py +171 -0
  189. nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
  190. nvmath/distributed/linalg/generic/__init__.py +8 -0
  191. nvmath/distributed/linalg/generic/_caching.py +66 -0
  192. nvmath/distributed/linalg/generic/_configuration.py +61 -0
  193. nvmath/distributed/linalg/generic/_factorization.py +172 -0
  194. nvmath/distributed/linalg/generic/_initialization.py +966 -0
  195. nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
  196. nvmath/distributed/linalg/generic/solvermod.py +1368 -0
  197. nvmath/distributed/process_group.py +408 -0
  198. nvmath/fft/__init__.py +7 -0
  199. nvmath/fft/_configuration.py +189 -0
  200. nvmath/fft/_exec_utils.py +82 -0
  201. nvmath/fft/_helpers.py +237 -0
  202. nvmath/fft/fft.py +3122 -0
  203. nvmath/internal/__init__.pxd +3 -0
  204. nvmath/internal/__init__.py +10 -0
  205. nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
  206. nvmath/internal/_bindings.pxd +18 -0
  207. nvmath/internal/_device_utils.py +45 -0
  208. nvmath/internal/_layout/__init__.pxd +3 -0
  209. nvmath/internal/_layout/__init__.py +7 -0
  210. nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
  211. nvmath/internal/_layout/_layout.pxd +1303 -0
  212. nvmath/internal/_layout/_layout.pyi +1145 -0
  213. nvmath/internal/enum_utils.py +142 -0
  214. nvmath/internal/formatters.py +87 -0
  215. nvmath/internal/mem_limit.py +51 -0
  216. nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
  217. nvmath/internal/memory.pxd +13 -0
  218. nvmath/internal/memory.pyi +50 -0
  219. nvmath/internal/ndbuffer/__init__.pxd +3 -0
  220. nvmath/internal/ndbuffer/__init__.py +9 -0
  221. nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
  222. nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
  223. nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
  224. nvmath/internal/ndbuffer/_jit.pxd +7 -0
  225. nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
  226. nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
  227. nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -0
  228. nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
  229. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
  230. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
  231. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
  232. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +242 -0
  233. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
  234. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
  235. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
  236. nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
  237. nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
  238. nvmath/internal/package_ifc.py +168 -0
  239. nvmath/internal/package_ifc_cuda.py +57 -0
  240. nvmath/internal/package_ifc_cupy.py +67 -0
  241. nvmath/internal/package_ifc_torch.py +69 -0
  242. nvmath/internal/package_wrapper.py +14 -0
  243. nvmath/internal/tensor_ifc.py +179 -0
  244. nvmath/internal/tensor_ifc_cupy.py +234 -0
  245. nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
  246. nvmath/internal/tensor_ifc_numpy.py +184 -0
  247. nvmath/internal/tensor_ifc_torch.py +178 -0
  248. nvmath/internal/tensor_wrapper.py +160 -0
  249. nvmath/internal/typemaps.py +113 -0
  250. nvmath/internal/utils.py +805 -0
  251. nvmath/linalg/__init__.py +56 -0
  252. nvmath/linalg/_internal/__init__.py +3 -0
  253. nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
  254. nvmath/linalg/_internal/algo_config_ifc.py +43 -0
  255. nvmath/linalg/_internal/batch.py +234 -0
  256. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  257. nvmath/linalg/_internal/epilog_protocol.py +766 -0
  258. nvmath/linalg/_internal/layout.py +624 -0
  259. nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
  260. nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
  261. nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
  262. nvmath/linalg/_internal/solver_utils.py +432 -0
  263. nvmath/linalg/_internal/typemaps.py +144 -0
  264. nvmath/linalg/_internal/utils.py +157 -0
  265. nvmath/linalg/advanced/__init__.py +8 -0
  266. nvmath/linalg/advanced/_algorithmmod.py +170 -0
  267. nvmath/linalg/advanced/_configuration.py +351 -0
  268. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  269. nvmath/linalg/advanced/helpers/matmul.py +1316 -0
  270. nvmath/linalg/advanced/matmulmod.py +3734 -0
  271. nvmath/linalg/generic/__init__.py +53 -0
  272. nvmath/linalg/generic/_configuration/__init__.py +39 -0
  273. nvmath/linalg/generic/_configuration/layout.py +263 -0
  274. nvmath/linalg/generic/_configuration/match.py +734 -0
  275. nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
  276. nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
  277. nvmath/linalg/generic/_configuration/wrap.py +217 -0
  278. nvmath/linalg/generic/_dtype.py +15 -0
  279. nvmath/linalg/generic/matmulmod.py +2094 -0
  280. nvmath/linalg/generic/solvermod.py +1301 -0
  281. nvmath/memory.py +279 -0
  282. nvmath/sparse/__init__.py +38 -0
  283. nvmath/sparse/_internal/__init__.py +21 -0
  284. nvmath/sparse/_internal/common_utils.py +147 -0
  285. nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
  286. nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
  287. nvmath/sparse/_internal/cudss_utils.py +506 -0
  288. nvmath/sparse/_internal/cusparse_utils.py +382 -0
  289. nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
  290. nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
  291. nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
  292. nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
  293. nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
  294. nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
  295. nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
  296. nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
  297. nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
  298. nvmath/sparse/_internal/utils.py +56 -0
  299. nvmath/sparse/advanced/__init__.py +7 -0
  300. nvmath/sparse/advanced/_configuration.py +227 -0
  301. nvmath/sparse/advanced/direct_solver.py +2069 -0
  302. nvmath/sparse/generic/__init__.py +7 -0
  303. nvmath/sparse/generic/_configuration.py +129 -0
  304. nvmath/sparse/generic/_helpers.py +137 -0
  305. nvmath/sparse/generic/_thunks.py +21 -0
  306. nvmath/sparse/generic/matmulmod.py +2353 -0
  307. nvmath/sparse/ust/__init__.py +7 -0
  308. nvmath/sparse/ust/_converters.py +422 -0
  309. nvmath/sparse/ust/_cpp.py +28 -0
  310. nvmath/sparse/ust/_drawer.py +565 -0
  311. nvmath/sparse/ust/_emitter.py +1033 -0
  312. nvmath/sparse/ust/_jit.py +188 -0
  313. nvmath/sparse/ust/_kernel.py +282 -0
  314. nvmath/sparse/ust/_utils.py +149 -0
  315. nvmath/sparse/ust/interfaces/__init__.py +0 -0
  316. nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
  317. nvmath/sparse/ust/tensor.py +1016 -0
  318. nvmath/sparse/ust/tensor_format.py +957 -0
  319. nvmath/tensor/__init__.py +6 -0
  320. nvmath/tensor/_configuration.py +120 -0
  321. nvmath/tensor/_internal/__init__.py +3 -0
  322. nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
  323. nvmath/tensor/_internal/cutensor_utils.py +230 -0
  324. nvmath/tensor/_internal/data.py +43 -0
  325. nvmath/tensor/_internal/einsum_parser.py +444 -0
  326. nvmath/tensor/_internal/typemaps.py +96 -0
  327. nvmath/tensor/contract.py +1900 -0
  328. nvmath_python-1.0.0.dist-info/METADATA +134 -0
  329. nvmath_python-1.0.0.dist-info/RECORD +332 -0
  330. nvmath_python-1.0.0.dist-info/WHEEL +5 -0
  331. nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
  332. nvmath_python-1.0.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from llvmlite import ir
6
+ from numba.core.datamodel.manager import DataModelManager
7
+ from numba.core.datamodel.models import PrimitiveModel
8
+ from numba.cuda.extending import models, register_model, types
9
+
10
+
11
+ class LLVMArray(types.Array):
12
+ def __init__(self, dtype, size):
13
+ super().__init__(dtype, layout="C", ndim=1)
14
+ self.size = size
15
+
16
+ def __str__(self):
17
+ return f"LLVMArray(dtype={self.dtype}, size={self.size})"
18
+
19
+ def __repr__(self):
20
+ return f"LLVMArray(dtype={self.dtype}, size={self.size})"
21
+
22
+
23
+ @register_model(LLVMArray)
24
+ class LLVMArrayModel(models.PrimitiveModel):
25
+ def __init__(self, dmm: DataModelManager, fe_type: LLVMArray):
26
+ dtype_model: PrimitiveModel = dmm.lookup(fe_type.dtype)
27
+ llvm_type = dtype_model.be_type
28
+ be_type = ir.ArrayType(llvm_type, fe_type.size)
29
+ super().__init__(dmm, fe_type, be_type)
@@ -0,0 +1,441 @@
1
+ # Copyright (c) 2024-2026, 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
+ import weakref
15
+
16
+ from cuda import pathfinder
17
+ from cuda.core import ObjectCode, Program, ProgramOptions
18
+
19
+ import nvmath.device
20
+ from nvmath.device import curand_kernel, random_helpers
21
+ from nvmath.device import random_states as states
22
+
23
+ # Common APIs (initialization, bit generation).
24
+ _COMMON_APIS = ["init", "rand", "rand4"]
25
+ _COMMON_APIS_PREFIX = ["curand_", "cu", "cu"]
26
+ _INIT_DOC = """init(..., state)
27
+ Initialize the RNG state.
28
+
29
+ The arguments depend upon the selected bit generator (see the overloads of `curand_init`
30
+ in `cuRAND docs <https://docs.nvidia.com/cuda/curand/group__DEVICE.html>`_).
31
+
32
+ Example:
33
+
34
+ >>> from numba import cuda
35
+ >>> from nvmath.device import random
36
+ >>> compiled_apis = random.Compile(cc=None)
37
+
38
+ We will be working on a grid of 64 blocks, with 64 threads in each.
39
+
40
+ >>> threads = 64
41
+ >>> blocks = 64
42
+ >>> nthreads = blocks * threads
43
+
44
+ Let us show how to use `init` with :class:`nvmath.device.random.StatesPhilox4_32_10`
45
+ states. The same applies to :class:`nvmath.device.random.StatesMRG32k3a` and
46
+ :class:`nvmath.device.random.StatesXORWOW`.
47
+
48
+ First, create an array of states (one per thread) using
49
+ :class:`nvmath.device.random.StatesPhilox4_32_10` constructor.
50
+
51
+ >>> states = random.StatesPhilox4_32_10(nthreads)
52
+
53
+ Define a kernel to initialize the states. Each thread will initialize one element of
54
+ `states`. For the `Philox4_32_10
55
+ <https://docs.nvidia.com/cuda/curand/group__DEVICE.html#group__DEVICE_1ga613d37dacbc50494f2f859ef0d378b8>`_
56
+ generator, the `init` arguments are: `seed`, `subsequence`, `offset`.
57
+
58
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
59
+ ... def setup(states):
60
+ ... i = cuda.grid(1)
61
+ ... random.init(1234, i, 0, states[i])
62
+
63
+ Run the kernel to initialize the states:
64
+
65
+ >>> setup[blocks, threads](states)
66
+
67
+ Now, you can use the `states` array to generate random numbers using the random
68
+ samplers available.
69
+
70
+ For Sobol' family of quasirandom number generators, initialization is a bit more
71
+ complex as it requires preparing a set of *direction vectors* and *scramble
72
+ constants*. In this example, we will setup
73
+ :class:`nvmath.device.random.StatesScrambledSobol64` states.
74
+
75
+ Direction vectors can be obtained with
76
+ :func:`nvmath.device.random_helpers.get_direction_vectors64`:
77
+
78
+ >>> from nvmath.device import random_helpers
79
+ >>> hostVectors = random_helpers.get_direction_vectors64(
80
+ ... random.random_helpers.DirectionVectorSet.SCRAMBLED_DIRECTION_VECTORS_64_JOEKUO6, nthreads)
81
+ >>> sobolDirectionVectors = cuda.to_device(hostVectors)
82
+
83
+ To get scramble constants, use
84
+ :func:`nvmath.device.random_helpers.get_scramble_constants64`:
85
+
86
+ >>> hostScrambleConstants = random_helpers.get_scramble_constants64(nthreads)
87
+ >>> sobolScrambleConstants = cuda.to_device(hostScrambleConstants)
88
+
89
+ As `init` expects a pointer to direction vectors, we will use `cffi` to obtain it.
90
+
91
+ >>> states = random.StatesScrambledSobol64(nthreads)
92
+ >>>
93
+ >>> import cffi
94
+ >>> ffi = cffi.FFI()
95
+ >>>
96
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
97
+ ... def setup(sobolDirectionVectors, sobolScrambleConstants, states):
98
+ ... id = cuda.grid(1)
99
+ ... dirptr = ffi.from_buffer(sobolDirectionVectors[id:])
100
+ ... random.init(dirptr, sobolScrambleConstants[id], 1234, states[id])
101
+ """
102
+ _RAND_DOC = """rand(state)
103
+ Generate 32 or 64 bits of randomness depending on the provided bit generator.
104
+
105
+ Args:
106
+ state: a state object corresponding to one of the bit generators.
107
+
108
+ Returns:
109
+ 32 or 64 bits of randomness depending on the provided bit generator.
110
+ """
111
+ _RAND4_DOC = """rand4(state)
112
+ Generate a 4-tuple of 32-bits of randomness from a Philox4_32_10 generator.
113
+
114
+ Args:
115
+ state: a state object corresponding to the Philox4_32_10 generator.
116
+
117
+ Returns:
118
+ A 4-tuple of 32-bits of randomness from a Philox4_32_10 generator as an uint32x4 object.
119
+ """
120
+ _COMMON_APIS_DOC = [_INIT_DOC, _RAND_DOC, _RAND4_DOC]
121
+
122
+ # Bit generator state types.
123
+ _STATES = [
124
+ "StatesMRG32k3a",
125
+ "StatesPhilox4_32_10",
126
+ "StatesSobol32",
127
+ "StatesSobol64",
128
+ "StatesScrambledSobol32",
129
+ "StatesScrambledSobol64",
130
+ "StatesTest",
131
+ "StatesXORWOW",
132
+ ]
133
+
134
+ # Sampling from distributions.
135
+ _SAMPLERS_NORMAL = ["normal", "normal_double", "normal2", "normal2_double", "normal4"]
136
+ _SAMPLERS_LOG_NORMAL = ["log_normal", "log_normal_double", "log_normal2", "log_normal2_double", "log_normal4"]
137
+ _SAMPLERS_POISSON = ["poisson", "poisson4"]
138
+ _SAMPLERS_UNIFORM = ["uniform", "uniform_double", "uniform2_double", "uniform4"]
139
+ _SAMPLERS = _SAMPLERS_NORMAL + _SAMPLERS_LOG_NORMAL + _SAMPLERS_POISSON + _SAMPLERS_UNIFORM
140
+
141
+ # Skip ahead functions.
142
+ _SKIPPERS = ["skipahead", "skipahead_sequence", "skipahead_subsequence"]
143
+
144
+ # Templates.
145
+ _NUMBER_TO_WORD = {"": "a", "2": "two", "4": "four"}
146
+
147
+ _DTYPE_NAME_MAP = {"uint": "uint32", "float": "float32", "double": "float64"}
148
+
149
+ _SAMPLER_DESCRIPTION_TEMPLATE = r"""{name}(state{extra_arguments_str})
150
+ Sample {num_values_word} {dtype_word} from {distribution_word} distribution using the specified bit generator state.
151
+ {arg_docs}
152
+ {sampler_return}
153
+
154
+ Example:
155
+
156
+ The `states` parameter of the kernel below should be an array of already initialized bit generator states.
157
+ See the documentation of :func:`nvmath.device.random.init` for more details on how to create and initialize the
158
+ bit generator states.
159
+
160
+ >>> from numba import cuda
161
+ >>> from nvmath.device import random
162
+ >>> compiled_apis = random.Compile()
163
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
164
+ ... def kernel(states{extra_arguments_str}):
165
+ ... i = cuda.grid(1)
166
+ ... value = random.{name}(states[i]{extra_arguments_str})
167
+ """
168
+
169
+ _DISTRIBUTION_NAME_SPECIAL_CASES = {
170
+ "poisson": "Poisson",
171
+ "log_normal": "log-normal",
172
+ }
173
+
174
+ _SAMPLER_COMMON_ARGS_TEMPLATE = r"""
175
+
176
+ Args:
177
+ state: a state object corresponding to one of the bit generators.
178
+ """
179
+
180
+ _SAMPLER_RETURN_TEMPLATE = r"""
181
+
182
+ Returns:
183
+ A value of type :class:`{vector_type_description}`.
184
+ """
185
+
186
+ _STATES_DESCRIPTION_TEMPLATE = r"""
187
+ States of {generator_name} bit generator.
188
+
189
+ Once created, the states can be initialized by :func:`nvmath.device.random.init` function.
190
+ See the documentation of :func:`nvmath.device.random.init` for details and examples.
191
+ """
192
+
193
+
194
+ def _wrap(module, orig_name, new_name):
195
+ global functools
196
+
197
+ function = getattr(module, orig_name)
198
+ wrapped = functools.wraps(function)(function)
199
+ wrapped.__name__ = new_name
200
+ return wrapped
201
+
202
+
203
+ def _wrap_sampler(new_name, *, extra_arguments_list: list | None = None, extra_arguments_doc: list[str] | None = None):
204
+ global re
205
+ global curand_kernel
206
+
207
+ if extra_arguments_list is None:
208
+ extra_arguments_list = []
209
+ if extra_arguments_doc is None:
210
+ extra_arguments_doc = []
211
+ # Additional arguments for sampler, if any, other than 'state'.
212
+ num_extra_arguments = len(extra_arguments_list)
213
+ extra_arguments_str = "" if num_extra_arguments == 0 else ", {}".format(", ".join(extra_arguments_list))
214
+
215
+ # Infer data needed for the description template from the name.
216
+ m = re.match(r"([a-z_]+)([24])?(_([\w]+))?", new_name)
217
+ if m is None:
218
+ raise AssertionError(
219
+ f"Random sampler name '{new_name}' is invalid or unexpected. "
220
+ "The regex in nvmath.device.random.py should be updated."
221
+ )
222
+ # Distribution type.
223
+ distribution = m.group(1)
224
+ # Number of return values.
225
+ num_values = "" if m.group(2) is None else m.group(2)
226
+ num_values_word = _NUMBER_TO_WORD[num_values]
227
+ # The dtype of the return values.
228
+ dtype = m.group(4)
229
+ if match_dtype_in_name := re.match("(.*)_(float|double)", distribution):
230
+ # If dtype was parsed as a part of distribution name, extract it.
231
+ distribution = match_dtype_in_name.group(1)
232
+ dtype = match_dtype_in_name.group(2)
233
+ if not dtype:
234
+ # If dtype is not qualified in the name, uint for Poisson, float otherwise.
235
+ dtype = "uint" if distribution == "poisson" else "float"
236
+ distribution_word = _DISTRIBUTION_NAME_SPECIAL_CASES.get(distribution, distribution)
237
+ dtype_word = dtype + "s" if num_values else dtype
238
+
239
+ # Wrap function.
240
+ wrapped = _wrap(curand_kernel, "curand_" + new_name, new_name)
241
+
242
+ # Argument docs
243
+ arg_docs = _SAMPLER_COMMON_ARGS_TEMPLATE
244
+ for extra_argument, extra_argument_doc in zip(extra_arguments_list, extra_arguments_doc, strict=False):
245
+ arg_docs += f" {extra_argument}: {extra_argument_doc}.\n"
246
+
247
+ # Return docs
248
+ vector_type_description = _DTYPE_NAME_MAP[dtype]
249
+ if num_values:
250
+ vector_type_description = "nvmath.device." + vector_type_description + "x" + num_values
251
+ sampler_return = _SAMPLER_RETURN_TEMPLATE.format(vector_type_description=vector_type_description)
252
+
253
+ # Update docstring.
254
+ description = _SAMPLER_DESCRIPTION_TEMPLATE.format(
255
+ name=new_name,
256
+ extra_arguments_str=extra_arguments_str,
257
+ num_values_word=num_values_word,
258
+ distribution_word=distribution_word,
259
+ dtype_word=dtype_word,
260
+ arg_docs=arg_docs,
261
+ sampler_return=sampler_return,
262
+ )
263
+ wrapped.__doc__ = description
264
+
265
+ return wrapped
266
+
267
+
268
+ def _wrap_skipahead(name):
269
+ global re
270
+ global curand_kernel
271
+
272
+ # Infer data needed for the description template from the name.
273
+ m = re.match("skipahead(_([a-z]+))?", name)
274
+ skiptype = "element" if m.group(2) is None else m.group(2)
275
+
276
+ # Wrap function.
277
+ wrapped = _wrap(curand_kernel, name, name)
278
+
279
+ description = f"""{name}(n, state)
280
+ Update the bit generator state to skip ahead ``n`` {skiptype}s.
281
+
282
+ Args:
283
+ n: The number of {skiptype}s to skip ahead.
284
+ state: The bit generator state to update.
285
+ """
286
+ if skiptype != "element":
287
+ description += """
288
+ .. note::
289
+ For the XORWOW and Philox4_32_10 bit generators, the term *sequence* used in the API name and the argument `n`
290
+ essentially refers to the notion of *subsequence* in these algorithms.
291
+ """
292
+
293
+ # Update docstring.
294
+ wrapped.__doc__ = description
295
+
296
+ return wrapped
297
+
298
+
299
+ def _create_symbols():
300
+ global sys
301
+ global curand_kernel
302
+ global c_ext_shim_source
303
+
304
+ random_module = sys.modules[__name__]
305
+
306
+ # Wrap shim function.
307
+ c_ext_shim_source = _wrap(curand_kernel, "c_ext_shim_source", "c_ext_shim_source")
308
+
309
+ # Wrap common APIs.
310
+ for api, prefix, doc in zip(_COMMON_APIS, _COMMON_APIS_PREFIX, _COMMON_APIS_DOC, strict=True):
311
+ function = _wrap(curand_kernel, prefix + api, api)
312
+ function.__doc__ = doc
313
+ setattr(random_module, api, function)
314
+ # TODO: Update doc string for
315
+
316
+ # Wrap skipahead APIs.
317
+ for skipper in _SKIPPERS:
318
+ function = _wrap_skipahead(skipper)
319
+ setattr(random_module, skipper, function)
320
+
321
+ # Samplers with no extra arguments.
322
+ for sampler in _SAMPLERS_NORMAL + _SAMPLERS_UNIFORM:
323
+ function = _wrap_sampler(sampler)
324
+ setattr(random_module, sampler, function)
325
+
326
+ # The log_normal distribution requires two extra arguments.
327
+ extra_arguments_list = ["mean", "stddev"]
328
+ extra_arguments_doc = ["The mean value", "The standard deviation"]
329
+ for sampler in _SAMPLERS_LOG_NORMAL:
330
+ function = _wrap_sampler(sampler, extra_arguments_list=extra_arguments_list, extra_arguments_doc=extra_arguments_doc)
331
+ setattr(random_module, sampler, function)
332
+
333
+ # The poisson distribution requires an extra argument.
334
+ extra_arguments_list = ["Lambda"]
335
+ extra_arguments_doc = ["The parameter characterizing the Poisson distribution"]
336
+ for sampler in _SAMPLERS_POISSON:
337
+ function = _wrap_sampler(sampler, extra_arguments_list=extra_arguments_list, extra_arguments_doc=extra_arguments_doc)
338
+ setattr(random_module, sampler, function)
339
+
340
+
341
+ _create_symbols()
342
+
343
+
344
+ def _wrap_states():
345
+ global sys
346
+ global re
347
+ global states
348
+ global states_arg_handlers
349
+
350
+ random_module = sys.modules[__name__]
351
+
352
+ # Wrap arg handlers extension.
353
+ states_arg_handlers = states.states_arg_handlers
354
+
355
+ for s in _STATES:
356
+ setattr(random_module, s, getattr(states, "curand" + s))
357
+ state = getattr(random_module, s)
358
+ generator_name = re.match("States(.*)", s).group(1)
359
+ state.__doc__ = _STATES_DESCRIPTION_TEMPLATE.format(generator_name=generator_name)
360
+ state.__name__ = s
361
+
362
+
363
+ _wrap_states()
364
+
365
+
366
+ class Compile:
367
+ """
368
+ Compile the random device APIs with the specified compute capability.
369
+
370
+ The ``files`` and ``extension`` attributes should be used as the arguments for
371
+ :py:func:`numba.cuda.jit` decorator in Numba kernels which use random device APIs.
372
+
373
+ Args:
374
+ cc: (optional) the compute capability specified as an object of type
375
+ :py:class:`nvmath.device.ComputeCapability`. If not specified, the default
376
+ compute capability will be used.
377
+
378
+ Example:
379
+ >>> from numba import cuda
380
+ >>> from nvmath.device import random
381
+ >>> compiled_apis = random.Compile()
382
+ >>> @cuda.jit(link=compiled_apis.files, extensions=compiled_apis.extension)
383
+ ... def kernel():
384
+ ... pass # use random device APIs here
385
+ """
386
+
387
+ def __init__(self, cc: nvmath.device.ComputeCapability | None = None):
388
+ global c_ext_shim_source
389
+
390
+ if cc is None:
391
+ cc = nvmath.device.common_cuda.get_default_code_type().cc
392
+ elif not isinstance(cc, nvmath.device.ComputeCapability):
393
+ raise ValueError(
394
+ f"The specified compute capability {cc} is not valid. "
395
+ "It must be an object of type :py:class:`nvmath.device.ComputeCapability`."
396
+ )
397
+ self.cc = cc
398
+
399
+ # Compile APIs to LTO-IR and materialize in 'files' for linking into Numba kernels.
400
+ prog = Program(
401
+ c_ext_shim_source.data, # type: ignore
402
+ "c++",
403
+ ProgramOptions(
404
+ std="c++17",
405
+ arch=f"compute_{cc.major * 10 + cc.minor}",
406
+ device_as_default_execution_space=True,
407
+ link_time_optimization=True,
408
+ gen_opt_lto=True,
409
+ relocatable_device_code=True,
410
+ include_path=[
411
+ pathfinder.find_nvidia_header_directory("cudart"),
412
+ pathfinder.find_nvidia_header_directory("cccl"),
413
+ ],
414
+ ),
415
+ )
416
+ obj = prog.compile("ltoir")
417
+ assert isinstance(obj, ObjectCode)
418
+ self._lto = obj.code
419
+ self._files = [nvmath.device.common.make_binary_tempfile(self._lto, ".ltoir")]
420
+
421
+ self._finalizer = weakref.finalize(self, nvmath.device.common.delete_binary_tempfiles, self.files)
422
+
423
+ @property
424
+ def files(self):
425
+ """
426
+ The data needed to link random device APIs with Numba kernels.
427
+ """
428
+ return [f.name for f in self._files]
429
+
430
+ @property
431
+ def extension(self):
432
+ """
433
+ The extension needed to use random device APIs with Numba kernels.
434
+ """
435
+ global states_arg_handlers
436
+ return states_arg_handlers
437
+
438
+
439
+ __all__ = ["Compile", "random_helpers"] + _COMMON_APIS + _SAMPLERS + _SKIPPERS + _STATES # type: ignore # noqa: PLE0605
440
+
441
+ del functools, re, curand_kernel, states
@@ -0,0 +1,23 @@
1
+ # Copyright (c) 2024-2026, 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_direction_vectors64,
21
+ get_scramble_constants32,
22
+ get_scramble_constants64,
23
+ )
@@ -0,0 +1,187 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import operator
6
+
7
+ import numpy as np
8
+ from llvmlite import ir
9
+ from numba import cuda, types
10
+ from numba.core.typing.templates import AbstractTemplate, signature
11
+ from numba.cuda.cudadecl import register_global
12
+ from numba.cuda.cudaimpl import lower
13
+ from numba.extending import models, register_model, typeof_impl
14
+
15
+ from nvmath.device import curand_kernel
16
+
17
+ xorwow_dtype = np.dtype(
18
+ [
19
+ ("d", np.uint32),
20
+ ("v", np.uint32, (5,)),
21
+ ("boxmuller_flag", np.int32),
22
+ ("boxmuller_flag_double", np.int32),
23
+ ("boxmuller_extra", np.float32),
24
+ ("boxmuller_extra_double", np.float64),
25
+ ],
26
+ align=True,
27
+ )
28
+ test_dtype = np.dtype([("v", np.uint32)], align=True)
29
+ mrg32k3a_dtype = np.dtype(
30
+ [
31
+ ("s1", np.uint32, (3,)),
32
+ ("s2", np.uint32, (3,)),
33
+ ("boxmuller_flag", np.int32),
34
+ ("boxmuller_flag_double", np.int32),
35
+ ("boxmuller_extra", np.float32),
36
+ ("boxmuller_extra_double", np.float64),
37
+ ],
38
+ align=True,
39
+ )
40
+ sobol32_dtype = np.dtype(
41
+ [("i", np.uint32), ("x", np.uint32), ("c", np.uint32), ("direction_vectors", np.int32, (32,))], align=True
42
+ )
43
+ scrambled_sobol32_dtype = np.dtype(
44
+ [("i", np.uint32), ("x", np.uint32), ("c", np.uint32), ("direction_vectors", np.int32, (32,))], align=True
45
+ )
46
+ sobol64_dtype = np.dtype(
47
+ [("i", np.uint64), ("x", np.uint64), ("c", np.uint64), ("direction_vectors", np.int64, (64,))], align=True
48
+ )
49
+ scrambled_sobol64_dtype = np.dtype(
50
+ [("i", np.uint64), ("x", np.uint64), ("c", np.uint64), ("direction_vectors", np.int64, (64,))], align=True
51
+ )
52
+ philox4_32_10_dtype = np.dtype(
53
+ [
54
+ ("ctr", np.uint32, (4,)),
55
+ ("output", np.uint32, (4,)),
56
+ ("key", np.uint32, (2,)),
57
+ ("STATE", np.uint32),
58
+ ("boxmuller_flag", np.int32),
59
+ ("boxmuller_flag_double", np.int32),
60
+ ("boxmuller_extra", np.float32),
61
+ ("boxmuller_extra_double", np.float64),
62
+ ],
63
+ align=True,
64
+ )
65
+
66
+ NP_DTYPES = {
67
+ "curandStateXORWOW": xorwow_dtype,
68
+ "curandStateTest": test_dtype,
69
+ "curandStateMRG32k3a": mrg32k3a_dtype,
70
+ "curandStateSobol32": sobol32_dtype,
71
+ "curandStateScrambledSobol32": scrambled_sobol32_dtype,
72
+ "curandStateSobol64": sobol64_dtype,
73
+ "curandStateScrambledSobol64": scrambled_sobol64_dtype,
74
+ "curandStatePhilox4_32_10": philox4_32_10_dtype,
75
+ }
76
+
77
+
78
+ def make_curand_states(name: str):
79
+ """Create a boxed curand states object to represent an array of curand state.
80
+ Should invoke after creating the numba types for each curand state.
81
+ """
82
+
83
+ curand_state_name = name
84
+
85
+ state_ty = getattr(curand_kernel, f"_type_{curand_state_name}")
86
+
87
+ curand_states_name = curand_state_name.replace("State", "States")
88
+
89
+ # cuRAND state type as a NumPy dtype - this mirrors the state defined in
90
+ # curand_kernel.h. Can be used to inspect the state through the device array
91
+ # held by CurandStates.
92
+
93
+ curandStateDtype = NP_DTYPES[curand_state_name]
94
+
95
+ # Hold an array of cuRAND states - somewhat analogous to a curandState* in
96
+ # C/C++.
97
+
98
+ class CurandStates:
99
+ def __init__(self, n):
100
+ self._array = cuda.device_array(n, dtype=curandStateDtype)
101
+
102
+ @property
103
+ def data(self):
104
+ return self._array.__cuda_array_interface__["data"][0]
105
+
106
+ CurandStates.__name__ = curand_states_name
107
+
108
+ class CurandStatePointer(types.Type):
109
+ def __init__(self, name):
110
+ self.dtype = state_ty
111
+ super().__init__(name=name)
112
+
113
+ curand_state_pointer = CurandStatePointer(curand_states_name + "*")
114
+
115
+ @typeof_impl.register(CurandStates)
116
+ def typeof_curand_states(val, c):
117
+ return curand_state_pointer
118
+
119
+ @register_global(operator.getitem)
120
+ class CurandStatesPointerGetItem(AbstractTemplate):
121
+ def generic(self, args, kws):
122
+ assert not kws
123
+ [ptr, idx] = args
124
+ if ptr == curand_state_pointer:
125
+ return signature(types.CPointer(state_ty), curand_state_pointer, types.int64)
126
+
127
+ register_model(CurandStatePointer)(models.PointerModel)
128
+
129
+ @lower(operator.getitem, curand_state_pointer, types.int64)
130
+ def lower_curand_states_getitem(context, builder, sig, args):
131
+ [ptr, idx] = args
132
+
133
+ # Working out my own GEP
134
+ ptrint = builder.ptrtoint(ptr, ir.IntType(64))
135
+ itemsize = curandStateDtype.itemsize
136
+ offset = builder.mul(idx, context.get_constant(types.int64, itemsize))
137
+ ptrint = builder.add(ptrint, offset)
138
+ ptr = builder.inttoptr(ptrint, ptr.type)
139
+ return ptr
140
+
141
+ # Argument handling. When a CurandStatePointer is passed into a kernel, we
142
+ # really only need to pass the pointer to the data, not the whole underlying
143
+ # array structure. Our handler here transforms these arguments into a uint64
144
+ # holding the pointer.
145
+
146
+ class CurandStateArgHandler:
147
+ def prepare_args(self, ty, val, **kwargs):
148
+ if isinstance(val, CurandStates):
149
+ assert ty == curand_state_pointer
150
+ return types.uint64, val.data
151
+ else:
152
+ return ty, val
153
+
154
+ curand_state_arg_handler = CurandStateArgHandler()
155
+
156
+ return CurandStates, curand_state_arg_handler
157
+
158
+
159
+ curandStates = [
160
+ "curandStateTest",
161
+ "curandStateXORWOW",
162
+ "curandStateMRG32k3a",
163
+ "curandStateSobol32",
164
+ "curandStateScrambledSobol32",
165
+ "curandStateSobol64",
166
+ "curandStateScrambledSobol64",
167
+ "curandStatePhilox4_32_10",
168
+ # Require additional type parsing of mtgp32_params_fast and mtgp32_kernel_params
169
+ # "curandStateMtgp32",
170
+ ]
171
+
172
+ numpy_curand_states = []
173
+ states_arg_handlers = []
174
+
175
+ for state in curandStates:
176
+ states_obj, arg_handler = make_curand_states(state)
177
+ numpy_curand_states.append(states_obj)
178
+ states_arg_handlers.append(arg_handler)
179
+
180
+
181
+ # Export
182
+ globals().update({s.__name__: s for s in numpy_curand_states})
183
+ globals().update({"states_arg_handlers": states_arg_handlers})
184
+
185
+ __all__ = list( # noqa: F822
186
+ {s.__name__ for s in numpy_curand_states} | {"states_arg_handlers"}
187
+ )