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.
- nvmath/__init__.pxd +0 -0
- nvmath/__init__.py +45 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/attribute_ifc_factory.py +330 -0
- nvmath/_internal/layout.py +70 -0
- nvmath/_internal/templates.py +130 -0
- nvmath/_internal/threadsafe.py +106 -0
- nvmath/_internal/utils.py +43 -0
- nvmath/_internal/workspace.py +490 -0
- nvmath/_utils.py +147 -0
- nvmath/bindings/__init__.py +60 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/common_types.pxd +31 -0
- nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +54 -0
- nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusolverMp.pxd +71 -0
- nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverSp.pxd +75 -0
- nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +471 -0
- nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +174 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +812 -0
- nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1461 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +267 -0
- nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +98 -0
- nvmath/bindings/cudss.pyi +443 -0
- nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +301 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +326 -0
- nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +189 -0
- nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +320 -0
- nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +422 -0
- nvmath/bindings/cusolverMp.pxd +98 -0
- nvmath/bindings/cusolverMp.pyi +114 -0
- nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverSp.pxd +95 -0
- nvmath/bindings/cusolverSp.pyi +70 -0
- nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +546 -0
- nvmath/bindings/cusparse.pyi +1017 -0
- nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +252 -0
- nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +324 -0
- nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +664 -0
- nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1045 -0
- nvmath/bindings/cycublasMp.pxd +171 -0
- nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +277 -0
- nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +333 -0
- nvmath/bindings/cycufftMp.pxd +342 -0
- nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +141 -0
- nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +137 -0
- nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +443 -0
- nvmath/bindings/cycusolverMp.pxd +107 -0
- nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverSp.pxd +93 -0
- nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +679 -0
- nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +135 -0
- nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +189 -0
- nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +118 -0
- nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1562 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +13 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/blas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
- nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +131 -0
- nvmath/bindings/nvpl/blas.pyi +168 -0
- nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +280 -0
- nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +93 -0
- nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +168 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +191 -0
- nvmath/device/__init__.py +38 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +315 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +300 -0
- nvmath/device/common_numba_cuda_mlir.py +202 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1606 -0
- nvmath/device/cublasdx_backend.py +860 -0
- nvmath/device/cublasdx_numba.py +1534 -0
- nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
- nvmath/device/cufftdx.py +373 -0
- nvmath/device/cufftdx_backend.py +220 -0
- nvmath/device/cufftdx_numba.py +140 -0
- nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2708 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +567 -0
- nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
- nvmath/device/cusolverdx_overload_backend.py +1029 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +441 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +138 -0
- nvmath/device/vector_types_numba.py +259 -0
- nvmath/distributed/__init__.py +200 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nccl.py +86 -0
- nvmath/distributed/_internal/nvshmem.py +307 -0
- nvmath/distributed/_internal/symmetric_memory.py +35 -0
- nvmath/distributed/_internal/tensor_ifc.py +70 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
- nvmath/distributed/_internal/tensor_wrapper.py +81 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution/__init__.py +30 -0
- nvmath/distributed/distribution/_configuration.py +39 -0
- nvmath/distributed/distribution/distributions.py +1024 -0
- nvmath/distributed/distribution/redistribute.py +1284 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +82 -0
- nvmath/distributed/fft/fft.py +2742 -0
- nvmath/distributed/linalg/__init__.py +22 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -0
- nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/distributed/linalg/advanced/__init__.py +8 -0
- nvmath/distributed/linalg/advanced/_configuration.py +171 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
- nvmath/distributed/linalg/generic/__init__.py +8 -0
- nvmath/distributed/linalg/generic/_caching.py +66 -0
- nvmath/distributed/linalg/generic/_configuration.py +61 -0
- nvmath/distributed/linalg/generic/_factorization.py +172 -0
- nvmath/distributed/linalg/generic/_initialization.py +966 -0
- nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
- nvmath/distributed/linalg/generic/solvermod.py +1368 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +189 -0
- nvmath/fft/_exec_utils.py +82 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +3122 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +18 -0
- nvmath/internal/_device_utils.py +45 -0
- nvmath/internal/_layout/__init__.pxd +3 -0
- nvmath/internal/_layout/__init__.py +7 -0
- nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_layout/_layout.pxd +1303 -0
- nvmath/internal/_layout/_layout.pyi +1145 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +13 -0
- nvmath/internal/memory.pyi +50 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +9 -0
- nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
- nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_jit.pxd +7 -0
- nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
- nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -0
- nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +242 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
- nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
- nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
- nvmath/internal/package_ifc.py +168 -0
- nvmath/internal/package_ifc_cuda.py +57 -0
- nvmath/internal/package_ifc_cupy.py +67 -0
- nvmath/internal/package_ifc_torch.py +69 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +179 -0
- nvmath/internal/tensor_ifc_cupy.py +234 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
- nvmath/internal/tensor_ifc_numpy.py +184 -0
- nvmath/internal/tensor_ifc_torch.py +178 -0
- nvmath/internal/tensor_wrapper.py +160 -0
- nvmath/internal/typemaps.py +113 -0
- nvmath/internal/utils.py +805 -0
- nvmath/linalg/__init__.py +56 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
- nvmath/linalg/_internal/algo_config_ifc.py +43 -0
- nvmath/linalg/_internal/batch.py +234 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +766 -0
- nvmath/linalg/_internal/layout.py +624 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
- nvmath/linalg/_internal/solver_utils.py +432 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +157 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +170 -0
- nvmath/linalg/advanced/_configuration.py +351 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1316 -0
- nvmath/linalg/advanced/matmulmod.py +3734 -0
- nvmath/linalg/generic/__init__.py +53 -0
- nvmath/linalg/generic/_configuration/__init__.py +39 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +734 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
- nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +2094 -0
- nvmath/linalg/generic/solvermod.py +1301 -0
- nvmath/memory.py +279 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +147 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +506 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +227 -0
- nvmath/sparse/advanced/direct_solver.py +2069 -0
- nvmath/sparse/generic/__init__.py +7 -0
- nvmath/sparse/generic/_configuration.py +129 -0
- nvmath/sparse/generic/_helpers.py +137 -0
- nvmath/sparse/generic/_thunks.py +21 -0
- nvmath/sparse/generic/matmulmod.py +2353 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +422 -0
- nvmath/sparse/ust/_cpp.py +28 -0
- nvmath/sparse/ust/_drawer.py +565 -0
- nvmath/sparse/ust/_emitter.py +1033 -0
- nvmath/sparse/ust/_jit.py +188 -0
- nvmath/sparse/ust/_kernel.py +282 -0
- nvmath/sparse/ust/_utils.py +149 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/tensor.py +1016 -0
- nvmath/sparse/ust/tensor_format.py +957 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +120 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
- nvmath/tensor/_internal/cutensor_utils.py +230 -0
- nvmath/tensor/_internal/data.py +43 -0
- nvmath/tensor/_internal/einsum_parser.py +444 -0
- nvmath/tensor/_internal/typemaps.py +96 -0
- nvmath/tensor/contract.py +1900 -0
- nvmath_python-1.0.0.dist-info/METADATA +134 -0
- nvmath_python-1.0.0.dist-info/RECORD +332 -0
- nvmath_python-1.0.0.dist-info/WHEEL +5 -0
- nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
- 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)
|
nvmath/device/random.py
ADDED
|
@@ -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
|
+
)
|