1#![warn(missing_debug_implementations)]
100
101use core::ffi::c_void;
102use std::marker::PhantomData;
103
104use baracuda_cusparse_sys::{
105 cudaDataType, cusparse, cusparseDiagType_t, cusparseDnMatDescr_t, cusparseDnVecDescr_t,
106 cusparseFillMode_t, cusparseHandle_t, cusparseIndexBase_t, cusparseIndexType_t,
107 cusparseOperation_t, cusparseOrder_t, cusparseSpGEMMDescr_t, cusparseSpMatAttribute_t,
108 cusparseSpMatDescr_t, cusparseSpSMDescr_t, cusparseSpSVDescr_t, cusparseStatus_t,
109};
110use baracuda_driver::{DeviceBuffer, Stream};
111use baracuda_types::{Complex32, Complex64};
112
113pub use baracuda_cusparse_sys::{
114 cusparseCsr2CscAlg_t as Csr2CscAlg, cusparseIndexBase_t as IndexBase,
115 cusparseSDDMMAlg_t as SDDMMAlg, cusparseSpGEMMAlg_t as SpGEMMAlg,
116 cusparseSpMMAlg_t as SpMMAlg, cusparseSpMVAlg_t as SpMVAlg, cusparseSpSMAlg_t as SpSMAlg,
117 cusparseSpSVAlg_t as SpSVAlg,
118};
119
120pub type Error = baracuda_core::Error<cusparseStatus_t>;
122pub type Result<T, E = Error> = core::result::Result<T, E>;
124
125#[inline]
126fn check(status: cusparseStatus_t) -> Result<()> {
127 Error::check(status)
128}
129
130pub trait SparseScalar: sealed::Sealed + Copy + 'static {
134 fn data_type() -> cudaDataType;
136}
137
138impl SparseScalar for f32 {
139 fn data_type() -> cudaDataType {
140 cudaDataType::R_32F
141 }
142}
143impl SparseScalar for f64 {
144 fn data_type() -> cudaDataType {
145 cudaDataType::R_64F
146 }
147}
148impl SparseScalar for Complex32 {
149 fn data_type() -> cudaDataType {
150 cudaDataType::C_32F
151 }
152}
153impl SparseScalar for Complex64 {
154 fn data_type() -> cudaDataType {
155 cudaDataType::C_64F
156 }
157}
158
159mod sealed {
160 use baracuda_types::{Complex32, Complex64};
161 pub trait Sealed {}
162 impl Sealed for f32 {}
163 impl Sealed for f64 {}
164 impl Sealed for Complex32 {}
165 impl Sealed for Complex64 {}
166}
167
168#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
172pub enum Op {
173 #[default]
175 N,
176 T,
178 C,
180}
181
182impl Op {
183 fn raw(self) -> cusparseOperation_t {
184 match self {
185 Op::N => cusparseOperation_t::N,
186 Op::T => cusparseOperation_t::T,
187 Op::C => cusparseOperation_t::C,
188 }
189 }
190}
191
192#[derive(Copy, Clone, Debug, Eq, PartialEq)]
194pub enum Order {
195 Row,
197 Col,
199}
200
201impl Order {
202 fn raw(self) -> cusparseOrder_t {
203 match self {
204 Order::Row => cusparseOrder_t::Row,
205 Order::Col => cusparseOrder_t::Col,
206 }
207 }
208}
209
210#[derive(Copy, Clone, Debug, Eq, PartialEq)]
212pub enum Fill {
213 Lower,
215 Upper,
217}
218
219impl Fill {
220 fn raw(self) -> cusparseFillMode_t {
221 match self {
222 Fill::Lower => cusparseFillMode_t::Lower,
223 Fill::Upper => cusparseFillMode_t::Upper,
224 }
225 }
226}
227
228#[derive(Copy, Clone, Debug, Eq, PartialEq)]
230pub enum Diag {
231 NonUnit,
233 Unit,
235}
236
237impl Diag {
238 fn raw(self) -> cusparseDiagType_t {
239 match self {
240 Diag::NonUnit => cusparseDiagType_t::NonUnit,
241 Diag::Unit => cusparseDiagType_t::Unit,
242 }
243 }
244}
245
246pub struct Handle {
250 handle: cusparseHandle_t,
251}
252
253unsafe impl Send for Handle {}
254
255impl core::fmt::Debug for Handle {
256 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
257 f.debug_struct("cusparse::Handle")
258 .field("handle", &self.handle)
259 .finish()
260 }
261}
262
263impl Handle {
264 pub fn new() -> Result<Self> {
266 let c = cusparse()?;
267 let cu = c.cusparse_create()?;
268 let mut h: cusparseHandle_t = core::ptr::null_mut();
269 check(unsafe { cu(&mut h) })?;
270 Ok(Self { handle: h })
271 }
272
273 pub fn set_stream(&self, stream: &Stream) -> Result<()> {
276 let c = cusparse()?;
277 let cu = c.cusparse_set_stream()?;
278 check(unsafe { cu(self.handle, stream.as_raw() as _) })
279 }
280
281 pub fn version(&self) -> Result<i32> {
284 let c = cusparse()?;
285 let cu = c.cusparse_get_version()?;
286 let mut v: core::ffi::c_int = 0;
287 check(unsafe { cu(self.handle, &mut v) })?;
288 Ok(v)
289 }
290
291 #[inline]
293 pub fn as_raw(&self) -> cusparseHandle_t {
294 self.handle
295 }
296}
297
298impl Drop for Handle {
299 fn drop(&mut self) {
300 if let Ok(c) = cusparse() {
301 if let Ok(cu) = c.cusparse_destroy() {
302 let _ = unsafe { cu(self.handle) };
303 }
304 }
305 }
306}
307
308pub struct SpMat<'buf, T> {
314 descr: cusparseSpMatDescr_t,
315 _markers: PhantomData<&'buf mut T>,
316}
317
318unsafe impl<T> Send for SpMat<'_, T> {}
319
320impl<T> core::fmt::Debug for SpMat<'_, T> {
321 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
322 f.debug_struct("SpMat")
323 .field("descr", &self.descr)
324 .finish_non_exhaustive()
325 }
326}
327
328impl<'buf, T: SparseScalar + baracuda_types::DeviceRepr> SpMat<'buf, T> {
329 pub fn csr(
334 rows: i64,
335 cols: i64,
336 nnz: i64,
337 row_offsets: &'buf mut DeviceBuffer<i32>,
338 col_indices: &'buf mut DeviceBuffer<i32>,
339 values: &'buf mut DeviceBuffer<T>,
340 ) -> Result<Self> {
341 let c = cusparse()?;
342 let cu = c.cusparse_create_csr()?;
343 let mut descr: cusparseSpMatDescr_t = core::ptr::null_mut();
344 check(unsafe {
345 cu(
346 &mut descr,
347 rows,
348 cols,
349 nnz,
350 row_offsets.as_raw().0 as *mut c_void,
351 col_indices.as_raw().0 as *mut c_void,
352 values.as_raw().0 as *mut c_void,
353 cusparseIndexType_t::I32I,
354 cusparseIndexType_t::I32I,
355 cusparseIndexBase_t::Zero,
356 T::data_type(),
357 )
358 })?;
359 Ok(Self {
360 descr,
361 _markers: PhantomData,
362 })
363 }
364
365 pub fn csc(
367 rows: i64,
368 cols: i64,
369 nnz: i64,
370 col_offsets: &'buf mut DeviceBuffer<i32>,
371 row_indices: &'buf mut DeviceBuffer<i32>,
372 values: &'buf mut DeviceBuffer<T>,
373 ) -> Result<Self> {
374 let c = cusparse()?;
375 let cu = c.cusparse_create_csc()?;
376 let mut descr: cusparseSpMatDescr_t = core::ptr::null_mut();
377 check(unsafe {
378 cu(
379 &mut descr,
380 rows,
381 cols,
382 nnz,
383 col_offsets.as_raw().0 as *mut c_void,
384 row_indices.as_raw().0 as *mut c_void,
385 values.as_raw().0 as *mut c_void,
386 cusparseIndexType_t::I32I,
387 cusparseIndexType_t::I32I,
388 cusparseIndexBase_t::Zero,
389 T::data_type(),
390 )
391 })?;
392 Ok(Self {
393 descr,
394 _markers: PhantomData,
395 })
396 }
397
398 #[allow(clippy::too_many_arguments)]
400 pub fn bsr(
401 brows: i64,
402 bcols: i64,
403 bnnz: i64,
404 row_block_dim: i64,
405 col_block_dim: i64,
406 order: Order,
407 row_offsets: &'buf mut DeviceBuffer<i32>,
408 col_indices: &'buf mut DeviceBuffer<i32>,
409 values: &'buf mut DeviceBuffer<T>,
410 ) -> Result<Self> {
411 let c = cusparse()?;
412 let cu = c.cusparse_create_bsr()?;
413 let mut descr: cusparseSpMatDescr_t = core::ptr::null_mut();
414 check(unsafe {
415 cu(
416 &mut descr,
417 brows,
418 bcols,
419 bnnz,
420 row_block_dim,
421 col_block_dim,
422 row_offsets.as_raw().0 as *mut c_void,
423 col_indices.as_raw().0 as *mut c_void,
424 values.as_raw().0 as *mut c_void,
425 cusparseIndexType_t::I32I,
426 cusparseIndexType_t::I32I,
427 cusparseIndexBase_t::Zero,
428 T::data_type(),
429 order.raw(),
430 )
431 })?;
432 Ok(Self {
433 descr,
434 _markers: PhantomData,
435 })
436 }
437
438 pub fn coo(
440 rows: i64,
441 cols: i64,
442 nnz: i64,
443 row_indices: &'buf mut DeviceBuffer<i32>,
444 col_indices: &'buf mut DeviceBuffer<i32>,
445 values: &'buf mut DeviceBuffer<T>,
446 ) -> Result<Self> {
447 let c = cusparse()?;
448 let cu = c.cusparse_create_coo()?;
449 let mut descr: cusparseSpMatDescr_t = core::ptr::null_mut();
450 check(unsafe {
451 cu(
452 &mut descr,
453 rows,
454 cols,
455 nnz,
456 row_indices.as_raw().0 as *mut c_void,
457 col_indices.as_raw().0 as *mut c_void,
458 values.as_raw().0 as *mut c_void,
459 cusparseIndexType_t::I32I,
460 cusparseIndexBase_t::Zero,
461 T::data_type(),
462 )
463 })?;
464 Ok(Self {
465 descr,
466 _markers: PhantomData,
467 })
468 }
469}
470
471impl<T> SpMat<'_, T> {
472 pub fn shape(&self) -> Result<(i64, i64, i64)> {
474 let c = cusparse()?;
475 let cu = c.cusparse_sp_mat_get_size()?;
476 let (mut r, mut col, mut nz) = (0i64, 0i64, 0i64);
477 check(unsafe { cu(self.descr, &mut r, &mut col, &mut nz) })?;
478 Ok((r, col, nz))
479 }
480
481 pub unsafe fn set_csr_pointers(
492 &self,
493 row_offsets: *mut c_void,
494 col_indices: *mut c_void,
495 values: *mut c_void,
496 ) -> Result<()> { unsafe {
497 let c = cusparse()?;
498 let cu = c.cusparse_csr_set_pointers()?;
499 check(cu(self.descr, row_offsets, col_indices, values))
500 }}
501
502 pub unsafe fn set_csc_pointers(
508 &self,
509 col_offsets: *mut c_void,
510 row_indices: *mut c_void,
511 values: *mut c_void,
512 ) -> Result<()> { unsafe {
513 let c = cusparse()?;
514 let cu = c.cusparse_csc_set_pointers()?;
515 check(cu(self.descr, col_offsets, row_indices, values))
516 }}
517
518 pub unsafe fn set_coo_pointers(
524 &self,
525 row_indices: *mut c_void,
526 col_indices: *mut c_void,
527 values: *mut c_void,
528 ) -> Result<()> { unsafe {
529 let c = cusparse()?;
530 let cu = c.cusparse_coo_set_pointers()?;
531 check(cu(self.descr, row_indices, col_indices, values))
532 }}
533
534 pub fn set_fill(&self, fill: Fill) -> Result<()> {
536 let c = cusparse()?;
537 let cu = c.cusparse_sp_mat_set_attribute()?;
538 let raw = fill.raw();
539 check(unsafe {
540 cu(
541 self.descr,
542 cusparseSpMatAttribute_t::FillMode,
543 &raw as *const _ as *const c_void,
544 core::mem::size_of::<cusparseFillMode_t>(),
545 )
546 })
547 }
548
549 pub fn set_diag(&self, diag: Diag) -> Result<()> {
551 let c = cusparse()?;
552 let cu = c.cusparse_sp_mat_set_attribute()?;
553 let raw = diag.raw();
554 check(unsafe {
555 cu(
556 self.descr,
557 cusparseSpMatAttribute_t::DiagType,
558 &raw as *const _ as *const c_void,
559 core::mem::size_of::<cusparseDiagType_t>(),
560 )
561 })
562 }
563
564 #[inline]
566 pub fn as_raw(&self) -> cusparseSpMatDescr_t {
567 self.descr
568 }
569}
570
571impl<T> Drop for SpMat<'_, T> {
572 fn drop(&mut self) {
573 if let Ok(c) = cusparse() {
574 if let Ok(cu) = c.cusparse_destroy_sp_mat() {
575 let _ = unsafe { cu(self.descr) };
576 }
577 }
578 }
579}
580
581pub struct DnVec<'buf, T> {
588 descr: cusparseDnVecDescr_t,
589 _marker: PhantomData<&'buf mut T>,
590}
591
592unsafe impl<T> Send for DnVec<'_, T> {}
593
594impl<T> core::fmt::Debug for DnVec<'_, T> {
595 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
596 f.debug_struct("DnVec")
597 .field("descr", &self.descr)
598 .finish_non_exhaustive()
599 }
600}
601
602impl<'buf, T: SparseScalar + baracuda_types::DeviceRepr> DnVec<'buf, T> {
603 pub fn new(values: &'buf mut DeviceBuffer<T>) -> Result<Self> {
606 let c = cusparse()?;
607 let cu = c.cusparse_create_dn_vec()?;
608 let mut descr: cusparseDnVecDescr_t = core::ptr::null_mut();
609 check(unsafe {
610 cu(
611 &mut descr,
612 values.len() as i64,
613 values.as_raw().0 as *mut c_void,
614 T::data_type(),
615 )
616 })?;
617 Ok(Self {
618 descr,
619 _marker: PhantomData,
620 })
621 }
622}
623
624impl<T> DnVec<'_, T> {
625 #[inline]
627 pub fn as_raw(&self) -> cusparseDnVecDescr_t {
628 self.descr
629 }
630}
631
632impl<T> Drop for DnVec<'_, T> {
633 fn drop(&mut self) {
634 if let Ok(c) = cusparse() {
635 if let Ok(cu) = c.cusparse_destroy_dn_vec() {
636 let _ = unsafe { cu(self.descr) };
637 }
638 }
639 }
640}
641
642pub struct DnMat<'buf, T> {
647 descr: cusparseDnMatDescr_t,
648 _marker: PhantomData<&'buf mut T>,
649}
650
651unsafe impl<T> Send for DnMat<'_, T> {}
652
653impl<T> core::fmt::Debug for DnMat<'_, T> {
654 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
655 f.debug_struct("DnMat")
656 .field("descr", &self.descr)
657 .finish_non_exhaustive()
658 }
659}
660
661impl<'buf, T: SparseScalar + baracuda_types::DeviceRepr> DnMat<'buf, T> {
662 pub fn new(
665 rows: i64,
666 cols: i64,
667 ld: i64,
668 order: Order,
669 values: &'buf mut DeviceBuffer<T>,
670 ) -> Result<Self> {
671 let c = cusparse()?;
672 let cu = c.cusparse_create_dn_mat()?;
673 let mut descr: cusparseDnMatDescr_t = core::ptr::null_mut();
674 check(unsafe {
675 cu(
676 &mut descr,
677 rows,
678 cols,
679 ld,
680 values.as_raw().0 as *mut c_void,
681 T::data_type(),
682 order.raw(),
683 )
684 })?;
685 Ok(Self {
686 descr,
687 _marker: PhantomData,
688 })
689 }
690}
691
692impl<T> DnMat<'_, T> {
693 #[inline]
695 pub fn as_raw(&self) -> cusparseDnMatDescr_t {
696 self.descr
697 }
698}
699
700impl<T> Drop for DnMat<'_, T> {
701 fn drop(&mut self) {
702 if let Ok(c) = cusparse() {
703 if let Ok(cu) = c.cusparse_destroy_dn_mat() {
704 let _ = unsafe { cu(self.descr) };
705 }
706 }
707 }
708}
709
710#[allow(clippy::too_many_arguments)]
714pub fn spmv_buffer_size<T: SparseScalar>(
715 handle: &Handle,
716 op: Op,
717 alpha: &T,
718 a: &SpMat<'_, T>,
719 x: &DnVec<'_, T>,
720 beta: &T,
721 y: &DnVec<'_, T>,
722 alg: SpMVAlg,
723) -> Result<usize> {
724 let c = cusparse()?;
725 let cu = c.cusparse_spmv_buffer_size()?;
726 let mut size: usize = 0;
727 check(unsafe {
728 cu(
729 handle.as_raw(),
730 op.raw(),
731 alpha as *const T as *const c_void,
732 a.descr,
733 x.descr,
734 beta as *const T as *const c_void,
735 y.descr,
736 T::data_type(),
737 alg,
738 &mut size,
739 )
740 })?;
741 Ok(size)
742}
743
744#[allow(clippy::too_many_arguments)]
746pub fn spmv<T: SparseScalar>(
747 handle: &Handle,
748 op: Op,
749 alpha: &T,
750 a: &SpMat<'_, T>,
751 x: &DnVec<'_, T>,
752 beta: &T,
753 y: &mut DnVec<'_, T>,
754 alg: SpMVAlg,
755 workspace: &mut DeviceBuffer<u8>,
756) -> Result<()> {
757 let c = cusparse()?;
758 let cu = c.cusparse_spmv()?;
759 check(unsafe {
760 cu(
761 handle.as_raw(),
762 op.raw(),
763 alpha as *const T as *const c_void,
764 a.descr,
765 x.descr,
766 beta as *const T as *const c_void,
767 y.descr,
768 T::data_type(),
769 alg,
770 workspace.as_raw().0 as *mut c_void,
771 )
772 })
773}
774
775#[allow(clippy::too_many_arguments)]
779pub fn spmm_buffer_size<T: SparseScalar>(
780 handle: &Handle,
781 op_a: Op,
782 op_b: Op,
783 alpha: &T,
784 a: &SpMat<'_, T>,
785 b: &DnMat<'_, T>,
786 beta: &T,
787 c: &DnMat<'_, T>,
788 alg: SpMMAlg,
789) -> Result<usize> {
790 let c_api = cusparse()?;
791 let cu = c_api.cusparse_spmm_buffer_size()?;
792 let mut size = 0usize;
793 check(unsafe {
794 cu(
795 handle.as_raw(),
796 op_a.raw(),
797 op_b.raw(),
798 alpha as *const T as *const c_void,
799 a.descr,
800 b.descr,
801 beta as *const T as *const c_void,
802 c.descr,
803 T::data_type(),
804 alg,
805 &mut size,
806 )
807 })?;
808 Ok(size)
809}
810
811#[allow(clippy::too_many_arguments)]
814pub fn spmm<T: SparseScalar>(
815 handle: &Handle,
816 op_a: Op,
817 op_b: Op,
818 alpha: &T,
819 a: &SpMat<'_, T>,
820 b: &DnMat<'_, T>,
821 beta: &T,
822 c: &mut DnMat<'_, T>,
823 alg: SpMMAlg,
824 workspace: &mut DeviceBuffer<u8>,
825) -> Result<()> {
826 let c_api = cusparse()?;
827 let cu = c_api.cusparse_spmm()?;
828 check(unsafe {
829 cu(
830 handle.as_raw(),
831 op_a.raw(),
832 op_b.raw(),
833 alpha as *const T as *const c_void,
834 a.descr,
835 b.descr,
836 beta as *const T as *const c_void,
837 c.descr,
838 T::data_type(),
839 alg,
840 workspace.as_raw().0 as *mut c_void,
841 )
842 })
843}
844
845#[allow(clippy::too_many_arguments)]
850pub fn spmm_preprocess<T: SparseScalar>(
851 handle: &Handle,
852 op_a: Op,
853 op_b: Op,
854 alpha: &T,
855 a: &SpMat<'_, T>,
856 b: &DnMat<'_, T>,
857 beta: &T,
858 c: &mut DnMat<'_, T>,
859 alg: SpMMAlg,
860 workspace: &mut DeviceBuffer<u8>,
861) -> Result<()> {
862 let c_api = cusparse()?;
863 let cu = c_api.cusparse_spmm_preprocess()?;
864 check(unsafe {
865 cu(
866 handle.as_raw(),
867 op_a.raw(),
868 op_b.raw(),
869 alpha as *const T as *const c_void,
870 a.descr,
871 b.descr,
872 beta as *const T as *const c_void,
873 c.descr,
874 T::data_type(),
875 alg,
876 workspace.as_raw().0 as *mut c_void,
877 )
878 })
879}
880
881#[derive(Debug)]
885pub struct SpGEMMPlan {
886 raw: cusparseSpGEMMDescr_t,
887}
888
889impl SpGEMMPlan {
890 pub fn new() -> Result<Self> {
893 let c = cusparse()?;
894 let cu = c.cusparse_spgemm_create_descr()?;
895 let mut d: cusparseSpGEMMDescr_t = core::ptr::null_mut();
896 check(unsafe { cu(&mut d) })?;
897 Ok(Self { raw: d })
898 }
899}
900
901impl Drop for SpGEMMPlan {
902 fn drop(&mut self) {
903 if let Ok(c) = cusparse() {
904 if let Ok(cu) = c.cusparse_spgemm_destroy_descr() {
905 let _ = unsafe { cu(self.raw) };
906 }
907 }
908 }
909}
910
911#[allow(clippy::too_many_arguments)]
920pub unsafe fn spgemm_work_estimation<T: SparseScalar>(
921 handle: &Handle,
922 op_a: Op,
923 op_b: Op,
924 alpha: &T,
925 a: &SpMat<'_, T>,
926 b: &SpMat<'_, T>,
927 beta: &T,
928 c: &mut SpMat<'_, T>,
929 alg: SpGEMMAlg,
930 plan: &SpGEMMPlan,
931 size1: &mut usize,
932 buffer1: *mut c_void,
933) -> Result<()> { unsafe {
934 let c_api = cusparse()?;
935 let cu = c_api.cusparse_spgemm_work_estimation()?;
936 check(cu(
937 handle.as_raw(),
938 op_a.raw(),
939 op_b.raw(),
940 alpha as *const T as *const c_void,
941 a.descr,
942 b.descr,
943 beta as *const T as *const c_void,
944 c.descr,
945 T::data_type(),
946 alg,
947 plan.raw,
948 size1,
949 buffer1,
950 ))
951}}
952
953#[allow(clippy::too_many_arguments)]
961pub unsafe fn spgemm_compute<T: SparseScalar>(
962 handle: &Handle,
963 op_a: Op,
964 op_b: Op,
965 alpha: &T,
966 a: &SpMat<'_, T>,
967 b: &SpMat<'_, T>,
968 beta: &T,
969 c: &mut SpMat<'_, T>,
970 alg: SpGEMMAlg,
971 plan: &SpGEMMPlan,
972 size2: &mut usize,
973 buffer2: *mut c_void,
974) -> Result<()> { unsafe {
975 let c_api = cusparse()?;
976 let cu = c_api.cusparse_spgemm_compute()?;
977 check(cu(
978 handle.as_raw(),
979 op_a.raw(),
980 op_b.raw(),
981 alpha as *const T as *const c_void,
982 a.descr,
983 b.descr,
984 beta as *const T as *const c_void,
985 c.descr,
986 T::data_type(),
987 alg,
988 plan.raw,
989 size2,
990 buffer2,
991 ))
992}}
993
994#[allow(clippy::too_many_arguments)]
996pub fn spgemm_copy<T: SparseScalar>(
997 handle: &Handle,
998 op_a: Op,
999 op_b: Op,
1000 alpha: &T,
1001 a: &SpMat<'_, T>,
1002 b: &SpMat<'_, T>,
1003 beta: &T,
1004 c: &mut SpMat<'_, T>,
1005 alg: SpGEMMAlg,
1006 plan: &SpGEMMPlan,
1007) -> Result<()> {
1008 let c_api = cusparse()?;
1009 let cu = c_api.cusparse_spgemm_copy()?;
1010 check(unsafe {
1011 cu(
1012 handle.as_raw(),
1013 op_a.raw(),
1014 op_b.raw(),
1015 alpha as *const T as *const c_void,
1016 a.descr,
1017 b.descr,
1018 beta as *const T as *const c_void,
1019 c.descr,
1020 T::data_type(),
1021 alg,
1022 plan.raw,
1023 )
1024 })
1025}
1026
1027#[derive(Debug)]
1031pub struct SpSVPlan {
1032 raw: cusparseSpSVDescr_t,
1033}
1034
1035impl SpSVPlan {
1036 pub fn new() -> Result<Self> {
1039 let c = cusparse()?;
1040 let cu = c.cusparse_spsv_create_descr()?;
1041 let mut d: cusparseSpSVDescr_t = core::ptr::null_mut();
1042 check(unsafe { cu(&mut d) })?;
1043 Ok(Self { raw: d })
1044 }
1045}
1046
1047impl Drop for SpSVPlan {
1048 fn drop(&mut self) {
1049 if let Ok(c) = cusparse() {
1050 if let Ok(cu) = c.cusparse_spsv_destroy_descr() {
1051 let _ = unsafe { cu(self.raw) };
1052 }
1053 }
1054 }
1055}
1056
1057#[allow(clippy::too_many_arguments)]
1060pub fn spsv_buffer_size<T: SparseScalar>(
1061 handle: &Handle,
1062 op: Op,
1063 alpha: &T,
1064 a: &SpMat<'_, T>,
1065 x: &DnVec<'_, T>,
1066 y: &DnVec<'_, T>,
1067 alg: SpSVAlg,
1068 plan: &SpSVPlan,
1069) -> Result<usize> {
1070 let c = cusparse()?;
1071 let cu = c.cusparse_spsv_buffer_size()?;
1072 let mut size = 0usize;
1073 check(unsafe {
1074 cu(
1075 handle.as_raw(),
1076 op.raw(),
1077 alpha as *const T as *const c_void,
1078 a.descr,
1079 x.descr,
1080 y.descr,
1081 T::data_type(),
1082 alg,
1083 plan.raw,
1084 &mut size,
1085 )
1086 })?;
1087 Ok(size)
1088}
1089
1090#[allow(clippy::too_many_arguments)]
1093pub fn spsv_analysis<T: SparseScalar>(
1094 handle: &Handle,
1095 op: Op,
1096 alpha: &T,
1097 a: &SpMat<'_, T>,
1098 x: &DnVec<'_, T>,
1099 y: &DnVec<'_, T>,
1100 alg: SpSVAlg,
1101 plan: &SpSVPlan,
1102 workspace: &mut DeviceBuffer<u8>,
1103) -> Result<()> {
1104 let c = cusparse()?;
1105 let cu = c.cusparse_spsv_analysis()?;
1106 check(unsafe {
1107 cu(
1108 handle.as_raw(),
1109 op.raw(),
1110 alpha as *const T as *const c_void,
1111 a.descr,
1112 x.descr,
1113 y.descr,
1114 T::data_type(),
1115 alg,
1116 plan.raw,
1117 workspace.as_raw().0 as *mut c_void,
1118 )
1119 })
1120}
1121
1122#[allow(clippy::too_many_arguments)]
1125pub fn spsv_solve<T: SparseScalar>(
1126 handle: &Handle,
1127 op: Op,
1128 alpha: &T,
1129 a: &SpMat<'_, T>,
1130 x: &DnVec<'_, T>,
1131 y: &mut DnVec<'_, T>,
1132 alg: SpSVAlg,
1133 plan: &SpSVPlan,
1134) -> Result<()> {
1135 let c = cusparse()?;
1136 let cu = c.cusparse_spsv_solve()?;
1137 check(unsafe {
1138 cu(
1139 handle.as_raw(),
1140 op.raw(),
1141 alpha as *const T as *const c_void,
1142 a.descr,
1143 x.descr,
1144 y.descr,
1145 T::data_type(),
1146 alg,
1147 plan.raw,
1148 )
1149 })
1150}
1151
1152#[derive(Debug)]
1154pub struct SpSMPlan {
1155 raw: cusparseSpSMDescr_t,
1156}
1157
1158impl SpSMPlan {
1159 pub fn new() -> Result<Self> {
1162 let c = cusparse()?;
1163 let cu = c.cusparse_spsm_create_descr()?;
1164 let mut d: cusparseSpSMDescr_t = core::ptr::null_mut();
1165 check(unsafe { cu(&mut d) })?;
1166 Ok(Self { raw: d })
1167 }
1168}
1169
1170impl Drop for SpSMPlan {
1171 fn drop(&mut self) {
1172 if let Ok(c) = cusparse() {
1173 if let Ok(cu) = c.cusparse_spsm_destroy_descr() {
1174 let _ = unsafe { cu(self.raw) };
1175 }
1176 }
1177 }
1178}
1179
1180#[allow(clippy::too_many_arguments)]
1183pub fn spsm_buffer_size<T: SparseScalar>(
1184 handle: &Handle,
1185 op_a: Op,
1186 op_b: Op,
1187 alpha: &T,
1188 a: &SpMat<'_, T>,
1189 b: &DnMat<'_, T>,
1190 c: &DnMat<'_, T>,
1191 alg: SpSMAlg,
1192 plan: &SpSMPlan,
1193) -> Result<usize> {
1194 let c_api = cusparse()?;
1195 let cu = c_api.cusparse_spsm_buffer_size()?;
1196 let mut size = 0usize;
1197 check(unsafe {
1198 cu(
1199 handle.as_raw(),
1200 op_a.raw(),
1201 op_b.raw(),
1202 alpha as *const T as *const c_void,
1203 a.descr,
1204 b.descr,
1205 c.descr,
1206 T::data_type(),
1207 alg,
1208 plan.raw,
1209 &mut size,
1210 )
1211 })?;
1212 Ok(size)
1213}
1214
1215#[allow(clippy::too_many_arguments)]
1218pub fn spsm_analysis<T: SparseScalar>(
1219 handle: &Handle,
1220 op_a: Op,
1221 op_b: Op,
1222 alpha: &T,
1223 a: &SpMat<'_, T>,
1224 b: &DnMat<'_, T>,
1225 c: &DnMat<'_, T>,
1226 alg: SpSMAlg,
1227 plan: &SpSMPlan,
1228 workspace: &mut DeviceBuffer<u8>,
1229) -> Result<()> {
1230 let c_api = cusparse()?;
1231 let cu = c_api.cusparse_spsm_analysis()?;
1232 check(unsafe {
1233 cu(
1234 handle.as_raw(),
1235 op_a.raw(),
1236 op_b.raw(),
1237 alpha as *const T as *const c_void,
1238 a.descr,
1239 b.descr,
1240 c.descr,
1241 T::data_type(),
1242 alg,
1243 plan.raw,
1244 workspace.as_raw().0 as *mut c_void,
1245 )
1246 })
1247}
1248
1249#[allow(clippy::too_many_arguments)]
1252pub fn spsm_solve<T: SparseScalar>(
1253 handle: &Handle,
1254 op_a: Op,
1255 op_b: Op,
1256 alpha: &T,
1257 a: &SpMat<'_, T>,
1258 b: &DnMat<'_, T>,
1259 c: &mut DnMat<'_, T>,
1260 alg: SpSMAlg,
1261 plan: &SpSMPlan,
1262) -> Result<()> {
1263 let c_api = cusparse()?;
1264 let cu = c_api.cusparse_spsm_solve()?;
1265 check(unsafe {
1266 cu(
1267 handle.as_raw(),
1268 op_a.raw(),
1269 op_b.raw(),
1270 alpha as *const T as *const c_void,
1271 a.descr,
1272 b.descr,
1273 c.descr,
1274 T::data_type(),
1275 alg,
1276 plan.raw,
1277 )
1278 })
1279}
1280
1281#[allow(clippy::too_many_arguments)]
1286pub fn sddmm_buffer_size<T: SparseScalar>(
1287 handle: &Handle,
1288 op_a: Op,
1289 op_b: Op,
1290 alpha: &T,
1291 a: &DnMat<'_, T>,
1292 b: &DnMat<'_, T>,
1293 beta: &T,
1294 c: &SpMat<'_, T>,
1295 alg: SDDMMAlg,
1296) -> Result<usize> {
1297 let c_api = cusparse()?;
1298 let cu = c_api.cusparse_sddmm_buffer_size()?;
1299 let mut size = 0usize;
1300 check(unsafe {
1301 cu(
1302 handle.as_raw(),
1303 op_a.raw(),
1304 op_b.raw(),
1305 alpha as *const T as *const c_void,
1306 a.descr,
1307 b.descr,
1308 beta as *const T as *const c_void,
1309 c.descr,
1310 T::data_type(),
1311 alg,
1312 &mut size,
1313 )
1314 })?;
1315 Ok(size)
1316}
1317
1318#[allow(clippy::too_many_arguments)]
1321pub fn sddmm<T: SparseScalar>(
1322 handle: &Handle,
1323 op_a: Op,
1324 op_b: Op,
1325 alpha: &T,
1326 a: &DnMat<'_, T>,
1327 b: &DnMat<'_, T>,
1328 beta: &T,
1329 c: &mut SpMat<'_, T>,
1330 alg: SDDMMAlg,
1331 workspace: &mut DeviceBuffer<u8>,
1332) -> Result<()> {
1333 let c_api = cusparse()?;
1334 let cu = c_api.cusparse_sddmm()?;
1335 check(unsafe {
1336 cu(
1337 handle.as_raw(),
1338 op_a.raw(),
1339 op_b.raw(),
1340 alpha as *const T as *const c_void,
1341 a.descr,
1342 b.descr,
1343 beta as *const T as *const c_void,
1344 c.descr,
1345 T::data_type(),
1346 alg,
1347 workspace.as_raw().0 as *mut c_void,
1348 )
1349 })
1350}
1351
1352#[allow(clippy::too_many_arguments)]
1355pub fn sddmm_preprocess<T: SparseScalar>(
1356 handle: &Handle,
1357 op_a: Op,
1358 op_b: Op,
1359 alpha: &T,
1360 a: &DnMat<'_, T>,
1361 b: &DnMat<'_, T>,
1362 beta: &T,
1363 c: &mut SpMat<'_, T>,
1364 alg: SDDMMAlg,
1365 workspace: &mut DeviceBuffer<u8>,
1366) -> Result<()> {
1367 let c_api = cusparse()?;
1368 let cu = c_api.cusparse_sddmm_preprocess()?;
1369 check(unsafe {
1370 cu(
1371 handle.as_raw(),
1372 op_a.raw(),
1373 op_b.raw(),
1374 alpha as *const T as *const c_void,
1375 a.descr,
1376 b.descr,
1377 beta as *const T as *const c_void,
1378 c.descr,
1379 T::data_type(),
1380 alg,
1381 workspace.as_raw().0 as *mut c_void,
1382 )
1383 })
1384}
1385
1386pub fn sparse_to_dense_buffer_size<T: SparseScalar>(
1391 handle: &Handle,
1392 sp: &SpMat<'_, T>,
1393 dn: &DnMat<'_, T>,
1394) -> Result<usize> {
1395 let c = cusparse()?;
1396 let cu = c.cusparse_sparse_to_dense_buffer_size()?;
1397 let mut size = 0usize;
1398 check(unsafe { cu(handle.as_raw(), sp.descr, dn.descr, 0, &mut size) })?;
1399 Ok(size)
1400}
1401
1402pub fn sparse_to_dense<T: SparseScalar>(
1405 handle: &Handle,
1406 sp: &SpMat<'_, T>,
1407 dn: &mut DnMat<'_, T>,
1408 workspace: &mut DeviceBuffer<u8>,
1409) -> Result<()> {
1410 let c = cusparse()?;
1411 let cu = c.cusparse_sparse_to_dense()?;
1412 check(unsafe {
1413 cu(
1414 handle.as_raw(),
1415 sp.descr,
1416 dn.descr,
1417 0,
1418 workspace.as_raw().0 as *mut c_void,
1419 )
1420 })
1421}
1422
1423pub fn dense_to_sparse_buffer_size<T: SparseScalar>(
1426 handle: &Handle,
1427 dn: &DnMat<'_, T>,
1428 sp: &SpMat<'_, T>,
1429) -> Result<usize> {
1430 let c = cusparse()?;
1431 let cu = c.cusparse_dense_to_sparse_buffer_size()?;
1432 let mut size = 0usize;
1433 check(unsafe { cu(handle.as_raw(), dn.descr, sp.descr, 0, &mut size) })?;
1434 Ok(size)
1435}
1436
1437pub fn dense_to_sparse_analysis<T: SparseScalar>(
1440 handle: &Handle,
1441 dn: &DnMat<'_, T>,
1442 sp: &SpMat<'_, T>,
1443 workspace: &mut DeviceBuffer<u8>,
1444) -> Result<()> {
1445 let c = cusparse()?;
1446 let cu = c.cusparse_dense_to_sparse_analysis()?;
1447 check(unsafe {
1448 cu(
1449 handle.as_raw(),
1450 dn.descr,
1451 sp.descr,
1452 0,
1453 workspace.as_raw().0 as *mut c_void,
1454 )
1455 })
1456}
1457
1458pub fn dense_to_sparse_convert<T: SparseScalar>(
1461 handle: &Handle,
1462 dn: &DnMat<'_, T>,
1463 sp: &mut SpMat<'_, T>,
1464 workspace: &mut DeviceBuffer<u8>,
1465) -> Result<()> {
1466 let c = cusparse()?;
1467 let cu = c.cusparse_dense_to_sparse_convert()?;
1468 check(unsafe {
1469 cu(
1470 handle.as_raw(),
1471 dn.descr,
1472 sp.descr,
1473 0,
1474 workspace.as_raw().0 as *mut c_void,
1475 )
1476 })
1477}
1478
1479#[allow(clippy::too_many_arguments)]
1481pub fn csr2csc_ex2_buffer_size<T: SparseScalar + baracuda_types::DeviceRepr>(
1482 handle: &Handle,
1483 m: i32,
1484 n: i32,
1485 nnz: i32,
1486 csr_val: &DeviceBuffer<T>,
1487 csr_row_ptr: &DeviceBuffer<i32>,
1488 csr_col_ind: &DeviceBuffer<i32>,
1489 csc_val: &mut DeviceBuffer<T>,
1490 csc_col_ptr: &mut DeviceBuffer<i32>,
1491 csc_row_ind: &mut DeviceBuffer<i32>,
1492 copy_values: bool,
1493 idx_base: IndexBase,
1494 alg: Csr2CscAlg,
1495) -> Result<usize> {
1496 let c = cusparse()?;
1497 let cu = c.cusparse_csr2csc_ex2_buffer_size()?;
1498 let mut size = 0usize;
1499 check(unsafe {
1500 cu(
1501 handle.as_raw(),
1502 m,
1503 n,
1504 nnz,
1505 csr_val.as_raw().0 as *const c_void,
1506 csr_row_ptr.as_raw().0 as *const i32,
1507 csr_col_ind.as_raw().0 as *const i32,
1508 csc_val.as_raw().0 as *mut c_void,
1509 csc_col_ptr.as_raw().0 as *mut i32,
1510 csc_row_ind.as_raw().0 as *mut i32,
1511 T::data_type(),
1512 copy_values as i32,
1513 idx_base,
1514 alg,
1515 &mut size,
1516 )
1517 })?;
1518 Ok(size)
1519}
1520
1521#[allow(clippy::too_many_arguments)]
1524pub fn csr2csc_ex2<T: SparseScalar + baracuda_types::DeviceRepr>(
1525 handle: &Handle,
1526 m: i32,
1527 n: i32,
1528 nnz: i32,
1529 csr_val: &DeviceBuffer<T>,
1530 csr_row_ptr: &DeviceBuffer<i32>,
1531 csr_col_ind: &DeviceBuffer<i32>,
1532 csc_val: &mut DeviceBuffer<T>,
1533 csc_col_ptr: &mut DeviceBuffer<i32>,
1534 csc_row_ind: &mut DeviceBuffer<i32>,
1535 copy_values: bool,
1536 idx_base: IndexBase,
1537 alg: Csr2CscAlg,
1538 workspace: &mut DeviceBuffer<u8>,
1539) -> Result<()> {
1540 let c = cusparse()?;
1541 let cu = c.cusparse_csr2csc_ex2()?;
1542 check(unsafe {
1543 cu(
1544 handle.as_raw(),
1545 m,
1546 n,
1547 nnz,
1548 csr_val.as_raw().0 as *const c_void,
1549 csr_row_ptr.as_raw().0 as *const i32,
1550 csr_col_ind.as_raw().0 as *const i32,
1551 csc_val.as_raw().0 as *mut c_void,
1552 csc_col_ptr.as_raw().0 as *mut i32,
1553 csc_row_ind.as_raw().0 as *mut i32,
1554 T::data_type(),
1555 copy_values as i32,
1556 idx_base,
1557 alg,
1558 workspace.as_raw().0 as *mut c_void,
1559 )
1560 })
1561}
1562
1563pub fn axpby<T: SparseScalar>(
1568 handle: &Handle,
1569 alpha: &T,
1570 x: &DnVec<'_, T>,
1571 beta: &T,
1572 y: &mut DnVec<'_, T>,
1573) -> Result<()> {
1574 let c = cusparse()?;
1575 let cu = c.cusparse_axpby()?;
1576 check(unsafe {
1577 cu(
1578 handle.as_raw(),
1579 alpha as *const T as *const c_void,
1580 x.descr,
1581 beta as *const T as *const c_void,
1582 y.descr,
1583 )
1584 })
1585}
1586
1587pub fn gather<T: SparseScalar>(
1589 handle: &Handle,
1590 y: &DnVec<'_, T>,
1591 x: &mut DnVec<'_, T>,
1592) -> Result<()> {
1593 let c = cusparse()?;
1594 let cu = c.cusparse_gather()?;
1595 check(unsafe { cu(handle.as_raw(), y.descr, x.descr) })
1596}
1597
1598pub fn scatter<T: SparseScalar>(
1600 handle: &Handle,
1601 x: &DnVec<'_, T>,
1602 y: &mut DnVec<'_, T>,
1603) -> Result<()> {
1604 let c = cusparse()?;
1605 let cu = c.cusparse_scatter()?;
1606 check(unsafe { cu(handle.as_raw(), x.descr, y.descr) })
1607}
1608
1609pub fn rot<T: SparseScalar>(
1612 handle: &Handle,
1613 c_cos: &T,
1614 s_sin: &T,
1615 x: &mut DnVec<'_, T>,
1616 y: &mut DnVec<'_, T>,
1617) -> Result<()> {
1618 let c_api = cusparse()?;
1619 let cu = c_api.cusparse_rot()?;
1620 check(unsafe {
1621 cu(
1622 handle.as_raw(),
1623 c_cos as *const T as *const c_void,
1624 s_sin as *const T as *const c_void,
1625 x.descr,
1626 y.descr,
1627 )
1628 })
1629}
1630
1631pub type CsrMatrix<'buf> = SpMat<'buf, f32>;
1635pub type DenseVector<'buf, T> = DnVec<'buf, T>;