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,320 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ __all__ = [
6
+ "MatmulEpilog",
7
+ "MatmulInnerShape",
8
+ "MatmulNumericalImplFlags",
9
+ "MatmulOptions",
10
+ "MatmulEpilogPreferences",
11
+ "MatmulPlanPreferences",
12
+ "MatmulQuantizationScales",
13
+ "MatmulReductionScheme",
14
+ "matrix_qualifiers_dtype",
15
+ ]
16
+
17
+ import dataclasses
18
+ from enum import IntEnum
19
+ from logging import Logger
20
+ from typing import Literal
21
+
22
+ import numpy as _np
23
+
24
+ from nvmath.bindings import cublas # type: ignore
25
+ from nvmath.bindings import cublasLt as cublaslt # type: ignore
26
+ from nvmath.internal import enum_utils
27
+ from nvmath.internal.utils import check_or_create_options
28
+ from nvmath.internal.mem_limit import check_memory_str
29
+ from nvmath.memory import BaseCUDAMemoryManager, BaseCUDAMemoryManagerAsync
30
+ from nvmath._utils import CudaDataType
31
+
32
+ MatmulEpilog = cublaslt.Epilogue
33
+ MatmulInnerShape = cublaslt.MatmulInnerShape
34
+ MatmulReductionScheme = cublaslt.ReductionScheme
35
+
36
+
37
+ @dataclasses.dataclass
38
+ class MatmulOptions:
39
+ """A data class for providing options to the :class:`Matmul` object and the wrapper
40
+ function :func:`matmul`.
41
+
42
+ Attributes:
43
+ compute_type (nvmath.linalg.ComputeType): CUDA compute type. A suitable compute type
44
+ will be selected if not specified.
45
+
46
+ scale_type (nvmath.CudaDataType): CUDA data type. A suitable data type consistent
47
+ with the compute type will be selected if not specified.
48
+
49
+ result_type (nvmath.CudaDataType): CUDA data type. A requested datatype of the
50
+ result. If not specified, this type will be determined based on the input types.
51
+ Non-default result types are only supported for narrow-precision (FP8 and lower)
52
+ operations.
53
+
54
+ result_amax (bool): If set, the absolute maximum (amax) of the result will be
55
+ returned in the auxiliary output tensor. Only supported for narrow-precision
56
+ (FP8 and lower) operations.
57
+
58
+ block_scaling (bool): If set, block scaling (MXFP8) will be used instead of
59
+ tensor-wide scaling for FP8 operations. If the result is a narrow-precision
60
+ (FP8 and lower) data type, scales used for result quantization will be returned
61
+ in the auxiliary output tensor as ``"d_out_scale"`` in UE8M0 format. For more
62
+ information on UE8M0 format, see the documentation of
63
+ :class:`~linalg.advanced.MatmulQuantizationScales`.
64
+ This option is only supported for narrow-precision (FP8 and lower) operations.
65
+
66
+ sm_count_target (int) : The number of SMs to use for execution. The default is 0,
67
+ corresponding to all available SMs.
68
+
69
+ fast_accumulation (bool) : Enable or disable FP8 fast accumulation mode. The default
70
+ is False (disabled).
71
+
72
+ device_id: CUDA device ordinal (only used if the operand resides on the CPU). The
73
+ default value is 0.
74
+
75
+ handle: Linear algebra library handle. A handle will be created if one is not
76
+ provided.
77
+
78
+ logger (logging.Logger): Python Logger object. The root logger will be used if a
79
+ logger object is not provided.
80
+
81
+ memory_limit: Maximum memory available to the MM operation. It can be specified as a
82
+ value (with optional suffix like K[iB], M[iB], G[iB]) or as a percentage. The
83
+ default is 80% of the device memory.
84
+
85
+ blocking: A flag specifying the behavior of the execution functions and methods,
86
+ such as :func:`matmul` and :meth:`Matmul.execute`. When ``blocking`` is `True`,
87
+ the execution methods do not return until the operation is complete. When
88
+ ``blocking`` is ``"auto"``, the methods return immediately when the inputs are
89
+ on the GPU. The execution methods always block when the operands are on the CPU
90
+ to ensure that the user doesn't inadvertently use the result before it becomes
91
+ available. The default is ``"auto"``.
92
+
93
+ allocator: An object that supports the :class:`BaseCUDAMemoryManager` protocol, used
94
+ to draw device memory. If an allocator is not provided, a memory allocator from
95
+ the library package will be used (:func:`torch.cuda.caching_allocator_alloc` for
96
+ PyTorch operands, :func:`cupy.cuda.alloc` otherwise).
97
+
98
+ See Also:
99
+ :class:`Matmul`, :func:`matmul`
100
+ """
101
+
102
+ compute_type: int | None = None
103
+ scale_type: int | None = None
104
+ result_type: int | None = None
105
+ result_amax: bool = False
106
+ block_scaling: bool = False
107
+ sm_count_target: int | None = 0
108
+ fast_accumulation: bool | None = False
109
+ device_id: int = 0
110
+ handle: int | None = None
111
+ logger: Logger | None = None
112
+ memory_limit: int | str | None = r"80%"
113
+ blocking: Literal[True, "auto"] = "auto"
114
+ allocator: BaseCUDAMemoryManager | None = None
115
+
116
+ def __post_init__(self):
117
+ # Defer computing the memory limit till we know the device the network is on.
118
+
119
+ if self.compute_type is not None:
120
+ self.compute_type = cublas.ComputeType(self.compute_type)
121
+
122
+ if self.scale_type is not None:
123
+ self.scale_type = CudaDataType(self.scale_type)
124
+
125
+ if self.sm_count_target is None:
126
+ self.sm_count_target = MatmulOptions.sm_count_target
127
+
128
+ if self.fast_accumulation is None:
129
+ self.fast_accumulation = MatmulOptions.fast_accumulation
130
+
131
+ if self.device_id is None:
132
+ self.device_id = 0
133
+
134
+ if self.memory_limit is None:
135
+ self.memory_limit = MatmulOptions.memory_limit
136
+
137
+ check_memory_str(self.memory_limit, "memory limit")
138
+
139
+ if self.blocking not in (True, "auto"):
140
+ raise ValueError("The value specified for blocking must be either True or 'auto'.")
141
+
142
+ if self.allocator is not None and not isinstance(self.allocator, BaseCUDAMemoryManager | BaseCUDAMemoryManagerAsync):
143
+ raise TypeError("The allocator must be an object of type that fulfils the BaseCUDAMemoryManager protocol.")
144
+
145
+
146
+ matrix_qualifiers_dtype = _np.dtype([("structure", object), ("is_conjugate", "<i4")])
147
+
148
+
149
+ class MatmulNumericalImplFlags(IntEnum):
150
+ """
151
+ These flags can be combined with the | operator: OP_TYPE_FMA | OP_TYPE_TENSOR_HMMA ...
152
+ """
153
+
154
+ OP_TYPE_FMA = 0x01 << 0
155
+ OP_TYPE_TENSOR_HMMA = 0x02 << 0
156
+ OP_TYPE_TENSOR_IMMA = 0x04 << 0
157
+ OP_TYPE_TENSOR_DMMA = 0x08 << 0
158
+ OP_TYPE_TENSOR_MASK = 0xFE << 0
159
+ OP_TYPE_MASK = 0xFF << 0
160
+
161
+ ACCUMULATOR_16F = 0x01 << 8
162
+ ACCUMULATOR_32F = 0x02 << 8
163
+ ACCUMULATOR_64F = 0x04 << 8
164
+ ACCUMULATOR_32I = 0x08 << 8
165
+ ACCUMULATOR_TYPE_MASK = 0xFF << 8
166
+
167
+ INPUT_TYPE_16F = 0x01 << 16
168
+ INPUT_TYPE_16BF = 0x02 << 16
169
+ INPUT_TYPE_TF32 = 0x04 << 16
170
+ INPUT_TYPE_32F = 0x08 << 16
171
+ INPUT_TYPE_64F = 0x10 << 16
172
+ INPUT_TYPE_8I = 0x20 << 16
173
+ INPUT_TYPE_8F_E4M3 = 0x40 << 16
174
+ INPUT_TYPE_8F_E5M2 = 0x80 << 16
175
+ INPUT_TYPE_MASK = 0xFF << 16
176
+
177
+ GAUSSIAN = 0x01 << 32
178
+
179
+ ALL = (1 << 64) - 1
180
+
181
+
182
+ @dataclasses.dataclass
183
+ class MatmulEpilogPreferences:
184
+ """A data class for providing epilog options as part of ``preferences`` to the
185
+ :meth:`Matmul.plan` method and the wrapper function :func:`matmul`.
186
+
187
+ Attributes:
188
+ aux_type (nvmath.CudaDataType): The requested datatype of the
189
+ epilog auxiliary output. If not specified, this type will be determined based on
190
+ the input types. Non-default auxiliary output types are only supported for
191
+ narrow-precision operations and certain epilogs. For more details on the
192
+ supported combinations, see ``CUBLASLT_MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE`` in
193
+ cuBLAS documentation. If this option is set to a narrow-precision data type,
194
+ an additional epilog input ``"aux_quantization_scale"`` needs to be specified.
195
+
196
+ aux_amax (bool): If set, the absolute maximum (amax) of the epilog
197
+ auxiliary output will be returned in the auxiliary output tensor.
198
+ Only supported when ``aux_type`` option is set to a narrow-precision
199
+ data type.
200
+
201
+ See Also:
202
+ :meth:`Matmul.plan`, :func:`matmul`, :class:`MatmulPlanPreferences`
203
+ """
204
+
205
+ aux_type: int | None = None
206
+ aux_amax: bool = False
207
+
208
+
209
+ @dataclasses.dataclass
210
+ class MatmulPlanPreferences:
211
+ """A data class for providing options to the :meth:`Matmul.plan` method and the
212
+ wrapper function :func:`matmul`.
213
+
214
+ Attributes:
215
+ reduction_scheme_mask (:class:`nvmath.linalg.advanced.MatmulReductionScheme`):
216
+ Enumerators from
217
+ :class:`nvmath.linalg.advanced.MatmulReductionScheme` combined with
218
+ bitwise operator ``|``. The default is all reduction schemes.
219
+
220
+ max_waves_count (float) : The maximum wave count. Selecting a value greater than 0.
221
+ will exclude algorithms with device utilization greater than specified. The
222
+ default is 0.
223
+
224
+ numerical_impl_mask (:class:`nvmath.linalg.advanced.MatmulNumericalImplFlags`):
225
+ Enumerators from
226
+ :class:`nvmath.nvmath.linalg.advanced.MatmulNumericalImplFlags` combined with
227
+ bitwise operator ``|``. The default is all numerical implementation flag
228
+ choices.
229
+
230
+ limit (int) : The number of algorithms to consider. If not specified, a suitable
231
+ default will be chosen.
232
+
233
+ epilog (:class:`nvmath.linalg.advanced.MatmulEpilogPreferences`):
234
+ Epilog preferences (as an object of class
235
+ :class:`~nvmath.linalg.advanced.MatmulEpilogPreferences` or a `dict`).
236
+
237
+ See Also:
238
+ :meth:`Matmul.plan`, :func:`matmul`
239
+ """
240
+
241
+ reduction_scheme_mask: cublaslt.ReductionScheme | None = cublaslt.ReductionScheme.MASK
242
+ max_waves_count: float | None = 0.0
243
+ numerical_impl_mask: MatmulNumericalImplFlags | None = MatmulNumericalImplFlags.ALL
244
+ limit: int = 8
245
+ epilog: MatmulEpilogPreferences | None = None
246
+
247
+ def __post_init__(self):
248
+ if self.reduction_scheme_mask is None:
249
+ self.reduction_scheme_mask = MatmulPlanPreferences.reduction_scheme_mask
250
+ else:
251
+ self.reduction_scheme_mask = cublaslt.ReductionScheme(self.reduction_scheme_mask)
252
+
253
+ if self.max_waves_count is None:
254
+ self.max_waves_count = MatmulPlanPreferences.max_waves_count
255
+
256
+ if self.numerical_impl_mask is None:
257
+ self.numerical_impl_mask = MatmulPlanPreferences.numerical_impl_mask
258
+
259
+ if self.limit is None:
260
+ self.limit = MatmulPlanPreferences.limit
261
+
262
+ self.epilog = check_or_create_options(MatmulEpilogPreferences, self.epilog, "epilog preferences")
263
+
264
+
265
+ @dataclasses.dataclass
266
+ class MatmulQuantizationScales:
267
+ """A data class for providing quantization_scales to :class:`Matmul` constructor and the
268
+ wrapper function :func:`matmul`.
269
+
270
+ Scales can only be set for narrow-precision (FP8 and lower) matrices.
271
+
272
+ When ``MatmulOptions.block_scaling=False``, each scale can either be a scalar (integer
273
+ or float) or a single-element tensor of shape ``()`` or ``(1,)``.
274
+
275
+ When ``MatmulOptions.block_scaling=True``, each scale should be a 1D ``uint8`` tensor
276
+ with layout matching the requirements of cuBLAS MXFP8 scaling tensor. Values in the
277
+ tensor will be interpreted as UE8M0 values. This means that a value :math:`x` in the
278
+ scaling tensor will cause cuBLAS to multiply the respective block by :math:`2^{x-127}`.
279
+
280
+ Attributes:
281
+ a (float or Tensor) : Scale for matrix A.
282
+
283
+ b (float or Tensor) : Scale for matrix B.
284
+
285
+ c (float or Tensor) : Scale for matrix C.
286
+
287
+ d (float or Tensor) : Scale for matrix D.
288
+
289
+ See Also:
290
+ :class:`Matmul`, :func:`matmul`
291
+ """
292
+
293
+ a: float | None = None
294
+ b: float | None = None
295
+ c: float | None = None
296
+ d: float | None = None
297
+
298
+
299
+ _create_options = enum_utils.create_options_class_from_enum
300
+ _algo_cap_enum = cublaslt.MatmulAlgoCapAttribute
301
+ _get_dtype = cublaslt.get_matmul_algo_cap_attribute_dtype
302
+
303
+ AlgorithmCapabilities = _create_options(
304
+ "AlgorithmCapabilities", _algo_cap_enum, _get_dtype, "algorithm capabilities", "(?P<option_name>.*)"
305
+ )
306
+
307
+
308
+ def algorithm_capabilities_str(self):
309
+ names = [field.name for field in dataclasses.fields(self)]
310
+ width = max(len(n) for n in names)
311
+ s = """Algorithm Capabilities (refer to `MatmulAlgoCapAttribute` for documentation):
312
+ """
313
+ for name in names:
314
+ s += f" {name:{width}} = {getattr(self, name)}\n"
315
+ return s
316
+
317
+
318
+ AlgorithmCapabilities.__str__ = algorithm_capabilities_str
319
+
320
+ del _create_options, _algo_cap_enum, _get_dtype
@@ -0,0 +1,5 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from . import matmul as matmul # noqa: F403
@@ -0,0 +1,173 @@
1
+ # Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from nvmath.internal.tensor_wrapper import wrap_operand
6
+ from nvmath.internal.utils import create_empty_tensor, infer_object_package, get_or_create_stream
7
+
8
+ __all__ = ["create_mxfp8_scale", "invert_mxfp8_scale", "get_mxfp8_scale_offset", "apply_mxfp8_scale"]
9
+
10
+
11
+ def _validate_tensor(x, where, tensor_name="tensor", dtype=None):
12
+ """
13
+ Validate the tensor package and dtype.
14
+ Args:
15
+ x: wrapped tensor object
16
+ where: name of the function that is performing the validation
17
+ tensor_name: name of the tensor to use in the error messages
18
+ dtype: if not None, check that the object dtype matches the specified dtype
19
+ """
20
+ package = infer_object_package(x)
21
+ if package != "torch":
22
+ raise ValueError(
23
+ f"Only torch.Tensor is currently supported by function '{where}'; the "
24
+ f"specified {tensor_name} belongs to '{package}' package."
25
+ )
26
+ x = wrap_operand(x)
27
+ if dtype is not None and x.dtype != dtype:
28
+ raise ValueError(
29
+ f"The function '{where}' requires the specified {tensor_name} to have dtype "
30
+ f"'{dtype}', whereas it has dtype '{x.dtype}'."
31
+ )
32
+
33
+
34
+ def _validate_mxfp8_scale(scale, where, x=None):
35
+ if x is not None:
36
+ _validate_tensor(x, where)
37
+ x = wrap_operand(x)
38
+ _validate_tensor(scale, where, tensor_name="scale tensor", dtype="uint8")
39
+ scale = wrap_operand(scale)
40
+
41
+ if x is not None and scale.shape != (x.size // 32,):
42
+ raise ValueError(
43
+ f"The shape of scale {scale.shape} is not compatible with a tensor of shape {x.shape}. "
44
+ f"The expected scale shape is {(x.size // 32,)}."
45
+ )
46
+ return scale
47
+
48
+
49
+ def create_mxfp8_scale(x, exponent, stream=None):
50
+ """
51
+ Create MXFP8 block scale with the same value for the whole tensor ``x``.
52
+
53
+ Args:
54
+ x: The tensor to create the block scale for
55
+
56
+ exponent: An integer from [-127, 128] range. Effective scale will be ``2^exponent``.
57
+
58
+ stream: Optional stream to create the block scale on.
59
+ Defaults to the stream of ``x``.
60
+
61
+ Returns:
62
+ An MXFP8 block scale factors tensor to be used with MXFP8 computations.
63
+ """
64
+ _validate_tensor(x, "create_mxfp8_scale")
65
+ x = wrap_operand(x)
66
+
67
+ if not -127 <= exponent <= 128:
68
+ raise ValueError("The exponent should be an integer from [-127, 128] range.")
69
+
70
+ stream_holder = None if x.device_id == "cpu" else get_or_create_stream(x.device_id, stream, x.name)
71
+ scale = create_empty_tensor(
72
+ x.__class__, (x.size // 32,), "uint8", device_id=x.device_id, stream_holder=stream_holder, verify_strides=False
73
+ )
74
+ scale.tensor[:] = exponent + 127
75
+ return scale.tensor
76
+
77
+
78
+ def invert_mxfp8_scale(scale):
79
+ """
80
+ Compute a reciprocal of MXFP8 block scale.
81
+
82
+ Args:
83
+ scale: MXFP8 block scale tensor.
84
+
85
+ Returns:
86
+ An MXFP8 block scale factors tensor with reciprocals of the values in ``scale``.
87
+ """
88
+ _validate_mxfp8_scale(scale, "invert_mxfp8_scale")
89
+
90
+ scale[scale == 255] = 254 # Prevent the overflow
91
+ return (127 + 127) - scale
92
+
93
+
94
+ def get_mxfp8_scale_offset(x, index):
95
+ """
96
+ Computes the offset of MXFP8 scale used for element ``x[index]``.
97
+
98
+ Args:
99
+ x: The tensor to which ``index`` refers.
100
+
101
+ index: A tuple of tensor indices. This function supports broadcasting,
102
+ so the `index` can be a tuple of integers or a tuple of tensors.
103
+
104
+ Returns:
105
+ A single integer indicating an offset to the MXFP8 block scale factor which
106
+ is applied to ``x[index]`` during scaling.
107
+
108
+ Note:
109
+ In typical use-cases, there should be no need to manually modify MXFP8 scales.
110
+ The scales returned as ``"d_out_scale"`` by one multiplication can be directly
111
+ reused as input scales for another multiplication.
112
+ """
113
+
114
+ _validate_tensor(x, where="get_mxfp8_scale_offset")
115
+ x = wrap_operand(x)
116
+ ndim = len(x.shape)
117
+ if len(index) != ndim:
118
+ raise ValueError("Index length should match the number of dimensions of x.")
119
+
120
+ if ndim == 2:
121
+ batch_offset = 0
122
+ elif ndim > 2:
123
+ # Compute batch offset
124
+ batch_strides = x.strides[:-2]
125
+ batch_index = index[:-2]
126
+ batch_offset = sum(i * stride for i, stride in zip(batch_index, batch_strides, strict=True)) // min(batch_strides)
127
+ else:
128
+ raise ValueError(f"Got {ndim}-D tensor in `get_mxfp8_scale_offset`, but expected at least 2-D.")
129
+ major_d, minor_d = (-2, -1) if x.strides[-2] > x.strides[-1] else (-1, -2)
130
+ major, minor, minor_length = index[major_d], index[minor_d], x.shape[minor_d]
131
+
132
+ # Compute tile offset
133
+ tile_minor = minor // 128
134
+ tile_major = major // 128
135
+ tile_offset = (minor_length // 128) * tile_major + tile_minor
136
+ minor = minor % 128
137
+ major = major % 128
138
+
139
+ # Compute offset in the tile
140
+ minor = minor // 32
141
+ offset = (major % 32) * 16 + (major // 32) * 4 + minor
142
+
143
+ # Add the offsets together
144
+ tile_size = 128 * 128 // 32
145
+ matrix_size = x.shape[-1] * x.shape[-2] // 32
146
+ return batch_offset * matrix_size + tile_offset * tile_size + offset
147
+
148
+
149
+ def apply_mxfp8_scale(x, scale):
150
+ """
151
+ Apply MXFP8 block scale factors to tensor ``x``.
152
+
153
+ Args:
154
+ x: The tensor to which the scaling should be applied.
155
+
156
+ scale: The block scale factors to apply.
157
+
158
+ Returns:
159
+ A ``float32`` tensor with values of ``x`` with scales applied.
160
+
161
+ Note:
162
+ This function is not intended for production usage due to its relatively low
163
+ performance and high memory consumption. Instead of applying the scales
164
+ manually using this function, use
165
+ :attr:`~nvmath.linalg.advanced.MatmulOptions.result_type` to request non-FP8 output.
166
+ """
167
+ scale = _validate_mxfp8_scale(scale, "apply_mxfp8_scale", x=x)
168
+ import torch
169
+
170
+ idx = get_mxfp8_scale_offset(x, torch.meshgrid(*(torch.arange(d) for d in x.shape), indexing="ij")).to(x.device)
171
+
172
+ actual_scale = 2 ** (scale.tensor.type(torch.float32)[idx] - 127)
173
+ return x.type(torch.float32) * actual_scale