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