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,8 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from ._configuration import DirectSolverOptions
|
|
6
|
+
from .solvermod import DirectSolver, InvalidDirectSolverState, direct_solver
|
|
7
|
+
|
|
8
|
+
__all__ = ["DirectSolver", "DirectSolverOptions", "InvalidDirectSolverState", "direct_solver"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Cache for cuSOLVERMp lifecycle resources.
|
|
7
|
+
|
|
8
|
+
``_HANDLES`` -- cuSOLVERMp library handles, keyed on ``device_id`` -- is
|
|
9
|
+
subject to the "one process per device" cuSOLVERMp model (single host thread
|
|
10
|
+
per device, so no locking or thread-local state is needed). The handle lazily
|
|
11
|
+
splits NCCL sub-communicators off the parent communicator on the first
|
|
12
|
+
``cusolverMpGetrf`` / ``cusolverMpGetrs`` and caches them for its lifetime.
|
|
13
|
+
That one-time split is expensive, so reusing the handle amortizes the cost.
|
|
14
|
+
|
|
15
|
+
Cleanup is driven by ``nvmath.distributed.finalize()``, not by ``atexit``.
|
|
16
|
+
``finalize()`` calls :func:`clear_handles` before tearing down the
|
|
17
|
+
``nvmath.distributed`` runtime's NCCL communicator: :func:`clear_handles`
|
|
18
|
+
destroys each cuSOLVERMp handle, which in turn destroys the NCCL
|
|
19
|
+
sub-communicators that cuSOLVERMp split off from the runtime's parent
|
|
20
|
+
communicator. Those sub-communicators must be destroyed while the parent is
|
|
21
|
+
still alive, so this has to happen before ``finalize()`` tears the parent down.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
__all__ = ["clear_handles", "get_handle"]
|
|
25
|
+
|
|
26
|
+
from nvmath.bindings import cusolverMp # type: ignore[attr-defined]
|
|
27
|
+
from nvmath.internal import utils
|
|
28
|
+
|
|
29
|
+
_HANDLES: dict[int, int] = {}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_handle(device_id: int, stream_ptr: int) -> int:
|
|
33
|
+
"""
|
|
34
|
+
Return the cached cuSOLVERMp handle for ``device_id``, creating and
|
|
35
|
+
caching one if necessary.
|
|
36
|
+
|
|
37
|
+
``stream_ptr`` is used only on first creation per device; subsequent
|
|
38
|
+
calls return the cached handle unchanged.
|
|
39
|
+
|
|
40
|
+
**This is not a collective call.** ``cusolverMpCreate`` only allocates
|
|
41
|
+
local resources (CUDA streams/events, child cuBLAS/cuSOLVERDn handles,
|
|
42
|
+
scratch buffers, an empty communicator cache); it never touches the NCCL
|
|
43
|
+
communicator, so ranks may create their handles independently.
|
|
44
|
+
"""
|
|
45
|
+
handle = _HANDLES.get(device_id)
|
|
46
|
+
if handle is None:
|
|
47
|
+
with utils.device_ctx(device_id):
|
|
48
|
+
handle = cusolverMp.create(device_id, stream_ptr)
|
|
49
|
+
_HANDLES[device_id] = handle
|
|
50
|
+
return handle
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def clear_handles() -> None:
|
|
54
|
+
"""Destroy and forget all cached handles.
|
|
55
|
+
|
|
56
|
+
**This is a collective call.** ``cusolverMpDestroy`` tears down the NCCL
|
|
57
|
+
sub-communicators the handle split off and any cached cuBLASMp grids,
|
|
58
|
+
both of which are collective over the runtime communicator.
|
|
59
|
+
All ranks must therefore call this in lockstep, and it must happen
|
|
60
|
+
while that parent communicator is still alive, i.e.
|
|
61
|
+
before ``nvmath.distributed.finalize()`` tears it down.
|
|
62
|
+
"""
|
|
63
|
+
for device_id, handle in _HANDLES.items():
|
|
64
|
+
with utils.device_ctx(device_id):
|
|
65
|
+
cusolverMp.destroy(handle)
|
|
66
|
+
_HANDLES.clear()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
__all__ = ["DirectSolverOptions"]
|
|
6
|
+
|
|
7
|
+
import dataclasses
|
|
8
|
+
import logging
|
|
9
|
+
from logging import Logger
|
|
10
|
+
from typing import Literal
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
|
14
|
+
class DirectSolverOptions:
|
|
15
|
+
"""A data class for providing options to
|
|
16
|
+
:func:`~nvmath.distributed.linalg.direct_solver` and
|
|
17
|
+
:class:`~nvmath.distributed.linalg.DirectSolver`.
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
logger: Python Logger object. The root logger will be used if a
|
|
21
|
+
logger object is not provided.
|
|
22
|
+
|
|
23
|
+
blocking: A flag specifying the behavior of the stream-ordered functions and
|
|
24
|
+
methods. When ``blocking`` is ``True``, the stream-ordered methods do not
|
|
25
|
+
return until the operation is complete. When ``blocking`` is ``"auto"``, the
|
|
26
|
+
methods may execute asynchronously when the inputs are on the GPU, depending
|
|
27
|
+
on the problem specification and runtime conditions. The stream-ordered methods
|
|
28
|
+
always block when the operands are on the CPU to ensure that the user doesn't
|
|
29
|
+
inadvertently use the result before it becomes available. The default is
|
|
30
|
+
``"auto"``.
|
|
31
|
+
|
|
32
|
+
inplace_a: Whether the LU factorization overwrites the input left-hand side
|
|
33
|
+
matrix ``a`` with the LU factors. The default is ``True``.
|
|
34
|
+
|
|
35
|
+
.. experimental:: attribute
|
|
36
|
+
|
|
37
|
+
inplace_b: Whether the solve overwrites the input right-hand side ``b``
|
|
38
|
+
with the solution ``x``. The default is ``True``.
|
|
39
|
+
|
|
40
|
+
.. experimental:: attribute
|
|
41
|
+
|
|
42
|
+
handle: If ``None`` (the default), the required cuSOLVERMp library handle will be
|
|
43
|
+
created automatically for the computation. If users wish to manage the library
|
|
44
|
+
handle themselves, they may provide a cuSOLVERMp handle. The presence of a
|
|
45
|
+
handle must be consistent across processes: either every process provides its
|
|
46
|
+
own handle, or none do.
|
|
47
|
+
|
|
48
|
+
.. seealso::
|
|
49
|
+
:func:`~nvmath.distributed.linalg.direct_solver`,
|
|
50
|
+
:class:`~nvmath.distributed.linalg.DirectSolver`.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
logger: Logger = dataclasses.field(default_factory=logging.getLogger)
|
|
54
|
+
blocking: Literal[True, "auto"] = "auto"
|
|
55
|
+
inplace_a: bool = True
|
|
56
|
+
inplace_b: bool = True
|
|
57
|
+
handle: int | None = None
|
|
58
|
+
|
|
59
|
+
def __post_init__(self):
|
|
60
|
+
if self.blocking not in (True, "auto"):
|
|
61
|
+
raise ValueError("The value specified for blocking must be either True or 'auto'.")
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Persistent device state (pivot vector + info words) and the cross-rank
|
|
7
|
+
info reducer used by :meth:`DirectSolver.factorize`.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import TYPE_CHECKING, Final
|
|
13
|
+
|
|
14
|
+
import cuda.bindings.runtime as cbr
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from nvmath.internal.tensor_ifc_ndbuffer import NDBufferTensor
|
|
18
|
+
from nvmath.internal.tensor_ifc_numpy import NumpyTensor
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from cuda.core import Event
|
|
22
|
+
|
|
23
|
+
from nvmath.internal.package_ifc import StreamHolder
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _FactorizationState:
|
|
27
|
+
"""Pivot vector and post-call info codes for cuSOLVERMp getrf/getrs."""
|
|
28
|
+
|
|
29
|
+
# info dtype, as documented by the cusolverMp getrf / getrs.
|
|
30
|
+
# Annotated as Final[str] so static checkers flag any reassignment.
|
|
31
|
+
_INFO_DTYPE: Final[str] = "int32"
|
|
32
|
+
|
|
33
|
+
__slots__ = (
|
|
34
|
+
"_alloc_stream",
|
|
35
|
+
"_info_getrf_d",
|
|
36
|
+
"_info_getrf_h",
|
|
37
|
+
"_info_getrs_d",
|
|
38
|
+
"_ipiv",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
local_cols_a: int,
|
|
45
|
+
device_id: int,
|
|
46
|
+
stream_holder: StreamHolder,
|
|
47
|
+
) -> None:
|
|
48
|
+
# Stream the device buffers are allocated on, used in free().
|
|
49
|
+
self._alloc_stream = stream_holder.obj
|
|
50
|
+
|
|
51
|
+
# ``ipiv`` is pure cuSOLVERMp scratch: getrf writes the pivot
|
|
52
|
+
# indices, getrs reads them, we never inspect the contents.
|
|
53
|
+
# ipiv has extent N (one entry per column of A, one per pivot step).
|
|
54
|
+
# Each entry's value is still a global row index (the row swapped
|
|
55
|
+
# to the leading position at that step). The dtype is int64.
|
|
56
|
+
# max(.., 1) is used for ranks that own zero columns.
|
|
57
|
+
#
|
|
58
|
+
self._ipiv = NDBufferTensor.empty(
|
|
59
|
+
(max(local_cols_a, 1),),
|
|
60
|
+
device_id=device_id,
|
|
61
|
+
dtype="int64",
|
|
62
|
+
stream_holder=stream_holder,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# ``_info_getrs_d`` is kept as a write-only target: cuSOLVERMp's
|
|
66
|
+
# getrs requires a non-NULL pointer for the info argument, but
|
|
67
|
+
# we never read the value back -- getrs has no info>0 case and
|
|
68
|
+
# info<0 would indicate an internal binding bug we cannot
|
|
69
|
+
# productively surface here.
|
|
70
|
+
self._info_getrs_d = NDBufferTensor.empty(
|
|
71
|
+
(1,),
|
|
72
|
+
device_id=device_id,
|
|
73
|
+
dtype=self._INFO_DTYPE,
|
|
74
|
+
stream_holder=stream_holder,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Three-element buffer: element 0 holds the getrf info word and feeds
|
|
78
|
+
# the cross-rank info check, elements 1 and 2 receive its MAX and MIN
|
|
79
|
+
# reductions; see sync_and_check_factorize_info.
|
|
80
|
+
self._info_getrf_h = NumpyTensor.empty((3,), dtype=self._INFO_DTYPE)
|
|
81
|
+
self._info_getrf_d = self._info_getrf_h.to(device_id, stream_holder)
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def ipiv_device_ptr(self) -> int:
|
|
85
|
+
return self._ipiv.data_ptr
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def info_getrf_device_ptr(self) -> int:
|
|
89
|
+
# getrf's single int32 info word goes in element 0 of the shared buffer.
|
|
90
|
+
return self._info_getrf_d.data_ptr
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def info_getrs_device_ptr(self) -> int:
|
|
94
|
+
return self._info_getrs_d.data_ptr
|
|
95
|
+
|
|
96
|
+
def reset_info_getrs_device(self, stream_holder) -> None:
|
|
97
|
+
"""Stream-ordered zero of ``_info_getrs_d``."""
|
|
98
|
+
(status,) = cbr.cudaMemsetAsync(self._info_getrs_d.data_ptr, 0, np.dtype(self._INFO_DTYPE).itemsize, stream_holder.ptr)
|
|
99
|
+
if status != cbr.cudaError_t.cudaSuccess:
|
|
100
|
+
raise RuntimeError(f"cudaMemsetAsync on info_getrs_d failed with status {status!r}")
|
|
101
|
+
|
|
102
|
+
def sync_and_check_factorize_info(self, stream_holder, *, nccl_comm) -> None:
|
|
103
|
+
"""Sync the factorize stream, reduce the per-rank getrf ``info`` word
|
|
104
|
+
across ranks, and raise on failure.
|
|
105
|
+
|
|
106
|
+
getrf writes ``info`` on each rank (0 = success, >0 = singular
|
|
107
|
+
leading-minor order, <0 = illegal argument). Raises ``RuntimeError`` if
|
|
108
|
+
any rank is singular, or ``AssertionError`` if any rank reports an
|
|
109
|
+
illegal argument (a solver-internal bug). See the inline comments for
|
|
110
|
+
the MIN/MAX reduction and the raise ordering.
|
|
111
|
+
"""
|
|
112
|
+
assert nccl_comm is not None # should have been enforced at solver init
|
|
113
|
+
multi_rank = nccl_comm.nranks > 1
|
|
114
|
+
info_ptr = self._info_getrf_d.data_ptr # getrf wrote the local info word here (element 0)
|
|
115
|
+
if multi_rank:
|
|
116
|
+
# Reduce the local info word (element 0) across ranks with both MIN
|
|
117
|
+
# and MAX: MAX alone would miss negatives (``max(-3, 0) == 0``) and
|
|
118
|
+
# MIN alone would miss positives, and we must catch both. The two
|
|
119
|
+
# allreduces are grouped into a single NCCL launch; NCCL gives no
|
|
120
|
+
# ordering between operations in a group, so we have MAX/MIN write
|
|
121
|
+
# distinct outputs. The group is enqueued on the factorize
|
|
122
|
+
# stream so it orders after getrf.
|
|
123
|
+
# nccl is imported lazily here because importing nccl.core eagerly
|
|
124
|
+
# imports the torch and cupy packages (its interop submodules run
|
|
125
|
+
# ``import torch`` / ``import cupy`` at load time), which we can avoid
|
|
126
|
+
# unless we actually need it.
|
|
127
|
+
from nccl.bindings import nccl as nccl_bindings # type: ignore
|
|
128
|
+
from nccl.core.typing import INT32, MAX, MIN # type: ignore
|
|
129
|
+
|
|
130
|
+
vmax_ptr = info_ptr + self._info_getrf_d.itemsize # element 1
|
|
131
|
+
vmin_ptr = info_ptr + 2 * self._info_getrf_d.itemsize # element 2
|
|
132
|
+
nccl_bindings.group_start()
|
|
133
|
+
nccl_bindings.all_reduce(info_ptr, vmax_ptr, 1, int(INT32), int(MAX), nccl_comm.ptr, stream_holder.ptr)
|
|
134
|
+
nccl_bindings.all_reduce(info_ptr, vmin_ptr, 1, int(INT32), int(MIN), nccl_comm.ptr, stream_holder.ptr)
|
|
135
|
+
nccl_bindings.group_end()
|
|
136
|
+
|
|
137
|
+
# copy_ is blocking here.
|
|
138
|
+
self._info_getrf_h.copy_(self._info_getrf_d, stream_holder)
|
|
139
|
+
# Element 0 holds the local info word (used directly when single-rank);
|
|
140
|
+
# for the multi-rank, element 1 holds max(info) and element 2 holds min(info).
|
|
141
|
+
if multi_rank:
|
|
142
|
+
vmax = self._info_getrf_h.tensor[1]
|
|
143
|
+
vmin = self._info_getrf_h.tensor[2]
|
|
144
|
+
else:
|
|
145
|
+
vmax = vmin = self._info_getrf_h.tensor[0]
|
|
146
|
+
|
|
147
|
+
# Raise based on the allreduced values so every rank raises together.
|
|
148
|
+
# Negative info means an illegal argument: getrf's args are
|
|
149
|
+
# solver-internal, so it's our bug. Check it before the singular case
|
|
150
|
+
# so an internal bug still surfaces when another rank also flags a
|
|
151
|
+
# singular minor, and via AssertionError to survive `python -O`.
|
|
152
|
+
if vmin < 0:
|
|
153
|
+
raise AssertionError(
|
|
154
|
+
f"Internal error: cuSOLVERMp getrf reported an illegal argument at position {-vmin} (info={vmin})."
|
|
155
|
+
)
|
|
156
|
+
if vmax > 0:
|
|
157
|
+
raise RuntimeError(f"DirectSolver factorization failed: matrix is singular (leading minor of order {vmax}).")
|
|
158
|
+
|
|
159
|
+
def free(self, last_compute_event: Event | None = None) -> None:
|
|
160
|
+
"""Release the pivot vector and the host/device info buffers.
|
|
161
|
+
|
|
162
|
+
Device buffers free stream-ordered on their allocation stream when
|
|
163
|
+
dropped; waiting that stream on ``last_compute_event`` first orders
|
|
164
|
+
the free after any in-flight getrf/getrs (mirrors
|
|
165
|
+
:meth:`Workspace.release`).
|
|
166
|
+
"""
|
|
167
|
+
if last_compute_event is not None and self._alloc_stream is not None:
|
|
168
|
+
self._alloc_stream.wait(last_compute_event)
|
|
169
|
+
self._info_getrf_h = None
|
|
170
|
+
self._ipiv = None
|
|
171
|
+
self._info_getrf_d = None
|
|
172
|
+
self._info_getrs_d = None
|