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