nvmath-python 0.5.0__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +37 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/layout.py +58 -0
  5. nvmath/_utils.py +363 -0
  6. nvmath/bindings/__init__.pxd +0 -0
  7. nvmath/bindings/__init__.py +44 -0
  8. nvmath/bindings/_internal/__init__.pxd +0 -0
  9. nvmath/bindings/_internal/__init__.py +0 -0
  10. nvmath/bindings/_internal/cublas.cp313-win_amd64.pyd +0 -0
  11. nvmath/bindings/_internal/cublas.pxd +518 -0
  12. nvmath/bindings/_internal/cublasLt.cp313-win_amd64.pyd +0 -0
  13. nvmath/bindings/_internal/cublasLt.pxd +54 -0
  14. nvmath/bindings/_internal/cudss.cp313-win_amd64.pyd +0 -0
  15. nvmath/bindings/_internal/cudss.pxd +44 -0
  16. nvmath/bindings/_internal/cufft.cp313-win_amd64.pyd +0 -0
  17. nvmath/bindings/_internal/cufft.pxd +69 -0
  18. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  19. nvmath/bindings/_internal/curand.cp313-win_amd64.pyd +0 -0
  20. nvmath/bindings/_internal/curand.pxd +42 -0
  21. nvmath/bindings/_internal/cusolver.cp313-win_amd64.pyd +0 -0
  22. nvmath/bindings/_internal/cusolver.pxd +15 -0
  23. nvmath/bindings/_internal/cusolverDn.cp313-win_amd64.pyd +0 -0
  24. nvmath/bindings/_internal/cusolverDn.pxd +386 -0
  25. nvmath/bindings/_internal/cusparse.cp313-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/cusparse.pxd +270 -0
  27. nvmath/bindings/_internal/mathdx.cp313-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/mathdx.pxd +79 -0
  29. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  30. nvmath/bindings/_internal/utils.cp313-win_amd64.pyd +0 -0
  31. nvmath/bindings/_internal/utils.pxd +186 -0
  32. nvmath/bindings/cublas.cp313-win_amd64.pyd +0 -0
  33. nvmath/bindings/cublas.pxd +545 -0
  34. nvmath/bindings/cublas.pyi +18 -0
  35. nvmath/bindings/cublasLt.cp313-win_amd64.pyd +0 -0
  36. nvmath/bindings/cublasLt.pxd +99 -0
  37. nvmath/bindings/cudss.cp313-win_amd64.pyd +0 -0
  38. nvmath/bindings/cudss.pxd +83 -0
  39. nvmath/bindings/cudss.pyi +249 -0
  40. nvmath/bindings/cufft.cp313-win_amd64.pyd +0 -0
  41. nvmath/bindings/cufft.pxd +114 -0
  42. nvmath/bindings/cufftMp.pxd +124 -0
  43. nvmath/bindings/curand.cp313-win_amd64.pyd +0 -0
  44. nvmath/bindings/curand.pxd +71 -0
  45. nvmath/bindings/cusolver.cp313-win_amd64.pyd +0 -0
  46. nvmath/bindings/cusolver.pxd +60 -0
  47. nvmath/bindings/cusolverDn.cp313-win_amd64.pyd +0 -0
  48. nvmath/bindings/cusolverDn.pxd +410 -0
  49. nvmath/bindings/cusparse.cp313-win_amd64.pyd +0 -0
  50. nvmath/bindings/cusparse.pxd +329 -0
  51. nvmath/bindings/cycublas.cp313-win_amd64.pyd +0 -0
  52. nvmath/bindings/cycublas.pxd +657 -0
  53. nvmath/bindings/cycublasLt.cp313-win_amd64.pyd +0 -0
  54. nvmath/bindings/cycublasLt.pxd +1010 -0
  55. nvmath/bindings/cycudss.cp313-win_amd64.pyd +0 -0
  56. nvmath/bindings/cycudss.pxd +191 -0
  57. nvmath/bindings/cycufft.cp313-win_amd64.pyd +0 -0
  58. nvmath/bindings/cycufft.pxd +320 -0
  59. nvmath/bindings/cycufftMp.pxd +333 -0
  60. nvmath/bindings/cycurand.cp313-win_amd64.pyd +0 -0
  61. nvmath/bindings/cycurand.pxd +146 -0
  62. nvmath/bindings/cycusolver.cp313-win_amd64.pyd +0 -0
  63. nvmath/bindings/cycusolver.pxd +143 -0
  64. nvmath/bindings/cycusolverDn.cp313-win_amd64.pyd +0 -0
  65. nvmath/bindings/cycusolverDn.pxd +414 -0
  66. nvmath/bindings/cycusparse.cp313-win_amd64.pyd +0 -0
  67. nvmath/bindings/cycusparse.pxd +476 -0
  68. nvmath/bindings/cymathdx.cp313-win_amd64.pyd +0 -0
  69. nvmath/bindings/cymathdx.pxd +363 -0
  70. nvmath/bindings/cynvshmem.pxd +126 -0
  71. nvmath/bindings/mathdx.cp313-win_amd64.pyd +0 -0
  72. nvmath/bindings/mathdx.pxd +131 -0
  73. nvmath/bindings/mathdx.pyi +686 -0
  74. nvmath/bindings/nvpl/__init__.pxd +0 -0
  75. nvmath/bindings/nvpl/__init__.py +11 -0
  76. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  77. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  78. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  79. nvmath/bindings/nvpl/cyfft.pxd +87 -0
  80. nvmath/bindings/nvpl/fft.pxd +100 -0
  81. nvmath/bindings/nvshmem.pxd +54 -0
  82. nvmath/device/__init__.py +23 -0
  83. nvmath/device/_deprecated.py +33 -0
  84. nvmath/device/caching.py +51 -0
  85. nvmath/device/common.py +131 -0
  86. nvmath/device/common_backend.py +125 -0
  87. nvmath/device/common_cuda.py +156 -0
  88. nvmath/device/common_mathdx.py +97 -0
  89. nvmath/device/common_numba.py +159 -0
  90. nvmath/device/common_opaque_tensor.py +128 -0
  91. nvmath/device/cublasdx.py +1085 -0
  92. nvmath/device/cublasdx_backend.py +552 -0
  93. nvmath/device/cublasdx_numba.py +528 -0
  94. nvmath/device/cufftdx.py +551 -0
  95. nvmath/device/cufftdx_backend.py +194 -0
  96. nvmath/device/cufftdx_numba.py +123 -0
  97. nvmath/device/curand_kernel.py +9147 -0
  98. nvmath/device/nvrtc.py +95 -0
  99. nvmath/device/patch.py +35 -0
  100. nvmath/device/random.py +417 -0
  101. nvmath/device/random_helpers.py +23 -0
  102. nvmath/device/random_states.py +189 -0
  103. nvmath/device/types.py +11 -0
  104. nvmath/device/vector_types_numba.py +203 -0
  105. nvmath/distributed/__init__.py +117 -0
  106. nvmath/distributed/_internal/__init__.py +0 -0
  107. nvmath/distributed/_internal/nvshmem.py +243 -0
  108. nvmath/distributed/_internal/tensor_ifc_cupy.py +111 -0
  109. nvmath/distributed/_internal/tensor_ifc_numpy.py +53 -0
  110. nvmath/distributed/_internal/tensor_ifc_torch.py +108 -0
  111. nvmath/distributed/_internal/tensor_wrapper.py +59 -0
  112. nvmath/distributed/_utils.py +152 -0
  113. nvmath/distributed/fft/__init__.py +6 -0
  114. nvmath/distributed/fft/_configuration.py +86 -0
  115. nvmath/distributed/fft/fft.py +1737 -0
  116. nvmath/distributed/reshape/__init__.py +6 -0
  117. nvmath/distributed/reshape/_configuration.py +39 -0
  118. nvmath/distributed/reshape/reshape.py +1249 -0
  119. nvmath/fft/__init__.py +7 -0
  120. nvmath/fft/_configuration.py +208 -0
  121. nvmath/fft/_exec_utils.py +116 -0
  122. nvmath/fft/_helpers.py +260 -0
  123. nvmath/fft/fft.py +2346 -0
  124. nvmath/internal/__init__.py +5 -0
  125. nvmath/internal/enum_utils.py +142 -0
  126. nvmath/internal/formatters.py +87 -0
  127. nvmath/internal/mem_limit.py +51 -0
  128. nvmath/internal/package_ifc.py +119 -0
  129. nvmath/internal/package_ifc_cuda.py +43 -0
  130. nvmath/internal/package_ifc_cupy.py +49 -0
  131. nvmath/internal/package_ifc_torch.py +31 -0
  132. nvmath/internal/package_wrapper.py +14 -0
  133. nvmath/internal/tensor_ifc.py +143 -0
  134. nvmath/internal/tensor_ifc_cupy.py +185 -0
  135. nvmath/internal/tensor_ifc_numpy.py +157 -0
  136. nvmath/internal/tensor_ifc_torch.py +115 -0
  137. nvmath/internal/tensor_wrapper.py +160 -0
  138. nvmath/internal/typemaps.py +154 -0
  139. nvmath/internal/utils.py +634 -0
  140. nvmath/linalg/__init__.py +11 -0
  141. nvmath/linalg/_internal/__init__.py +3 -0
  142. nvmath/linalg/_internal/algo_cap_ifc.py +86 -0
  143. nvmath/linalg/_internal/algo_config_ifc.py +87 -0
  144. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  145. nvmath/linalg/_internal/epilog_protocol.py +738 -0
  146. nvmath/linalg/_internal/matmul_desc_ifc.py +72 -0
  147. nvmath/linalg/_internal/matmul_pref_ifc.py +65 -0
  148. nvmath/linalg/_internal/matrix_layout_ifc.py +59 -0
  149. nvmath/linalg/_internal/typemaps.py +135 -0
  150. nvmath/linalg/_internal/utils.py +96 -0
  151. nvmath/linalg/advanced/__init__.py +8 -0
  152. nvmath/linalg/advanced/_algorithmmod.py +142 -0
  153. nvmath/linalg/advanced/_configuration.py +320 -0
  154. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  155. nvmath/linalg/advanced/helpers/matmul.py +173 -0
  156. nvmath/linalg/advanced/matmulmod.py +2855 -0
  157. nvmath/memory.py +266 -0
  158. nvmath/sparse/__init__.py +18 -0
  159. nvmath/sparse/_internal/__init__.py +21 -0
  160. nvmath/sparse/_internal/common_utils.py +81 -0
  161. nvmath/sparse/_internal/cudss_config_ifc.py +584 -0
  162. nvmath/sparse/_internal/cudss_data_ifc.py +291 -0
  163. nvmath/sparse/_internal/cudss_utils.py +398 -0
  164. nvmath/sparse/_internal/sparse_csr_ifc.py +154 -0
  165. nvmath/sparse/_internal/sparse_format_helpers.py +88 -0
  166. nvmath/sparse/_internal/sparse_tensor_ifc.py +80 -0
  167. nvmath/sparse/advanced/__init__.py +7 -0
  168. nvmath/sparse/advanced/_configuration.py +150 -0
  169. nvmath/sparse/advanced/direct_solver.py +1705 -0
  170. nvmath_python-0.5.0.dist-info/METADATA +122 -0
  171. nvmath_python-0.5.0.dist-info/RECORD +174 -0
  172. nvmath_python-0.5.0.dist-info/WHEEL +5 -0
  173. nvmath_python-0.5.0.dist-info/licenses/LICENSE +177 -0
  174. nvmath_python-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,291 @@
1
+ # Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """
6
+ Interface classes to encapsulate low-level calls to get or set cuDSS "data" attributes.
7
+ """
8
+
9
+ __all__ = ["FactorizationInfo", "PlanInfo", "memory_estimates_dtype"]
10
+
11
+ import re
12
+ import threading
13
+ from typing import TypeAlias
14
+
15
+ import numpy as np
16
+
17
+ from nvmath.bindings import cudss
18
+ from nvmath.internal import utils
19
+
20
+
21
+ DataParamEnum: TypeAlias = cudss.DataParam
22
+
23
+ # Future-proofing - cuDSS is currently not thread-safe.
24
+ # https://docs.nvidia.com/cuda/cudss/general.html#thread-safety
25
+ _tls = threading.local()
26
+ _tls.size_written = np.empty((1,), dtype=np.uint64)
27
+
28
+
29
+ def _get_attribute(handle, data_ptr, name, attribute, length=1):
30
+ """
31
+ name = cudss enumerator for the attribute.
32
+ attribute = numpy ndarray object into which the value is stored.
33
+ """
34
+ cudss.data_get(
35
+ handle, data_ptr, name, attribute.ctypes.data, length * attribute.dtype.itemsize, _tls.size_written.ctypes.data
36
+ )
37
+ assert _tls.size_written[0] <= length * attribute.dtype.itemsize, "Internal error."
38
+
39
+
40
+ def _check_valid_solver(info):
41
+ """
42
+ Check if the configuration points to a valid DirectSolver object.
43
+ """
44
+ if not info._solver.valid_state:
45
+ m = re.match(r"<nvmath\..*\.(.*Info) object at (.*)>$", str(info))
46
+ assert m is not None, "Internal error."
47
+ name = m.group(1)
48
+ address = m.group(2)
49
+
50
+ raise RuntimeError(f"The {name} object at {address} cannot be used after it's solver object is free'd.")
51
+
52
+
53
+ memory_estimates_dtype = np.dtype(
54
+ [
55
+ ("permanent_device_memory", "<u8"),
56
+ ("peak_device_memory", "<u8"),
57
+ ("permanent_host_memory", "<u8"),
58
+ ("peak_host_memory", "<u8"),
59
+ ("hybrid_min_device_memory", "<u8"),
60
+ ("hybrid_max_device_memory", "<u8"),
61
+ ("reserved", "<u8", (10,)),
62
+ ]
63
+ )
64
+
65
+
66
+ class PlanInfo:
67
+ """
68
+ An interface to query information returned by
69
+ :meth:`nvmath.sparse.advanced.DirectSolver.plan`.
70
+ """
71
+
72
+ def __init__(self, solver):
73
+ """
74
+ ctor for internal use only.
75
+ """
76
+ self._solver = solver
77
+ self._handle = self._solver.handle
78
+ self._data_ptr = self._solver.data_ptr
79
+ assert self._data_ptr is not None, "Internal error."
80
+
81
+ self._N = self._solver._N
82
+ self._batched = self._solver.batched
83
+
84
+ # Allocate permutation arrays lazily, and only if not batched.
85
+ self._perm_reorder_col = None
86
+ self._perm_reorder_row = None
87
+
88
+ self._memory_estimates = np.zeros((), dtype=memory_estimates_dtype).view(np.recarray)
89
+
90
+ def _check_valid_solver_wrapper(self, *args, **kwargs):
91
+ _check_valid_solver(self)
92
+
93
+ @property
94
+ @utils.precondition(_check_valid_solver_wrapper)
95
+ def memory_estimates(self):
96
+ """
97
+ Query the memory estimates. See the
98
+ `cuDSS documentation
99
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
100
+ for more information.
101
+ """
102
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.MEMORY_ESTIMATES, self._memory_estimates, length=1)
103
+
104
+ return self._memory_estimates
105
+
106
+ @property
107
+ @utils.precondition(_check_valid_solver_wrapper)
108
+ def col_permutation(self):
109
+ """
110
+ Query the column permutation after planning (reordering). See the
111
+ `cuDSS documentation
112
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
113
+ for more information.
114
+ """
115
+ if self._batched:
116
+ raise RuntimeError("Column permutation is not available for batched systems.")
117
+
118
+ if self._perm_reorder_col is None:
119
+ get_dtype = cudss.get_data_param_dtype
120
+ self._perm_reorder_col = np.empty((self._N,), dtype=get_dtype(DataParamEnum.PERM_REORDER_COL))
121
+
122
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.PERM_REORDER_COL, self._perm_reorder_col, length=self._N)
123
+
124
+ return self._perm_reorder_col
125
+
126
+ @property
127
+ @utils.precondition(_check_valid_solver_wrapper)
128
+ def row_permutation(self):
129
+ """
130
+ Query the row permutation after planning (reordering). See the
131
+ `cuDSS documentation
132
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
133
+ for more information.
134
+ """
135
+ if self._batched:
136
+ raise RuntimeError("Row permutation is not available for batched systems.")
137
+
138
+ if self._perm_reorder_row is None:
139
+ get_dtype = cudss.get_data_param_dtype
140
+ self._perm_reorder_row = np.empty((self._N,), dtype=get_dtype(DataParamEnum.PERM_REORDER_ROW))
141
+
142
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.PERM_REORDER_ROW, self._perm_reorder_row, length=self._N)
143
+
144
+ return self._perm_reorder_row
145
+
146
+
147
+ class FactorizationInfo:
148
+ """
149
+ An interface to query information returned by
150
+ :meth:`nvmath.sparse.advanced.DirectSolver.factorize`.
151
+ """
152
+
153
+ def __init__(self, solver):
154
+ """
155
+ ctor for internal use only.
156
+ """
157
+ self._solver = solver
158
+ self._handle = self._solver.handle
159
+ self._data_ptr = self._solver.data_ptr
160
+ assert self._data_ptr is not None, "Internal error"
161
+
162
+ self._N = self._solver._N
163
+ self._batched = self._solver.batched
164
+ self._value_type = self._solver.value_type
165
+
166
+ get_dtype = cudss.get_data_param_dtype
167
+
168
+ self._info = np.zeros((1,), dtype=get_dtype(DataParamEnum.INFO))
169
+ self._lu_nnz = np.zeros((1,), dtype=get_dtype(DataParamEnum.LU_NNZ))
170
+ self._npivots = np.zeros((1,), dtype=get_dtype(DataParamEnum.NPIVOTS))
171
+ self._inertia = np.zeros((2,), dtype=get_dtype(DataParamEnum.INERTIA))
172
+
173
+ # Allocate permutation and diagonal arrays lazily, and only if not batched.
174
+ self._perm_col = None
175
+ self._perm_row = None
176
+ self._diag = None
177
+
178
+ def _check_valid_solver_wrapper(self, *args, **kwargs):
179
+ _check_valid_solver(self)
180
+
181
+ @property
182
+ @utils.precondition(_check_valid_solver_wrapper)
183
+ def info(self):
184
+ """
185
+ Query the error info after factorization. See the
186
+ `cuDSS documentation
187
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
188
+ for more information.
189
+ """
190
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.INFO, self._info)
191
+
192
+ return self._info.item()
193
+
194
+ @property
195
+ @utils.precondition(_check_valid_solver_wrapper)
196
+ def lu_nnz(self):
197
+ """
198
+ Query the number of non-zeros in the LU factorization. See the
199
+ `cuDSS documentation
200
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
201
+ for more information.
202
+ """
203
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.LU_NNZ, self._lu_nnz)
204
+
205
+ return self._lu_nnz.item()
206
+
207
+ @property
208
+ @utils.precondition(_check_valid_solver_wrapper)
209
+ def npivots(self):
210
+ """
211
+ Query the number of pivots encountered in the LU factorization. See the
212
+ `cuDSS documentation
213
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
214
+ for more information.
215
+ """
216
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.NPIVOTS, self._npivots)
217
+
218
+ return self._npivots.item()
219
+
220
+ @property
221
+ @utils.precondition(_check_valid_solver_wrapper)
222
+ def inertia(self):
223
+ """
224
+ Query the inertia (number of positive and negative pivots) encountered in the
225
+ LU factorization. See the
226
+ `cuDSS documentation
227
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
228
+ for more information.
229
+ """
230
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.INERTIA, self._inertia, length=2)
231
+
232
+ return self._inertia
233
+
234
+ @property
235
+ @utils.precondition(_check_valid_solver_wrapper)
236
+ def col_permutation(self):
237
+ """
238
+ Query the column permutation after factorization. See the
239
+ `cuDSS documentation
240
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
241
+ for more information.
242
+ """
243
+ if self._batched:
244
+ raise RuntimeError("Column permutation is not available for batched systems.")
245
+
246
+ if self._perm_col is None:
247
+ get_dtype = cudss.get_data_param_dtype
248
+ self._perm_col = np.empty((self._N,), dtype=get_dtype(DataParamEnum.PERM_COL))
249
+
250
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.PERM_COL, self._perm_col, length=self._N)
251
+
252
+ return self._perm_col
253
+
254
+ @property
255
+ @utils.precondition(_check_valid_solver_wrapper)
256
+ def row_permutation(self):
257
+ """
258
+ Query the row permutation after factorization. See the
259
+ `cuDSS documentation
260
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
261
+ for more information.
262
+ """
263
+ if self._batched:
264
+ raise RuntimeError("Row permutation is not available for batched systems.")
265
+
266
+ if self._perm_row is None:
267
+ get_dtype = cudss.get_data_param_dtype
268
+ self._perm_row = np.empty((self._N,), dtype=get_dtype(DataParamEnum.PERM_ROW))
269
+
270
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.PERM_ROW, self._perm_row, length=self._N)
271
+
272
+ return self._perm_row
273
+
274
+ @property
275
+ @utils.precondition(_check_valid_solver_wrapper)
276
+ def diag(self):
277
+ """
278
+ Query the diagonal of the factorized system. See the
279
+ `cuDSS documentation
280
+ <https://docs.nvidia.com/cuda/cudss/types.html#cudssdataparam-t>`_
281
+ for more information.
282
+ """
283
+ if self._batched:
284
+ raise RuntimeError("The factorized system's diagonal is not available for batched systems.")
285
+
286
+ if self._diag is None:
287
+ self._diag = np.empty((self._N,), dtype=self._value_type)
288
+
289
+ _get_attribute(self._handle, self._data_ptr, DataParamEnum.DIAG, self._diag, length=self._N)
290
+
291
+ return self._diag
@@ -0,0 +1,398 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from collections.abc import Sequence
6
+
7
+ import numpy as np
8
+
9
+ from nvmath.bindings import cudss
10
+ from nvmath.internal.tensor_wrapper import wrap_operand
11
+
12
+ COMPATIBLE_LHS_RHS_PACKAGES = {("scipy", "numpy"), ("cupyx", "cupy"), ("torch", "torch")}
13
+
14
+
15
+ # TODO: Add debug log messages.
16
+ def wrap_dense_tensors(tensor_type, native_operands):
17
+ # Unchecked faster version of tensor_wrapper.wrap_operands().
18
+ return tuple(tensor_type(o) for o in native_operands)
19
+
20
+
21
+ def wrap_sparse_tensors(tensor_type, attr_name_map, native_operands):
22
+ # A more direct version of nvmath.sparse._internal.common_utils.wrap_sparse_operands().
23
+ return tuple(tensor_type.create_from_tensor(o, attr_name_map=attr_name_map) for o in native_operands)
24
+
25
+
26
+ def create_cudss_dense_matrix(cuda_value_type, rhs):
27
+ # The rhs should be a wrapped (TensorHolder object) matrix or vector in a memory space
28
+ # consistent with the execution mode.
29
+ shape = rhs.shape
30
+ assert len(shape) <= 2, "Internal error."
31
+
32
+ m = shape[0]
33
+ n = shape[1] if len(shape) == 2 else 1
34
+
35
+ # Only column-major is supported.
36
+ ld = m
37
+
38
+ rhs_ptr = cudss.matrix_create_dn(m, n, ld, rhs.data_ptr, cuda_value_type, cudss.Layout.COL_MAJOR)
39
+ references = []
40
+ return references, rhs_ptr
41
+
42
+
43
+ def create_cudss_dense_explicit_batch(cuda_index_type, cuda_value_type, index_type, rhs, stream_holder):
44
+ # The rhs should be a sequence of wrapped (TensorHolder object) matrix or vector in a
45
+ # memory space consistent with the execution mode.
46
+ assert isinstance(rhs, Sequence), "Internal error."
47
+
48
+ batch_count = len(rhs)
49
+
50
+ m = wrap_operand(np.array([r.shape[0] for r in rhs], dtype=index_type))
51
+ n = wrap_operand(np.array([r.shape[1] if len(r.shape) == 2 else 1 for r in rhs], dtype=index_type))
52
+
53
+ # Take device ID of the first matrix, since it's the same for all.
54
+ device_id = rhs[0].device_id
55
+
56
+ # The pointers must be a device array. We'll first create it on the host, wrap and
57
+ # copy it to the device.
58
+ p = wrap_operand(np.array([r.data_ptr for r in rhs], dtype=np.uint64))
59
+ p = p.to(device_id=device_id, stream_holder=stream_holder)
60
+
61
+ # LD is the same as M, since only column-major is supported.
62
+ rhs_ptr = cudss.matrix_create_batch_dn(
63
+ batch_count, m.data_ptr, n.data_ptr, m.data_ptr, p.data_ptr, cuda_index_type, cuda_value_type, cudss.Layout.COL_MAJOR
64
+ )
65
+
66
+ references = [m, n, p]
67
+ return references, rhs_ptr
68
+
69
+
70
+ def create_cudss_dense_implicit_batch(cuda_index_type, cuda_value_type, index_type, batch_indices, rhs, stream_holder):
71
+ # The rhs should be a wrapped (TensorHolder object) NDarray 3D or greater dimension.
72
+ assert len(rhs.shape) > 2, "Internal error."
73
+
74
+ # Create a sequence of samples in the batch.
75
+ # Explicitly unpack indices to avoid tensor[*b, ...] (support 3.10).
76
+ unpacked_indices = [tuple(b) + (...,) for b in batch_indices]
77
+ rhs_sequence = [rhs.tensor[u] for u in unpacked_indices]
78
+
79
+ # Wrap the samples using the lightweight interface, since we've already checked.
80
+ rhs_sequence = wrap_dense_tensors(rhs.__class__, rhs_sequence)
81
+
82
+ return create_cudss_dense_explicit_batch(cuda_index_type, cuda_value_type, index_type, rhs_sequence, stream_holder)
83
+
84
+
85
+ def create_cudss_dense_wrapper(cuda_index_type, cuda_value_type, index_type, batch_indices, rhs, stream_holder):
86
+ # A convenience function to forward to the right implementation.
87
+
88
+ if isinstance(rhs, Sequence):
89
+ return create_cudss_dense_explicit_batch(cuda_index_type, cuda_value_type, index_type, rhs, stream_holder)
90
+
91
+ if len(rhs.shape) > 2:
92
+ return create_cudss_dense_implicit_batch(
93
+ cuda_index_type, cuda_value_type, index_type, batch_indices, rhs, stream_holder
94
+ )
95
+
96
+ return create_cudss_dense_matrix(cuda_value_type, rhs)
97
+
98
+
99
+ def update_cudss_dense_matrix_ptr(rhs_ptr, new_rhs):
100
+ # The new rhs should be a wrapped (TensorHolder object) matrix or vector in a memory
101
+ # space consistent with the execution mode.
102
+ # rhs_ptr is a cuDSS matrix ptr.
103
+ assert len(new_rhs.shape) <= 2, "Internal error."
104
+ cudss.matrix_set_values(rhs_ptr, new_rhs.data_ptr)
105
+
106
+ references = []
107
+ return references
108
+
109
+
110
+ def update_cudss_dense_explicit_batch_ptr(rhs_ptr, new_rhs, stream_holder):
111
+ # The new rhs should be a sequence of wrapped (TensorHolder object) matrix or vector
112
+ # in a memory space consistent with the execution mode.
113
+ assert isinstance(new_rhs, Sequence), "Internal error."
114
+
115
+ # Take device ID of the first matrix, since it's the same for all.
116
+ device_id = new_rhs[0].device_id
117
+
118
+ # The pointers must be a device array. We'll first create it on the host, wrap and
119
+ # copy it to the device.
120
+ p = wrap_operand(np.array([r.data_ptr for r in new_rhs], dtype=np.uint64))
121
+ p = p.to(device_id=device_id, stream_holder=stream_holder)
122
+
123
+ cudss.matrix_set_batch_values(rhs_ptr, p.data_ptr)
124
+
125
+ references = [p]
126
+ return references
127
+
128
+
129
+ def update_cudss_dense_implicit_batch_ptr(rhs_ptr, batch_indices, new_rhs, stream_holder):
130
+ # The new rhs should be a wrapped (TensorHolder object) NDarray 3D or greater dimension.
131
+ assert len(new_rhs.shape) > 2, "Internal error."
132
+
133
+ # Create a sequence of samples in the batch.
134
+ # Explicitly unpack indices to avoid tensor[*b, ...] (support 3.10).
135
+ unpacked_indices = [tuple(b) + (...,) for b in batch_indices]
136
+ rhs_sequence = [new_rhs.tensor[u] for u in unpacked_indices]
137
+
138
+ # Wrap the samples using the lightweight interface, since we've already checked.
139
+ rhs_sequence = wrap_dense_tensors(new_rhs.__class__, rhs_sequence)
140
+
141
+ return update_cudss_dense_explicit_batch_ptr(rhs_ptr, rhs_sequence, stream_holder)
142
+
143
+
144
+ def update_cudss_dense_ptr_wrapper(rhs_ptr, *, batch_indices=None, new_rhs=None, stream_holder=None):
145
+ # A convenience function to forward to the right implementation.
146
+ assert new_rhs is not None, "Internal error."
147
+
148
+ if isinstance(new_rhs, Sequence):
149
+ assert stream_holder is not None, "Internal error."
150
+ return update_cudss_dense_explicit_batch_ptr(rhs_ptr, new_rhs, stream_holder)
151
+
152
+ if len(new_rhs.shape) > 2:
153
+ assert batch_indices is not None and stream_holder is not None, "Internal error."
154
+ return update_cudss_dense_implicit_batch_ptr(rhs_ptr, batch_indices, new_rhs, stream_holder)
155
+
156
+ return update_cudss_dense_matrix_ptr(rhs_ptr, new_rhs)
157
+
158
+
159
+ def create_cudss_csr_matrix(cuda_index_type, cuda_value_type, matrix_type, matrix_view_type, lhs):
160
+ # The lhs should be a wrapped (CSRTensorHolder object) matrix in a memory space
161
+ # consistent with the execution mode.
162
+ assert lhs.format_name == "CSR", "Internal error."
163
+
164
+ shape = lhs.shape
165
+ assert len(shape) == 2, "Internal error."
166
+
167
+ m, n = shape
168
+ nnz = lhs.values.size
169
+
170
+ lhs_ptr = cudss.matrix_create_csr(
171
+ m,
172
+ n,
173
+ nnz,
174
+ lhs.crow_indices.data_ptr,
175
+ 0,
176
+ lhs.col_indices.data_ptr,
177
+ lhs.values.data_ptr,
178
+ cuda_index_type,
179
+ cuda_value_type,
180
+ matrix_type,
181
+ matrix_view_type,
182
+ cudss.IndexBase.ZERO,
183
+ )
184
+ references = []
185
+ return references, lhs_ptr
186
+
187
+
188
+ def create_cudss_csr_explicit_batch(
189
+ cuda_index_type, cuda_value_type, index_type, matrix_type, matrix_view_type, lhs, stream_holder
190
+ ):
191
+ # The lhs should be a sequence of wrapped (CSRTensorHolder object) matrix in a memory
192
+ # space consistent with the execution mode.
193
+ assert isinstance(lhs, Sequence), "Internal error."
194
+
195
+ batch_count = len(lhs)
196
+
197
+ m = wrap_operand(np.array([o.shape[0] for o in lhs], dtype=index_type))
198
+ n = wrap_operand(np.array([o.shape[1] for o in lhs], dtype=index_type))
199
+ nnz = wrap_operand(np.array([o.values.size for o in lhs], dtype=index_type))
200
+
201
+ # Take device ID of the first operator, since it's the same for all.
202
+ device_id = lhs[0].device_id
203
+
204
+ # The pointer arrays must be on device. We'll first create it on the host, wrap and
205
+ # copy it to the device.
206
+ crow_indices = wrap_operand(np.array([o.crow_indices.data_ptr for o in lhs], dtype=np.uint64))
207
+ crow_indices = crow_indices.to(device_id=device_id, stream_holder=stream_holder)
208
+
209
+ col_indices = wrap_operand(np.array([o.col_indices.data_ptr for o in lhs], dtype=np.uint64))
210
+ col_indices = col_indices.to(device_id=device_id, stream_holder=stream_holder)
211
+
212
+ values = wrap_operand(np.array([o.values.data_ptr for o in lhs], dtype=np.uint64))
213
+ values = values.to(device_id=device_id, stream_holder=stream_holder)
214
+
215
+ lhs_ptr = cudss.matrix_create_batch_csr(
216
+ batch_count,
217
+ m.data_ptr,
218
+ n.data_ptr,
219
+ nnz.data_ptr,
220
+ crow_indices.data_ptr,
221
+ 0,
222
+ col_indices.data_ptr,
223
+ values.data_ptr,
224
+ cuda_index_type,
225
+ cuda_value_type,
226
+ matrix_type,
227
+ matrix_view_type,
228
+ cudss.IndexBase.ZERO,
229
+ )
230
+ references = [m, n, nnz, crow_indices, col_indices, values]
231
+ return references, lhs_ptr
232
+
233
+
234
+ def create_cudss_csr_implicit_batch(
235
+ cuda_index_type, cuda_value_type, index_type, matrix_type, matrix_view_type, batch_indices, lhs, stream_holder
236
+ ):
237
+ # The lhs should be a wrapped CSRTensorHolder object in a memory space consistent with
238
+ # the execution mode.
239
+ assert lhs.num_dimensions > 2, "Internal error."
240
+
241
+ # We can't use an elegant implementation like for the dense implicit batch, where we
242
+ # index the samples in the tensor to form an explicit sequence and forward to the dense
243
+ # explicit batch implementation. This is because we can't rely on having the native
244
+ # LHS tensor after copying across memory spaces.
245
+
246
+ # For this function, we assume that the batch_indices are consistent with the
247
+ # specified lhs.
248
+ batch_count = len(batch_indices)
249
+
250
+ # The shape is constant for each sample.
251
+ shape = lhs.shape[-2], lhs.shape[-1]
252
+ m = wrap_operand(np.full(batch_count, shape[0], dtype=index_type))
253
+ n = wrap_operand(np.full(batch_count, shape[1], dtype=index_type))
254
+
255
+ # Explicitly unpack indices to avoid tensor[*b, ...] (support 3.10).
256
+ unpacked_indices = [tuple(b) + (...,) for b in batch_indices]
257
+
258
+ # Create a sequence of wrapped samples in the batch for each of the constituent dense
259
+ # arrays.
260
+ crow_indices_sequence = [lhs.crow_indices.__class__(lhs.crow_indices.tensor[u]) for u in unpacked_indices]
261
+ col_indices_sequence = [lhs.col_indices.__class__(lhs.col_indices.tensor[u]) for u in unpacked_indices]
262
+ values_sequence = [lhs.values.__class__(lhs.values.tensor[u]) for u in unpacked_indices]
263
+
264
+ # The pointer arrays must be on device. We'll first create it on the host, wrap and
265
+ # copy it to the device.
266
+ crow_indices = wrap_operand(np.array([o.data_ptr for o in crow_indices_sequence], dtype=np.uint64))
267
+ crow_indices = crow_indices.to(device_id=lhs.device_id, stream_holder=stream_holder)
268
+
269
+ col_indices = wrap_operand(np.array([o.data_ptr for o in col_indices_sequence], dtype=np.uint64))
270
+ col_indices = col_indices.to(device_id=lhs.device_id, stream_holder=stream_holder)
271
+
272
+ values = wrap_operand(np.array([o.data_ptr for o in values_sequence], dtype=np.uint64))
273
+ values = values.to(device_id=lhs.device_id, stream_holder=stream_holder)
274
+
275
+ # The nnz should be the same for each sample, but we'll iterate anyway.
276
+ nnz = wrap_operand(np.array([o.size for o in values_sequence], dtype=index_type))
277
+
278
+ lhs_ptr = cudss.matrix_create_batch_csr(
279
+ batch_count,
280
+ m.data_ptr,
281
+ n.data_ptr,
282
+ nnz.data_ptr,
283
+ crow_indices.data_ptr,
284
+ 0,
285
+ col_indices.data_ptr,
286
+ values.data_ptr,
287
+ cuda_index_type,
288
+ cuda_value_type,
289
+ matrix_type,
290
+ matrix_view_type,
291
+ cudss.IndexBase.ZERO,
292
+ )
293
+ references = [m, n, nnz, crow_indices, col_indices, values]
294
+ return references, lhs_ptr
295
+
296
+
297
+ def create_cudss_csr_wrapper(
298
+ cuda_index_type, cuda_value_type, index_type, matrix_type, matrix_view_type, batch_indices, lhs, stream_holder
299
+ ):
300
+ if isinstance(lhs, Sequence):
301
+ return create_cudss_csr_explicit_batch(
302
+ cuda_index_type, cuda_value_type, index_type, matrix_type, matrix_view_type, lhs, stream_holder
303
+ )
304
+
305
+ if len(lhs.shape) > 2:
306
+ return create_cudss_csr_implicit_batch(
307
+ cuda_index_type, cuda_value_type, index_type, matrix_type, matrix_view_type, batch_indices, lhs, stream_holder
308
+ )
309
+
310
+ return create_cudss_csr_matrix(cuda_index_type, cuda_value_type, matrix_type, matrix_view_type, lhs)
311
+
312
+
313
+ def update_cudss_csr_matrix_ptr(lhs_ptr, new_lhs):
314
+ # The new lhs should be a wrapped (CSRTensorHolder object) matrix in a memory space
315
+ # consistent with the execution mode.
316
+ # lhs_ptr is a cuDSS CSR matrix ptr.
317
+ assert len(new_lhs.shape) == 2, "Internal error."
318
+ cudss.matrix_set_csr_pointers(
319
+ lhs_ptr, new_lhs.crow_indices.data_ptr, 0, new_lhs.col_indices.data_ptr, new_lhs.values.data_ptr
320
+ )
321
+ references = []
322
+ return references
323
+
324
+
325
+ def update_cudss_csr_explicit_batch_ptr(lhs_ptr, new_lhs, stream_holder):
326
+ # The new lhs should be a sequence of wrapped (CSRTensorHolder object) matrix in a
327
+ # memory space consistent with the execution mode.
328
+ assert isinstance(new_lhs, Sequence), "Internal error."
329
+
330
+ # Take device ID of the first matrix, since it's the same for all.
331
+ device_id = new_lhs[0].device_id
332
+
333
+ # The pointers must be a device array. We'll first create it on the host, wrap and
334
+ # copy it to the device.
335
+ crow_indices = wrap_operand(np.array([o.crow_indices.data_ptr for o in new_lhs], dtype=np.uint64))
336
+ crow_indices = crow_indices.to(device_id=device_id, stream_holder=stream_holder)
337
+
338
+ col_indices = wrap_operand(np.array([o.col_indices.data_ptr for o in new_lhs], dtype=np.uint64))
339
+ col_indices = col_indices.to(device_id=device_id, stream_holder=stream_holder)
340
+
341
+ values = wrap_operand(np.array([o.values.data_ptr for o in new_lhs], dtype=np.uint64))
342
+ values = values.to(device_id=device_id, stream_holder=stream_holder)
343
+
344
+ cudss.matrix_set_batch_csr_pointers(lhs_ptr, crow_indices.data_ptr, 0, col_indices.data_ptr, values.data_ptr)
345
+
346
+ references = [crow_indices, col_indices, values]
347
+ return references
348
+
349
+
350
+ def update_cudss_csr_implicit_batch_ptr(lhs_ptr, batch_indices, new_lhs, stream_holder):
351
+ # The new lhs should be a wrapped (CSRTensorHolder object) tensor 3D or greater
352
+ # dimension in a memory space consistent with the execution mode.
353
+ assert new_lhs.num_dimensions > 2, "Internal error."
354
+
355
+ # We can't use an elegant implementation like for the dense implicit batch, where we
356
+ # index the samples in the tensor to form an explicit sequence and forward to the dense
357
+ # explicit batch implementation. This is because we can't rely on having the native
358
+ # LHS tensor after copying across memory spaces.
359
+
360
+ # Explicitly unpack indices to avoid tensor[*b, ...] (support 3.10).
361
+ unpacked_indices = [tuple(b) + (...,) for b in batch_indices]
362
+
363
+ # Create a sequence of wrapped samples in the batch for each of the constituent dense
364
+ # arrays.
365
+ crow_indices_sequence = [new_lhs.crow_indices.__class__(new_lhs.crow_indices.tensor[u]) for u in unpacked_indices]
366
+ col_indices_sequence = [new_lhs.col_indices.__class__(new_lhs.col_indices.tensor[u]) for u in unpacked_indices]
367
+ values_sequence = [new_lhs.values.__class__(new_lhs.values.tensor[u]) for u in unpacked_indices]
368
+
369
+ # The pointer arrays must be on device. We'll first create it on the host, wrap and
370
+ # copy it to the device.
371
+ crow_indices = wrap_operand(np.array([o.data_ptr for o in crow_indices_sequence], dtype=np.uint64))
372
+ crow_indices = crow_indices.to(device_id=new_lhs.device_id, stream_holder=stream_holder)
373
+
374
+ col_indices = wrap_operand(np.array([o.data_ptr for o in col_indices_sequence], dtype=np.uint64))
375
+ col_indices = col_indices.to(device_id=new_lhs.device_id, stream_holder=stream_holder)
376
+
377
+ values = wrap_operand(np.array([o.data_ptr for o in values_sequence], dtype=np.uint64))
378
+ values = values.to(device_id=new_lhs.device_id, stream_holder=stream_holder)
379
+
380
+ cudss.matrix_set_batch_csr_pointers(lhs_ptr, crow_indices.data_ptr, 0, col_indices.data_ptr, values.data_ptr)
381
+
382
+ references = [crow_indices, col_indices, values]
383
+ return references
384
+
385
+
386
+ def update_cudss_csr_ptr_wrapper(lhs_ptr, *, batch_indices=None, new_lhs=None, stream_holder=None):
387
+ # A convenience function to forward to the right implementation.
388
+ assert new_lhs is not None, "Internal error."
389
+
390
+ if isinstance(new_lhs, Sequence):
391
+ assert stream_holder is not None, "Internal error."
392
+ return update_cudss_csr_explicit_batch_ptr(lhs_ptr, new_lhs, stream_holder)
393
+
394
+ if len(new_lhs.shape) > 2:
395
+ assert batch_indices is not None and stream_holder is not None, "Internal error."
396
+ return update_cudss_csr_implicit_batch_ptr(lhs_ptr, batch_indices, new_lhs, stream_holder)
397
+
398
+ return update_cudss_csr_matrix_ptr(lhs_ptr, new_lhs)