Skip to main content

baracuda_cusparse_sys/
lib.rs

1//! Raw FFI + dynamic loader for NVIDIA cuSPARSE (generic API subset).
2//!
3//! `baracuda-cusparse` wraps this with a safe, typed API. Use this
4//! crate directly only if you need a function that the safe layer
5//! hasn't wrapped yet (in which case please file a bug).
6
7#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
8#![warn(missing_debug_implementations)]
9
10use core::ffi::{c_int, c_void};
11use std::sync::OnceLock;
12
13use baracuda_core::{Library, LoaderError, platform};
14use baracuda_cuda_sys::runtime::cudaStream_t;
15use baracuda_types::CudaStatus;
16
17// ---- handles --------------------------------------------------------------
18
19/// Opaque cuSPARSE handle.
20pub type cusparseHandle_t = *mut c_void;
21/// Opaque sparse-matrix descriptor (CSR / CSC / COO / BSR).
22pub type cusparseSpMatDescr_t = *mut c_void;
23/// Opaque dense-matrix descriptor.
24pub type cusparseDnMatDescr_t = *mut c_void;
25/// Opaque dense-vector descriptor.
26pub type cusparseDnVecDescr_t = *mut c_void;
27/// Opaque SpGEMM intermediate-state descriptor.
28pub type cusparseSpGEMMDescr_t = *mut c_void;
29/// Opaque SpSV intermediate-state descriptor.
30pub type cusparseSpSVDescr_t = *mut c_void;
31/// Opaque SpSM intermediate-state descriptor.
32pub type cusparseSpSMDescr_t = *mut c_void;
33/// Opaque legacy-API matrix descriptor.
34pub type cusparseMatDescr_t = *mut c_void;
35
36// ---- enums ----------------------------------------------------------------
37
38/// Transpose selector for cuSPARSE routines (matches cuBLAS values).
39#[repr(i32)]
40#[derive(Copy, Clone, Debug, Eq, PartialEq)]
41pub enum cusparseOperation_t {
42    /// No transpose.
43    N = 0,
44    /// Transpose.
45    T = 1,
46    /// Conjugate transpose.
47    C = 2,
48}
49
50/// Index-element dtype for sparse-matrix offsets and column indices.
51#[repr(i32)]
52#[derive(Copy, Clone, Debug, Eq, PartialEq)]
53pub enum cusparseIndexType_t {
54    /// Unsigned 16-bit indices.
55    I16U = 1,
56    /// Signed 32-bit indices.
57    I32I = 2,
58    /// Signed 64-bit indices.
59    I64I = 3,
60}
61
62/// Zero- vs one-based indexing for sparse-matrix index arrays.
63#[repr(i32)]
64#[derive(Copy, Clone, Debug, Eq, PartialEq)]
65pub enum cusparseIndexBase_t {
66    /// Zero-based indexing.
67    Zero = 0,
68    /// One-based indexing (Fortran convention).
69    One = 1,
70}
71
72/// Row-major vs column-major dense storage order.
73#[repr(i32)]
74#[derive(Copy, Clone, Debug, Eq, PartialEq)]
75pub enum cusparseOrder_t {
76    /// Row-major dense storage.
77    Row = 1,
78    /// Column-major dense storage.
79    Col = 2,
80}
81
82/// Algorithm selector for `cusparseSpMV`.
83#[repr(i32)]
84#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85pub enum cusparseSpMVAlg_t {
86    /// Driver-chosen default.
87    Default = 0,
88    /// CSR algorithm 1 (deterministic).
89    CsrAlg1 = 2,
90    /// CSR algorithm 2 (higher throughput).
91    CsrAlg2 = 3,
92    /// COO algorithm 1.
93    CooAlg1 = 1,
94    /// COO algorithm 2.
95    CooAlg2 = 4,
96}
97
98/// Algorithm selector for `cusparseSpMM`.
99#[repr(i32)]
100#[derive(Copy, Clone, Debug, Eq, PartialEq)]
101pub enum cusparseSpMMAlg_t {
102    /// Driver-chosen default.
103    Default = 0,
104    /// COO algorithm 1.
105    CooAlg1 = 1,
106    /// CSR algorithm 1.
107    CsrAlg1 = 2,
108    /// COO algorithm 2.
109    CooAlg2 = 3,
110    /// COO algorithm 3.
111    CooAlg3 = 4,
112    /// CSR algorithm 2.
113    CsrAlg2 = 5,
114    /// CSR algorithm 3.
115    CsrAlg3 = 6,
116    /// BSR algorithm.
117    Bsr = 7,
118    /// CSR algorithm 4.
119    CsrAlg4 = 8,
120}
121
122/// Algorithm selector for `cusparseSpGEMM`.
123#[repr(i32)]
124#[derive(Copy, Clone, Debug, Eq, PartialEq)]
125pub enum cusparseSpGEMMAlg_t {
126    /// Driver-chosen default.
127    Default = 0,
128    /// SpGEMM algorithm 1.
129    Alg1 = 1,
130    /// SpGEMM algorithm 2.
131    Alg2 = 2,
132    /// SpGEMM algorithm 3.
133    Alg3 = 3,
134    /// Memory-saving default for CSR inputs.
135    CsrMemoryDefault = 4,
136}
137
138/// Algorithm selector for `cusparseSpSV`.
139#[repr(i32)]
140#[derive(Copy, Clone, Debug, Eq, PartialEq)]
141pub enum cusparseSpSVAlg_t {
142    /// Driver-chosen default.
143    Default = 0,
144}
145
146/// Algorithm selector for `cusparseSpSM`.
147#[repr(i32)]
148#[derive(Copy, Clone, Debug, Eq, PartialEq)]
149pub enum cusparseSpSMAlg_t {
150    /// Driver-chosen default.
151    Default = 0,
152}
153
154/// Algorithm selector for `cusparseSDDMM`.
155#[repr(i32)]
156#[derive(Copy, Clone, Debug, Eq, PartialEq)]
157pub enum cusparseSDDMMAlg_t {
158    /// Driver-chosen default.
159    Default = 0,
160}
161
162/// Algorithm selector for CSR-to-CSC conversion.
163#[repr(i32)]
164#[derive(Copy, Clone, Debug, Eq, PartialEq)]
165pub enum cusparseCsr2CscAlg_t {
166    /// CSR-to-CSC algorithm 1.
167    Alg1 = 1,
168    /// CSR-to-CSC algorithm 2.
169    Alg2 = 2,
170}
171
172impl cusparseCsr2CscAlg_t {
173    /// Alias for `cusparseCsr2CscAlg_t::Alg1`.
174    pub const DEFAULT: Self = Self::Alg1;
175}
176
177/// Triangular fill mode for sparse triangular routines.
178#[repr(i32)]
179#[derive(Copy, Clone, Debug, Eq, PartialEq)]
180pub enum cusparseFillMode_t {
181    /// Lower-triangular.
182    Lower = 0,
183    /// Upper-triangular.
184    Upper = 1,
185}
186
187/// Diagonal-unit selector for sparse triangular routines.
188#[repr(i32)]
189#[derive(Copy, Clone, Debug, Eq, PartialEq)]
190pub enum cusparseDiagType_t {
191    /// Non-unit diagonal.
192    NonUnit = 0,
193    /// Unit diagonal.
194    Unit = 1,
195}
196
197/// Attribute key for `cusparseSpMatSetAttribute` / `*GetAttribute`.
198#[repr(i32)]
199#[derive(Copy, Clone, Debug, Eq, PartialEq)]
200pub enum cusparseSpMatAttribute_t {
201    /// Fill-mode attribute (lower / upper triangular).
202    FillMode = 0,
203    /// Diagonal-type attribute (unit / non-unit).
204    DiagType = 1,
205}
206
207/// `cudaDataType` values used by cuSPARSE / cuSOLVER's generic APIs. Only
208/// the subset we actually use at v0.1.
209#[repr(i32)]
210#[derive(Copy, Clone, Debug, Eq, PartialEq)]
211pub enum cudaDataType {
212    /// 32-bit real (`f32`).
213    R_32F = 0,
214    /// 64-bit real (`f64`).
215    R_64F = 1,
216    /// 16-bit real (IEEE half / `f16`).
217    R_16F = 2,
218    /// 32-bit complex (`Complex<f32>`).
219    C_32F = 4,
220    /// 64-bit complex (`Complex<f64>`).
221    C_64F = 5,
222    /// 16-bit real bfloat16.
223    R_16BF = 14,
224}
225
226// ---- status ---------------------------------------------------------------
227
228/// Status / error code returned by cuSPARSE FFI calls.
229#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
230#[repr(transparent)]
231pub struct cusparseStatus_t(pub i32);
232
233impl cusparseStatus_t {
234    /// Status: success.
235    pub const SUCCESS: Self = Self(0);
236    /// Status: not initialized.
237    pub const NOT_INITIALIZED: Self = Self(1);
238    /// Status: alloc failed.
239    pub const ALLOC_FAILED: Self = Self(2);
240    /// Status: invalid value.
241    pub const INVALID_VALUE: Self = Self(3);
242    /// Status: arch mismatch.
243    pub const ARCH_MISMATCH: Self = Self(4);
244    /// Status: mapping error.
245    pub const MAPPING_ERROR: Self = Self(5);
246    /// Status: execution failed.
247    pub const EXECUTION_FAILED: Self = Self(6);
248    /// Status: internal error.
249    pub const INTERNAL_ERROR: Self = Self(7);
250    /// Status: matrix type not supported.
251    pub const MATRIX_TYPE_NOT_SUPPORTED: Self = Self(8);
252    /// Status: zero pivot.
253    pub const ZERO_PIVOT: Self = Self(9);
254    /// Status: not supported.
255    pub const NOT_SUPPORTED: Self = Self(10);
256    /// Status: insufficient resources.
257    pub const INSUFFICIENT_RESOURCES: Self = Self(11);
258
259    /// Returns `true` when this is the success status code.
260    pub const fn is_success(self) -> bool {
261        self.0 == 0
262    }
263}
264
265impl CudaStatus for cusparseStatus_t {
266    fn code(self) -> i32 {
267        self.0
268    }
269    fn name(self) -> &'static str {
270        match self.0 {
271            0 => "CUSPARSE_STATUS_SUCCESS",
272            1 => "CUSPARSE_STATUS_NOT_INITIALIZED",
273            2 => "CUSPARSE_STATUS_ALLOC_FAILED",
274            3 => "CUSPARSE_STATUS_INVALID_VALUE",
275            4 => "CUSPARSE_STATUS_ARCH_MISMATCH",
276            6 => "CUSPARSE_STATUS_EXECUTION_FAILED",
277            7 => "CUSPARSE_STATUS_INTERNAL_ERROR",
278            10 => "CUSPARSE_STATUS_NOT_SUPPORTED",
279            _ => "CUSPARSE_STATUS_UNRECOGNIZED",
280        }
281    }
282    fn description(self) -> &'static str {
283        match self.0 {
284            0 => "success",
285            1 => "cuSPARSE handle not initialized",
286            2 => "allocation failed",
287            3 => "invalid argument",
288            6 => "GPU execution failed",
289            10 => "operation not supported",
290            _ => "unrecognized cuSPARSE status code",
291        }
292    }
293    fn is_success(self) -> bool {
294        cusparseStatus_t::is_success(self)
295    }
296    fn library(self) -> &'static str {
297        "cusparse"
298    }
299}
300
301// ---- function-pointer types ----------------------------------------------
302
303/// cuSPARSE: create a cuSPARSE handle. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
304pub type PFN_cusparseCreate =
305    unsafe extern "C" fn(handle: *mut cusparseHandle_t) -> cusparseStatus_t;
306/// cuSPARSE: destroy a cuSPARSE handle. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
307pub type PFN_cusparseDestroy = unsafe extern "C" fn(handle: cusparseHandle_t) -> cusparseStatus_t;
308/// cuSPARSE: bind a CUDA stream to a cuSPARSE handle. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
309pub type PFN_cusparseSetStream =
310    unsafe extern "C" fn(handle: cusparseHandle_t, stream: cudaStream_t) -> cusparseStatus_t;
311/// cuSPARSE: return the cuSPARSE library version. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
312pub type PFN_cusparseGetVersion =
313    unsafe extern "C" fn(handle: cusparseHandle_t, version: *mut c_int) -> cusparseStatus_t;
314
315/// cuSPARSE: create a CSR sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
316pub type PFN_cusparseCreateCsr = unsafe extern "C" fn(
317    sp_mat: *mut cusparseSpMatDescr_t,
318    rows: i64,
319    cols: i64,
320    nnz: i64,
321    csr_row_offsets: *mut c_void,
322    csr_col_ind: *mut c_void,
323    csr_values: *mut c_void,
324    csr_row_offsets_type: cusparseIndexType_t,
325    csr_col_ind_type: cusparseIndexType_t,
326    idx_base: cusparseIndexBase_t,
327    value_type: cudaDataType,
328) -> cusparseStatus_t;
329/// cuSPARSE: destroy a sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
330pub type PFN_cusparseDestroySpMat =
331    unsafe extern "C" fn(descr: cusparseSpMatDescr_t) -> cusparseStatus_t;
332
333/// cuSPARSE: create a dense-vector descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
334pub type PFN_cusparseCreateDnVec = unsafe extern "C" fn(
335    descr: *mut cusparseDnVecDescr_t,
336    size: i64,
337    values: *mut c_void,
338    value_type: cudaDataType,
339) -> cusparseStatus_t;
340/// cuSPARSE: destroy a dense-vector descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
341pub type PFN_cusparseDestroyDnVec =
342    unsafe extern "C" fn(descr: cusparseDnVecDescr_t) -> cusparseStatus_t;
343
344/// cuSPARSE: workspace-size query for sparse matrix-vector multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
345pub type PFN_cusparseSpMV_bufferSize = unsafe extern "C" fn(
346    handle: cusparseHandle_t,
347    op: cusparseOperation_t,
348    alpha: *const c_void,
349    mat_a: cusparseSpMatDescr_t,
350    vec_x: cusparseDnVecDescr_t,
351    beta: *const c_void,
352    vec_y: cusparseDnVecDescr_t,
353    compute_type: cudaDataType,
354    alg: cusparseSpMVAlg_t,
355    buffer_size: *mut usize,
356) -> cusparseStatus_t;
357
358/// cuSPARSE: sparse matrix-vector multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
359pub type PFN_cusparseSpMV = unsafe extern "C" fn(
360    handle: cusparseHandle_t,
361    op: cusparseOperation_t,
362    alpha: *const c_void,
363    mat_a: cusparseSpMatDescr_t,
364    vec_x: cusparseDnVecDescr_t,
365    beta: *const c_void,
366    vec_y: cusparseDnVecDescr_t,
367    compute_type: cudaDataType,
368    alg: cusparseSpMVAlg_t,
369    external_buffer: *mut c_void,
370) -> cusparseStatus_t;
371
372// ---- CSC / COO / BSR / Dense descriptors ---------------------------------
373
374/// cuSPARSE: create a CSC sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
375pub type PFN_cusparseCreateCsc = unsafe extern "C" fn(
376    sp_mat: *mut cusparseSpMatDescr_t,
377    rows: i64,
378    cols: i64,
379    nnz: i64,
380    csc_col_offsets: *mut c_void,
381    csc_row_ind: *mut c_void,
382    csc_values: *mut c_void,
383    csc_col_offsets_type: cusparseIndexType_t,
384    csc_row_ind_type: cusparseIndexType_t,
385    idx_base: cusparseIndexBase_t,
386    value_type: cudaDataType,
387) -> cusparseStatus_t;
388
389/// cuSPARSE: create a COO sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
390pub type PFN_cusparseCreateCoo = unsafe extern "C" fn(
391    sp_mat: *mut cusparseSpMatDescr_t,
392    rows: i64,
393    cols: i64,
394    nnz: i64,
395    coo_row_ind: *mut c_void,
396    coo_col_ind: *mut c_void,
397    coo_values: *mut c_void,
398    coo_idx_type: cusparseIndexType_t,
399    idx_base: cusparseIndexBase_t,
400    value_type: cudaDataType,
401) -> cusparseStatus_t;
402
403/// cuSPARSE: create a BSR sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
404pub type PFN_cusparseCreateBsr = unsafe extern "C" fn(
405    sp_mat: *mut cusparseSpMatDescr_t,
406    brows: i64,
407    bcols: i64,
408    bnnz: i64,
409    row_block_dim: i64,
410    col_block_dim: i64,
411    bsr_row_offsets: *mut c_void,
412    bsr_col_ind: *mut c_void,
413    bsr_values: *mut c_void,
414    bsr_row_offsets_type: cusparseIndexType_t,
415    bsr_col_ind_type: cusparseIndexType_t,
416    idx_base: cusparseIndexBase_t,
417    value_type: cudaDataType,
418    order: cusparseOrder_t,
419) -> cusparseStatus_t;
420
421/// cuSPARSE: create a dense-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
422pub type PFN_cusparseCreateDnMat = unsafe extern "C" fn(
423    descr: *mut cusparseDnMatDescr_t,
424    rows: i64,
425    cols: i64,
426    ld: i64,
427    values: *mut c_void,
428    value_type: cudaDataType,
429    order: cusparseOrder_t,
430) -> cusparseStatus_t;
431
432/// cuSPARSE: destroy a dense-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
433pub type PFN_cusparseDestroyDnMat =
434    unsafe extern "C" fn(descr: cusparseDnMatDescr_t) -> cusparseStatus_t;
435
436/// cuSPARSE: query rows, cols, and nnz of a sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
437pub type PFN_cusparseSpMatGetSize = unsafe extern "C" fn(
438    sp_mat: cusparseSpMatDescr_t,
439    rows: *mut i64,
440    cols: *mut i64,
441    nnz: *mut i64,
442) -> cusparseStatus_t;
443
444/// cuSPARSE: set an attribute (fill mode, diag type) on a sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
445pub type PFN_cusparseSpMatSetAttribute = unsafe extern "C" fn(
446    sp_mat: cusparseSpMatDescr_t,
447    attribute: cusparseSpMatAttribute_t,
448    data: *const c_void,
449    data_size: usize,
450) -> cusparseStatus_t;
451
452/// cuSPARSE: replace the row/column/value pointers on a CSR descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
453pub type PFN_cusparseCsrSetPointers = unsafe extern "C" fn(
454    sp_mat: cusparseSpMatDescr_t,
455    csr_row_offsets: *mut c_void,
456    csr_col_ind: *mut c_void,
457    csr_values: *mut c_void,
458) -> cusparseStatus_t;
459
460/// cuSPARSE: replace the column/row/value pointers on a CSC descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
461pub type PFN_cusparseCscSetPointers = unsafe extern "C" fn(
462    sp_mat: cusparseSpMatDescr_t,
463    csc_col_offsets: *mut c_void,
464    csc_row_ind: *mut c_void,
465    csc_values: *mut c_void,
466) -> cusparseStatus_t;
467
468/// cuSPARSE: replace the row/column/value pointers on a COO descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
469pub type PFN_cusparseCooSetPointers = unsafe extern "C" fn(
470    sp_mat: cusparseSpMatDescr_t,
471    coo_row_ind: *mut c_void,
472    coo_col_ind: *mut c_void,
473    coo_values: *mut c_void,
474) -> cusparseStatus_t;
475
476// ---- SpMM (sparse × dense = dense) ---------------------------------------
477
478/// cuSPARSE: workspace-size query for sparse matrix × dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
479pub type PFN_cusparseSpMM_bufferSize = unsafe extern "C" fn(
480    handle: cusparseHandle_t,
481    op_a: cusparseOperation_t,
482    op_b: cusparseOperation_t,
483    alpha: *const c_void,
484    mat_a: cusparseSpMatDescr_t,
485    mat_b: cusparseDnMatDescr_t,
486    beta: *const c_void,
487    mat_c: cusparseDnMatDescr_t,
488    compute_type: cudaDataType,
489    alg: cusparseSpMMAlg_t,
490    buffer_size: *mut usize,
491) -> cusparseStatus_t;
492
493/// cuSPARSE: preprocess stage of sparse matrix × dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
494pub type PFN_cusparseSpMM_preprocess = unsafe extern "C" fn(
495    handle: cusparseHandle_t,
496    op_a: cusparseOperation_t,
497    op_b: cusparseOperation_t,
498    alpha: *const c_void,
499    mat_a: cusparseSpMatDescr_t,
500    mat_b: cusparseDnMatDescr_t,
501    beta: *const c_void,
502    mat_c: cusparseDnMatDescr_t,
503    compute_type: cudaDataType,
504    alg: cusparseSpMMAlg_t,
505    external_buffer: *mut c_void,
506) -> cusparseStatus_t;
507
508/// cuSPARSE: sparse matrix × dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
509pub type PFN_cusparseSpMM = unsafe extern "C" fn(
510    handle: cusparseHandle_t,
511    op_a: cusparseOperation_t,
512    op_b: cusparseOperation_t,
513    alpha: *const c_void,
514    mat_a: cusparseSpMatDescr_t,
515    mat_b: cusparseDnMatDescr_t,
516    beta: *const c_void,
517    mat_c: cusparseDnMatDescr_t,
518    compute_type: cudaDataType,
519    alg: cusparseSpMMAlg_t,
520    external_buffer: *mut c_void,
521) -> cusparseStatus_t;
522
523// ---- SpGEMM (sparse × sparse = sparse) -----------------------------------
524
525/// cuSPARSE: create an opaque descriptor for sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
526pub type PFN_cusparseSpGEMM_createDescr =
527    unsafe extern "C" fn(descr: *mut cusparseSpGEMMDescr_t) -> cusparseStatus_t;
528/// cuSPARSE: destroy an opaque descriptor for sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
529pub type PFN_cusparseSpGEMM_destroyDescr =
530    unsafe extern "C" fn(descr: cusparseSpGEMMDescr_t) -> cusparseStatus_t;
531
532/// cuSPARSE: work-estimation stage of sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
533pub type PFN_cusparseSpGEMM_workEstimation = unsafe extern "C" fn(
534    handle: cusparseHandle_t,
535    op_a: cusparseOperation_t,
536    op_b: cusparseOperation_t,
537    alpha: *const c_void,
538    mat_a: cusparseSpMatDescr_t,
539    mat_b: cusparseSpMatDescr_t,
540    beta: *const c_void,
541    mat_c: cusparseSpMatDescr_t,
542    compute_type: cudaDataType,
543    alg: cusparseSpGEMMAlg_t,
544    descr: cusparseSpGEMMDescr_t,
545    buffer_size1: *mut usize,
546    external_buffer1: *mut c_void,
547) -> cusparseStatus_t;
548
549/// cuSPARSE: compute stage of sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
550pub type PFN_cusparseSpGEMM_compute = unsafe extern "C" fn(
551    handle: cusparseHandle_t,
552    op_a: cusparseOperation_t,
553    op_b: cusparseOperation_t,
554    alpha: *const c_void,
555    mat_a: cusparseSpMatDescr_t,
556    mat_b: cusparseSpMatDescr_t,
557    beta: *const c_void,
558    mat_c: cusparseSpMatDescr_t,
559    compute_type: cudaDataType,
560    alg: cusparseSpGEMMAlg_t,
561    descr: cusparseSpGEMMDescr_t,
562    buffer_size2: *mut usize,
563    external_buffer2: *mut c_void,
564) -> cusparseStatus_t;
565
566/// cuSPARSE: copy stage of sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
567pub type PFN_cusparseSpGEMM_copy = unsafe extern "C" fn(
568    handle: cusparseHandle_t,
569    op_a: cusparseOperation_t,
570    op_b: cusparseOperation_t,
571    alpha: *const c_void,
572    mat_a: cusparseSpMatDescr_t,
573    mat_b: cusparseSpMatDescr_t,
574    beta: *const c_void,
575    mat_c: cusparseSpMatDescr_t,
576    compute_type: cudaDataType,
577    alg: cusparseSpGEMMAlg_t,
578    descr: cusparseSpGEMMDescr_t,
579) -> cusparseStatus_t;
580
581// ---- SpSV (sparse triangular solve, vector) ------------------------------
582
583/// cuSPARSE: create an opaque descriptor for sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
584pub type PFN_cusparseSpSV_createDescr =
585    unsafe extern "C" fn(descr: *mut cusparseSpSVDescr_t) -> cusparseStatus_t;
586/// cuSPARSE: destroy an opaque descriptor for sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
587pub type PFN_cusparseSpSV_destroyDescr =
588    unsafe extern "C" fn(descr: cusparseSpSVDescr_t) -> cusparseStatus_t;
589
590/// cuSPARSE: workspace-size query for sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
591pub type PFN_cusparseSpSV_bufferSize = unsafe extern "C" fn(
592    handle: cusparseHandle_t,
593    op_a: cusparseOperation_t,
594    alpha: *const c_void,
595    mat_a: cusparseSpMatDescr_t,
596    vec_x: cusparseDnVecDescr_t,
597    vec_y: cusparseDnVecDescr_t,
598    compute_type: cudaDataType,
599    alg: cusparseSpSVAlg_t,
600    descr: cusparseSpSVDescr_t,
601    buffer_size: *mut usize,
602) -> cusparseStatus_t;
603
604/// cuSPARSE: analysis stage of sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
605pub type PFN_cusparseSpSV_analysis = unsafe extern "C" fn(
606    handle: cusparseHandle_t,
607    op_a: cusparseOperation_t,
608    alpha: *const c_void,
609    mat_a: cusparseSpMatDescr_t,
610    vec_x: cusparseDnVecDescr_t,
611    vec_y: cusparseDnVecDescr_t,
612    compute_type: cudaDataType,
613    alg: cusparseSpSVAlg_t,
614    descr: cusparseSpSVDescr_t,
615    external_buffer: *mut c_void,
616) -> cusparseStatus_t;
617
618/// cuSPARSE: solve stage of sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
619pub type PFN_cusparseSpSV_solve = unsafe extern "C" fn(
620    handle: cusparseHandle_t,
621    op_a: cusparseOperation_t,
622    alpha: *const c_void,
623    mat_a: cusparseSpMatDescr_t,
624    vec_x: cusparseDnVecDescr_t,
625    vec_y: cusparseDnVecDescr_t,
626    compute_type: cudaDataType,
627    alg: cusparseSpSVAlg_t,
628    descr: cusparseSpSVDescr_t,
629) -> cusparseStatus_t;
630
631// ---- SpSM (sparse triangular solve, matrix) ------------------------------
632
633/// cuSPARSE: create an opaque descriptor for sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
634pub type PFN_cusparseSpSM_createDescr =
635    unsafe extern "C" fn(descr: *mut cusparseSpSMDescr_t) -> cusparseStatus_t;
636/// cuSPARSE: destroy an opaque descriptor for sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
637pub type PFN_cusparseSpSM_destroyDescr =
638    unsafe extern "C" fn(descr: cusparseSpSMDescr_t) -> cusparseStatus_t;
639
640/// cuSPARSE: workspace-size query for sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
641pub type PFN_cusparseSpSM_bufferSize = unsafe extern "C" fn(
642    handle: cusparseHandle_t,
643    op_a: cusparseOperation_t,
644    op_b: cusparseOperation_t,
645    alpha: *const c_void,
646    mat_a: cusparseSpMatDescr_t,
647    mat_b: cusparseDnMatDescr_t,
648    mat_c: cusparseDnMatDescr_t,
649    compute_type: cudaDataType,
650    alg: cusparseSpSMAlg_t,
651    descr: cusparseSpSMDescr_t,
652    buffer_size: *mut usize,
653) -> cusparseStatus_t;
654
655/// cuSPARSE: analysis stage of sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
656pub type PFN_cusparseSpSM_analysis = unsafe extern "C" fn(
657    handle: cusparseHandle_t,
658    op_a: cusparseOperation_t,
659    op_b: cusparseOperation_t,
660    alpha: *const c_void,
661    mat_a: cusparseSpMatDescr_t,
662    mat_b: cusparseDnMatDescr_t,
663    mat_c: cusparseDnMatDescr_t,
664    compute_type: cudaDataType,
665    alg: cusparseSpSMAlg_t,
666    descr: cusparseSpSMDescr_t,
667    external_buffer: *mut c_void,
668) -> cusparseStatus_t;
669
670/// cuSPARSE: solve stage of sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
671pub type PFN_cusparseSpSM_solve = unsafe extern "C" fn(
672    handle: cusparseHandle_t,
673    op_a: cusparseOperation_t,
674    op_b: cusparseOperation_t,
675    alpha: *const c_void,
676    mat_a: cusparseSpMatDescr_t,
677    mat_b: cusparseDnMatDescr_t,
678    mat_c: cusparseDnMatDescr_t,
679    compute_type: cudaDataType,
680    alg: cusparseSpSMAlg_t,
681    descr: cusparseSpSMDescr_t,
682) -> cusparseStatus_t;
683
684// ---- SDDMM (sampled dense-dense matmul) ----------------------------------
685
686/// cuSPARSE: workspace-size query for sampled dense-dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
687pub type PFN_cusparseSDDMM_bufferSize = unsafe extern "C" fn(
688    handle: cusparseHandle_t,
689    op_a: cusparseOperation_t,
690    op_b: cusparseOperation_t,
691    alpha: *const c_void,
692    mat_a: cusparseDnMatDescr_t,
693    mat_b: cusparseDnMatDescr_t,
694    beta: *const c_void,
695    mat_c: cusparseSpMatDescr_t,
696    compute_type: cudaDataType,
697    alg: cusparseSDDMMAlg_t,
698    buffer_size: *mut usize,
699) -> cusparseStatus_t;
700
701/// cuSPARSE: preprocess stage of sampled dense-dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
702pub type PFN_cusparseSDDMM_preprocess = unsafe extern "C" fn(
703    handle: cusparseHandle_t,
704    op_a: cusparseOperation_t,
705    op_b: cusparseOperation_t,
706    alpha: *const c_void,
707    mat_a: cusparseDnMatDescr_t,
708    mat_b: cusparseDnMatDescr_t,
709    beta: *const c_void,
710    mat_c: cusparseSpMatDescr_t,
711    compute_type: cudaDataType,
712    alg: cusparseSDDMMAlg_t,
713    external_buffer: *mut c_void,
714) -> cusparseStatus_t;
715
716/// cuSPARSE: sampled dense-dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
717pub type PFN_cusparseSDDMM = unsafe extern "C" fn(
718    handle: cusparseHandle_t,
719    op_a: cusparseOperation_t,
720    op_b: cusparseOperation_t,
721    alpha: *const c_void,
722    mat_a: cusparseDnMatDescr_t,
723    mat_b: cusparseDnMatDescr_t,
724    beta: *const c_void,
725    mat_c: cusparseSpMatDescr_t,
726    compute_type: cudaDataType,
727    alg: cusparseSDDMMAlg_t,
728    external_buffer: *mut c_void,
729) -> cusparseStatus_t;
730
731// ---- CSR ↔ CSC conversion -------------------------------------------------
732
733/// cuSPARSE: workspace-size query for `cusparseCsr2cscEx2`. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
734pub type PFN_cusparseCsr2cscEx2_bufferSize = unsafe extern "C" fn(
735    handle: cusparseHandle_t,
736    m: c_int,
737    n: c_int,
738    nnz: c_int,
739    csr_val: *const c_void,
740    csr_row_ptr: *const c_int,
741    csr_col_ind: *const c_int,
742    csc_val: *mut c_void,
743    csc_col_ptr: *mut c_int,
744    csc_row_ind: *mut c_int,
745    value_type: cudaDataType,
746    copy_values: c_int,
747    idx_base: cusparseIndexBase_t,
748    alg: cusparseCsr2CscAlg_t,
749    buffer_size: *mut usize,
750) -> cusparseStatus_t;
751
752/// cuSPARSE: convert a CSR matrix to CSC (extended API). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
753pub type PFN_cusparseCsr2cscEx2 = unsafe extern "C" fn(
754    handle: cusparseHandle_t,
755    m: c_int,
756    n: c_int,
757    nnz: c_int,
758    csr_val: *const c_void,
759    csr_row_ptr: *const c_int,
760    csr_col_ind: *const c_int,
761    csc_val: *mut c_void,
762    csc_col_ptr: *mut c_int,
763    csc_row_ind: *mut c_int,
764    value_type: cudaDataType,
765    copy_values: c_int,
766    idx_base: cusparseIndexBase_t,
767    alg: cusparseCsr2CscAlg_t,
768    buffer: *mut c_void,
769) -> cusparseStatus_t;
770
771// ---- Sparse↔Dense conversion ---------------------------------------------
772
773/// cuSPARSE: workspace-size query for sparse-to-dense conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
774pub type PFN_cusparseSparseToDense_bufferSize = unsafe extern "C" fn(
775    handle: cusparseHandle_t,
776    mat_a: cusparseSpMatDescr_t,
777    mat_b: cusparseDnMatDescr_t,
778    alg: c_int,
779    buffer_size: *mut usize,
780) -> cusparseStatus_t;
781
782/// cuSPARSE: materialize a sparse matrix into a dense one. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
783pub type PFN_cusparseSparseToDense = unsafe extern "C" fn(
784    handle: cusparseHandle_t,
785    mat_a: cusparseSpMatDescr_t,
786    mat_b: cusparseDnMatDescr_t,
787    alg: c_int,
788    external_buffer: *mut c_void,
789) -> cusparseStatus_t;
790
791/// cuSPARSE: workspace-size query for dense-to-sparse conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
792pub type PFN_cusparseDenseToSparse_bufferSize = unsafe extern "C" fn(
793    handle: cusparseHandle_t,
794    mat_a: cusparseDnMatDescr_t,
795    mat_b: cusparseSpMatDescr_t,
796    alg: c_int,
797    buffer_size: *mut usize,
798) -> cusparseStatus_t;
799
800/// cuSPARSE: analysis stage for dense-to-sparse conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
801pub type PFN_cusparseDenseToSparse_analysis = unsafe extern "C" fn(
802    handle: cusparseHandle_t,
803    mat_a: cusparseDnMatDescr_t,
804    mat_b: cusparseSpMatDescr_t,
805    alg: c_int,
806    external_buffer: *mut c_void,
807) -> cusparseStatus_t;
808
809/// cuSPARSE: execute stage for dense-to-sparse conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
810pub type PFN_cusparseDenseToSparse_convert = unsafe extern "C" fn(
811    handle: cusparseHandle_t,
812    mat_a: cusparseDnMatDescr_t,
813    mat_b: cusparseSpMatDescr_t,
814    alg: c_int,
815    external_buffer: *mut c_void,
816) -> cusparseStatus_t;
817
818// ---- Axpby / Gather / Scatter / Rot (sparse BLAS L1) --------------------
819
820/// cuSPARSE: scaled vector addition (alpha*x + beta*y → y). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
821pub type PFN_cusparseAxpby = unsafe extern "C" fn(
822    handle: cusparseHandle_t,
823    alpha: *const c_void,
824    vec_x: cusparseDnVecDescr_t,
825    beta: *const c_void,
826    vec_y: cusparseDnVecDescr_t,
827) -> cusparseStatus_t;
828
829/// cuSPARSE: gather dense entries into a sparse vector. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
830pub type PFN_cusparseGather = unsafe extern "C" fn(
831    handle: cusparseHandle_t,
832    vec_y: cusparseDnVecDescr_t,
833    vec_x: cusparseDnVecDescr_t,
834) -> cusparseStatus_t;
835
836/// cuSPARSE: scatter sparse vector entries into a dense vector. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
837pub type PFN_cusparseScatter = unsafe extern "C" fn(
838    handle: cusparseHandle_t,
839    vec_x: cusparseDnVecDescr_t,
840    vec_y: cusparseDnVecDescr_t,
841) -> cusparseStatus_t;
842
843/// cuSPARSE: Givens-rotation on sparse and dense vector pair. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
844pub type PFN_cusparseRot = unsafe extern "C" fn(
845    handle: cusparseHandle_t,
846    c: *const c_void,
847    s: *const c_void,
848    vec_x: cusparseDnVecDescr_t,
849    vec_y: cusparseDnVecDescr_t,
850) -> cusparseStatus_t;
851
852// ---- loader --------------------------------------------------------------
853
854fn cusparse_candidates() -> Vec<String> {
855    platform::versioned_library_candidates("cusparse", &["13", "12", "11"])
856}
857
858macro_rules! cusparse_fns {
859    ($($(#[$m:meta])* $name:ident as $sym:literal : $pfn:ty);* $(;)?) => {
860        /// Loaded cuSPARSE shared library plus a per-symbol `OnceLock` of function pointers.
861        pub struct Cusparse {
862            lib: Library,
863            $($name: OnceLock<$pfn>,)*
864        }
865        impl core::fmt::Debug for Cusparse {
866            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
867                f.debug_struct("Cusparse").field("lib", &self.lib).finish_non_exhaustive()
868            }
869        }
870        impl Cusparse {
871            $(
872                $(#[$m])*
873                pub fn $name(&self) -> Result<$pfn, LoaderError> {
874                    if let Some(&p) = self.$name.get() { return Ok(p); }
875                    let raw: *mut () = unsafe { self.lib.raw_symbol($sym)? };
876                    let p: $pfn = unsafe { core::mem::transmute_copy::<*mut (), $pfn>(&raw) };
877                    let _ = self.$name.set(p);
878                    Ok(p)
879                }
880            )*
881            fn empty(lib: Library) -> Self {
882                Self { lib, $($name: OnceLock::new(),)* }
883            }
884        }
885    };
886}
887
888cusparse_fns! {
889    /// cuSPARSE: create a cuSPARSE handle. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
890    cusparse_create as "cusparseCreate": PFN_cusparseCreate;
891    /// cuSPARSE: destroy a cuSPARSE handle. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
892    cusparse_destroy as "cusparseDestroy": PFN_cusparseDestroy;
893    /// cuSPARSE: bind a CUDA stream to a cuSPARSE handle. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
894    cusparse_set_stream as "cusparseSetStream": PFN_cusparseSetStream;
895    /// cuSPARSE: return the cuSPARSE library version. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
896    cusparse_get_version as "cusparseGetVersion": PFN_cusparseGetVersion;
897    // Sparse-matrix descriptors
898    /// cuSPARSE: create a CSR sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
899    cusparse_create_csr as "cusparseCreateCsr": PFN_cusparseCreateCsr;
900    /// cuSPARSE: create a CSC sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
901    cusparse_create_csc as "cusparseCreateCsc": PFN_cusparseCreateCsc;
902    /// cuSPARSE: create a COO sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
903    cusparse_create_coo as "cusparseCreateCoo": PFN_cusparseCreateCoo;
904    /// cuSPARSE: create a BSR sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
905    cusparse_create_bsr as "cusparseCreateBsr": PFN_cusparseCreateBsr;
906    /// cuSPARSE: destroy a sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
907    cusparse_destroy_sp_mat as "cusparseDestroySpMat": PFN_cusparseDestroySpMat;
908    /// cuSPARSE: query rows, cols, and nnz of a sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
909    cusparse_sp_mat_get_size as "cusparseSpMatGetSize": PFN_cusparseSpMatGetSize;
910    /// cuSPARSE: set an attribute (fill mode, diag type) on a sparse-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
911    cusparse_sp_mat_set_attribute as "cusparseSpMatSetAttribute": PFN_cusparseSpMatSetAttribute;
912    /// cuSPARSE: replace the row/column/value pointers on a CSR descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
913    cusparse_csr_set_pointers as "cusparseCsrSetPointers": PFN_cusparseCsrSetPointers;
914    /// cuSPARSE: replace the column/row/value pointers on a CSC descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
915    cusparse_csc_set_pointers as "cusparseCscSetPointers": PFN_cusparseCscSetPointers;
916    /// cuSPARSE: replace the row/column/value pointers on a COO descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
917    cusparse_coo_set_pointers as "cusparseCooSetPointers": PFN_cusparseCooSetPointers;
918    // Dense descriptors
919    /// cuSPARSE: create a dense-vector descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
920    cusparse_create_dn_vec as "cusparseCreateDnVec": PFN_cusparseCreateDnVec;
921    /// cuSPARSE: destroy a dense-vector descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
922    cusparse_destroy_dn_vec as "cusparseDestroyDnVec": PFN_cusparseDestroyDnVec;
923    /// cuSPARSE: create a dense-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
924    cusparse_create_dn_mat as "cusparseCreateDnMat": PFN_cusparseCreateDnMat;
925    /// cuSPARSE: destroy a dense-matrix descriptor. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
926    cusparse_destroy_dn_mat as "cusparseDestroyDnMat": PFN_cusparseDestroyDnMat;
927    // SpMV
928    /// cuSPARSE: workspace-size query for sparse matrix-vector multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
929    cusparse_spmv_buffer_size as "cusparseSpMV_bufferSize": PFN_cusparseSpMV_bufferSize;
930    /// cuSPARSE: sparse matrix-vector multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
931    cusparse_spmv as "cusparseSpMV": PFN_cusparseSpMV;
932    // SpMM
933    /// cuSPARSE: workspace-size query for sparse matrix × dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
934    cusparse_spmm_buffer_size as "cusparseSpMM_bufferSize": PFN_cusparseSpMM_bufferSize;
935    /// cuSPARSE: preprocess stage of sparse matrix × dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
936    cusparse_spmm_preprocess as "cusparseSpMM_preprocess": PFN_cusparseSpMM_preprocess;
937    /// cuSPARSE: sparse matrix × dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
938    cusparse_spmm as "cusparseSpMM": PFN_cusparseSpMM;
939    // SpGEMM
940    /// cuSPARSE: create an opaque descriptor for sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
941    cusparse_spgemm_create_descr as "cusparseSpGEMM_createDescr": PFN_cusparseSpGEMM_createDescr;
942    /// cuSPARSE: destroy an opaque descriptor for sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
943    cusparse_spgemm_destroy_descr as "cusparseSpGEMM_destroyDescr": PFN_cusparseSpGEMM_destroyDescr;
944    /// cuSPARSE: work-estimation stage of sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
945    cusparse_spgemm_work_estimation as "cusparseSpGEMM_workEstimation": PFN_cusparseSpGEMM_workEstimation;
946    /// cuSPARSE: compute stage of sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
947    cusparse_spgemm_compute as "cusparseSpGEMM_compute": PFN_cusparseSpGEMM_compute;
948    /// cuSPARSE: copy stage of sparse matrix × sparse matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
949    cusparse_spgemm_copy as "cusparseSpGEMM_copy": PFN_cusparseSpGEMM_copy;
950    // SpSV
951    /// cuSPARSE: create an opaque descriptor for sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
952    cusparse_spsv_create_descr as "cusparseSpSV_createDescr": PFN_cusparseSpSV_createDescr;
953    /// cuSPARSE: destroy an opaque descriptor for sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
954    cusparse_spsv_destroy_descr as "cusparseSpSV_destroyDescr": PFN_cusparseSpSV_destroyDescr;
955    /// cuSPARSE: workspace-size query for sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
956    cusparse_spsv_buffer_size as "cusparseSpSV_bufferSize": PFN_cusparseSpSV_bufferSize;
957    /// cuSPARSE: analysis stage of sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
958    cusparse_spsv_analysis as "cusparseSpSV_analysis": PFN_cusparseSpSV_analysis;
959    /// cuSPARSE: solve stage of sparse triangular linear solve (single right-hand side). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
960    cusparse_spsv_solve as "cusparseSpSV_solve": PFN_cusparseSpSV_solve;
961    // SpSM
962    /// cuSPARSE: create an opaque descriptor for sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
963    cusparse_spsm_create_descr as "cusparseSpSM_createDescr": PFN_cusparseSpSM_createDescr;
964    /// cuSPARSE: destroy an opaque descriptor for sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
965    cusparse_spsm_destroy_descr as "cusparseSpSM_destroyDescr": PFN_cusparseSpSM_destroyDescr;
966    /// cuSPARSE: workspace-size query for sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
967    cusparse_spsm_buffer_size as "cusparseSpSM_bufferSize": PFN_cusparseSpSM_bufferSize;
968    /// cuSPARSE: analysis stage of sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
969    cusparse_spsm_analysis as "cusparseSpSM_analysis": PFN_cusparseSpSM_analysis;
970    /// cuSPARSE: solve stage of sparse triangular linear solve (multiple right-hand sides). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
971    cusparse_spsm_solve as "cusparseSpSM_solve": PFN_cusparseSpSM_solve;
972    // SDDMM
973    /// cuSPARSE: workspace-size query for sampled dense-dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
974    cusparse_sddmm_buffer_size as "cusparseSDDMM_bufferSize": PFN_cusparseSDDMM_bufferSize;
975    /// cuSPARSE: preprocess stage of sampled dense-dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
976    cusparse_sddmm_preprocess as "cusparseSDDMM_preprocess": PFN_cusparseSDDMM_preprocess;
977    /// cuSPARSE: sampled dense-dense matrix multiplication. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
978    cusparse_sddmm as "cusparseSDDMM": PFN_cusparseSDDMM;
979    // CSR ↔ CSC
980    /// cuSPARSE: workspace-size query for `cusparseCsr2cscEx2`. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
981    cusparse_csr2csc_ex2_buffer_size as "cusparseCsr2cscEx2_bufferSize": PFN_cusparseCsr2cscEx2_bufferSize;
982    /// cuSPARSE: convert a CSR matrix to CSC (extended API). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
983    cusparse_csr2csc_ex2 as "cusparseCsr2cscEx2": PFN_cusparseCsr2cscEx2;
984    // Sparse ↔ Dense
985    /// cuSPARSE: workspace-size query for sparse-to-dense conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
986    cusparse_sparse_to_dense_buffer_size as "cusparseSparseToDense_bufferSize": PFN_cusparseSparseToDense_bufferSize;
987    /// cuSPARSE: materialize a sparse matrix into a dense one. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
988    cusparse_sparse_to_dense as "cusparseSparseToDense": PFN_cusparseSparseToDense;
989    /// cuSPARSE: workspace-size query for dense-to-sparse conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
990    cusparse_dense_to_sparse_buffer_size as "cusparseDenseToSparse_bufferSize": PFN_cusparseDenseToSparse_bufferSize;
991    /// cuSPARSE: analysis stage for dense-to-sparse conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
992    cusparse_dense_to_sparse_analysis as "cusparseDenseToSparse_analysis": PFN_cusparseDenseToSparse_analysis;
993    /// cuSPARSE: execute stage for dense-to-sparse conversion. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
994    cusparse_dense_to_sparse_convert as "cusparseDenseToSparse_convert": PFN_cusparseDenseToSparse_convert;
995    // Sparse BLAS L1
996    /// cuSPARSE: scaled vector addition (alpha*x + beta*y → y). See <https://docs.nvidia.com/cuda/cusparse/index.html>.
997    cusparse_axpby as "cusparseAxpby": PFN_cusparseAxpby;
998    /// cuSPARSE: gather dense entries into a sparse vector. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
999    cusparse_gather as "cusparseGather": PFN_cusparseGather;
1000    /// cuSPARSE: scatter sparse vector entries into a dense vector. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
1001    cusparse_scatter as "cusparseScatter": PFN_cusparseScatter;
1002    /// cuSPARSE: Givens-rotation on sparse and dense vector pair. See <https://docs.nvidia.com/cuda/cusparse/index.html>.
1003    cusparse_rot as "cusparseRot": PFN_cusparseRot;
1004}
1005
1006/// Lazy-load the cuSPARSE shared library and return its function-pointer table.
1007pub fn cusparse() -> Result<&'static Cusparse, LoaderError> {
1008    static CUSPARSE: OnceLock<Cusparse> = OnceLock::new();
1009    if let Some(c) = CUSPARSE.get() {
1010        return Ok(c);
1011    }
1012    let candidates: Vec<&'static str> = cusparse_candidates()
1013        .into_iter()
1014        .map(|s| Box::leak(s.into_boxed_str()) as &'static str)
1015        .collect();
1016    let candidates_leaked: &'static [&'static str] = Box::leak(candidates.into_boxed_slice());
1017    let lib = Library::open("cusparse", candidates_leaked)?;
1018    let c = Cusparse::empty(lib);
1019    let _ = CUSPARSE.set(c);
1020    Ok(CUSPARSE.get().expect("OnceLock set or lost race"))
1021}