1use std::{marker::PhantomData, mem::MaybeUninit, mem::size_of, ptr};
2
3use singe_cuda::{data_type::DataTypeLike, memory::DeviceMemory, types::DevicePtr};
4
5use crate::{
6 context::Context,
7 error::{Error, Result},
8 sys, try_ffi,
9 types::{
10 CsrToCscAlgorithm, DenseToSparseAlgorithm, DiagonalType, FillMode, Format, IndexBase,
11 IndexTypeLike, MatrixType, Order, SparseMatrixAttribute, SparseToDenseAlgorithm,
12 },
13 utility::{to_i32, to_i64, to_usize},
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct SparseMatrixShape {
18 pub rows: usize,
19 pub cols: usize,
20 pub nonzero_count: usize,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct DenseMatrixInfo {
25 pub rows: usize,
26 pub cols: usize,
27 pub leading_dimension: usize,
28 pub values: DevicePtr,
29 pub order: Order,
30}
31
32#[derive(Debug)]
33pub struct MatrixDescriptor {
34 handle: sys::cusparseMatDescr_t,
35}
36
37#[derive(Debug)]
38pub struct SparseMatrixDescriptor<'a> {
39 handle: sys::cusparseSpMatDescr_t,
40 _buffers: PhantomData<&'a mut ()>,
41}
42
43#[derive(Debug)]
44pub struct DenseMatrixDescriptor<'a> {
45 handle: sys::cusparseDnMatDescr_t,
46 _buffers: PhantomData<&'a mut ()>,
47}
48
49unsafe impl Send for MatrixDescriptor {}
53unsafe impl Sync for MatrixDescriptor {}
54unsafe impl Send for SparseMatrixDescriptor<'_> {}
55unsafe impl Send for DenseMatrixDescriptor<'_> {}
56
57impl MatrixDescriptor {
58 pub fn create() -> Result<Self> {
67 let mut handle = ptr::null_mut();
68 unsafe {
69 try_ffi!(sys::cusparseCreateMatDescr(&raw mut handle))?;
70 }
71
72 if handle.is_null() {
73 return Err(Error::NullHandle);
74 }
75
76 Ok(Self { handle })
77 }
78
79 pub fn matrix_type(&self) -> MatrixType {
81 unsafe { sys::cusparseGetMatType(self.as_raw()).into() }
82 }
83
84 pub fn set_matrix_type(&mut self, matrix_type: MatrixType) -> Result<()> {
90 unsafe {
91 try_ffi!(sys::cusparseSetMatType(self.as_raw(), matrix_type.into()))?;
92 }
93 Ok(())
94 }
95
96 pub fn fill_mode(&self) -> FillMode {
98 unsafe { sys::cusparseGetMatFillMode(self.as_raw()).into() }
99 }
100
101 pub fn set_fill_mode(&mut self, fill_mode: FillMode) -> Result<()> {
107 unsafe {
108 try_ffi!(sys::cusparseSetMatFillMode(self.as_raw(), fill_mode.into()))?;
109 }
110 Ok(())
111 }
112
113 pub fn diagonal_type(&self) -> DiagonalType {
115 unsafe { sys::cusparseGetMatDiagType(self.as_raw()).into() }
116 }
117
118 pub fn set_diagonal_type(&mut self, diagonal_type: DiagonalType) -> Result<()> {
124 unsafe {
125 try_ffi!(sys::cusparseSetMatDiagType(
126 self.as_raw(),
127 diagonal_type.into(),
128 ))?;
129 }
130 Ok(())
131 }
132
133 pub fn index_base(&self) -> IndexBase {
135 unsafe { sys::cusparseGetMatIndexBase(self.as_raw()).into() }
136 }
137
138 pub fn set_index_base(&mut self, index_base: IndexBase) -> Result<()> {
144 unsafe {
145 try_ffi!(sys::cusparseSetMatIndexBase(
146 self.as_raw(),
147 index_base.into(),
148 ))?;
149 }
150 Ok(())
151 }
152
153 pub fn as_raw(&self) -> sys::cusparseMatDescr_t {
154 self.handle
155 }
156}
157
158impl Drop for MatrixDescriptor {
159 fn drop(&mut self) {
160 unsafe {
161 if let Err(err) = try_ffi!(sys::cusparseDestroyMatDescr(self.handle)) {
162 #[cfg(debug_assertions)]
163 eprintln!("failed to destroy cusparse matrix descriptor: {err}");
164 }
165 }
166 }
167}
168
169impl<'a> SparseMatrixDescriptor<'a> {
170 pub fn create_csr<Offsets: IndexTypeLike, Columns: IndexTypeLike, T: DataTypeLike>(
175 rows: usize,
176 cols: usize,
177 nonzero_count: usize,
178 row_offsets: &'a mut DeviceMemory<Offsets>,
179 column_indices: &'a mut DeviceMemory<Columns>,
180 values: &'a mut DeviceMemory<T>,
181 index_base: IndexBase,
182 ) -> Result<Self> {
183 let mut raw = ptr::null_mut();
184 unsafe {
185 try_ffi!(sys::cusparseCreateCsr(
186 &raw mut raw,
187 to_i64(rows, "rows")?,
188 to_i64(cols, "cols")?,
189 to_i64(nonzero_count, "nonzero_count")?,
190 row_offsets.as_mut_ptr().cast(),
191 column_indices.as_mut_ptr().cast(),
192 values.as_mut_ptr().cast(),
193 Offsets::index_type().into(),
194 Columns::index_type().into(),
195 index_base.into(),
196 T::data_type().into(),
197 ))?;
198 }
199 ensure_spmat(raw)
200 }
201
202 pub fn create_csc<Offsets: IndexTypeLike, Rows: IndexTypeLike, T: DataTypeLike>(
207 rows: usize,
208 cols: usize,
209 nonzero_count: usize,
210 column_offsets: &'a mut DeviceMemory<Offsets>,
211 row_indices: &'a mut DeviceMemory<Rows>,
212 values: &'a mut DeviceMemory<T>,
213 index_base: IndexBase,
214 ) -> Result<Self> {
215 let mut raw = ptr::null_mut();
216 unsafe {
217 try_ffi!(sys::cusparseCreateCsc(
218 &raw mut raw,
219 to_i64(rows, "rows")?,
220 to_i64(cols, "cols")?,
221 to_i64(nonzero_count, "nonzero_count")?,
222 column_offsets.as_mut_ptr().cast(),
223 row_indices.as_mut_ptr().cast(),
224 values.as_mut_ptr().cast(),
225 Offsets::index_type().into(),
226 Rows::index_type().into(),
227 index_base.into(),
228 T::data_type().into(),
229 ))?;
230 }
231 ensure_spmat(raw)
232 }
233
234 pub fn create_coo<I: IndexTypeLike, T: DataTypeLike>(
239 rows: usize,
240 cols: usize,
241 nonzero_count: usize,
242 row_indices: &'a mut DeviceMemory<I>,
243 column_indices: &'a mut DeviceMemory<I>,
244 values: &'a mut DeviceMemory<T>,
245 index_base: IndexBase,
246 ) -> Result<Self> {
247 let mut raw = ptr::null_mut();
248 unsafe {
249 try_ffi!(sys::cusparseCreateCoo(
250 &raw mut raw,
251 to_i64(rows, "rows")?,
252 to_i64(cols, "cols")?,
253 to_i64(nonzero_count, "nonzero_count")?,
254 row_indices.as_mut_ptr().cast(),
255 column_indices.as_mut_ptr().cast(),
256 values.as_mut_ptr().cast(),
257 I::index_type().into(),
258 index_base.into(),
259 T::data_type().into(),
260 ))?;
261 }
262 ensure_spmat(raw)
263 }
264
265 pub fn create_bsr<Offsets: IndexTypeLike, Columns: IndexTypeLike, T: DataTypeLike>(
270 block_rows: usize,
271 block_cols: usize,
272 block_nnz: usize,
273 row_block_size: usize,
274 col_block_size: usize,
275 row_offsets: &'a mut DeviceMemory<Offsets>,
276 column_indices: &'a mut DeviceMemory<Columns>,
277 values: &'a mut DeviceMemory<T>,
278 index_base: IndexBase,
279 order: Order,
280 ) -> Result<Self> {
281 let mut raw = ptr::null_mut();
282 unsafe {
283 try_ffi!(sys::cusparseCreateBsr(
284 &raw mut raw,
285 to_i64(block_rows, "block_rows")?,
286 to_i64(block_cols, "block_cols")?,
287 to_i64(block_nnz, "block_nnz")?,
288 to_i64(row_block_size, "row_block_size")?,
289 to_i64(col_block_size, "col_block_size")?,
290 row_offsets.as_mut_ptr().cast(),
291 column_indices.as_mut_ptr().cast(),
292 values.as_mut_ptr().cast(),
293 Offsets::index_type().into(),
294 Columns::index_type().into(),
295 index_base.into(),
296 T::data_type().into(),
297 order.into(),
298 ))?;
299 }
300 ensure_spmat(raw)
301 }
302
303 pub fn create_blocked_ell<I: IndexTypeLike, T: DataTypeLike>(
310 rows: usize,
311 cols: usize,
312 block_size: usize,
313 ell_cols: usize,
314 column_indices: &'a mut DeviceMemory<I>,
315 values: &'a mut DeviceMemory<T>,
316 index_base: IndexBase,
317 ) -> Result<Self> {
318 let mut raw = ptr::null_mut();
319 unsafe {
320 try_ffi!(sys::cusparseCreateBlockedEll(
321 &raw mut raw,
322 to_i64(rows, "rows")?,
323 to_i64(cols, "cols")?,
324 to_i64(block_size, "block_size")?,
325 to_i64(ell_cols, "ell_cols")?,
326 column_indices.as_mut_ptr().cast(),
327 values.as_mut_ptr().cast(),
328 I::index_type().into(),
329 index_base.into(),
330 T::data_type().into(),
331 ))?;
332 }
333 ensure_spmat(raw)
334 }
335
336 pub fn create_sliced_ell<
341 SliceOffsets: IndexTypeLike,
342 Columns: IndexTypeLike,
343 T: DataTypeLike,
344 >(
345 rows: usize,
346 cols: usize,
347 nonzero_count: usize,
348 values_size: usize,
349 slice_size: usize,
350 slice_offsets: &'a mut DeviceMemory<SliceOffsets>,
351 column_indices: &'a mut DeviceMemory<Columns>,
352 values: &'a mut DeviceMemory<T>,
353 index_base: IndexBase,
354 ) -> Result<Self> {
355 let mut raw = ptr::null_mut();
356 unsafe {
357 try_ffi!(sys::cusparseCreateSlicedEll(
358 &raw mut raw,
359 to_i64(rows, "rows")?,
360 to_i64(cols, "cols")?,
361 to_i64(nonzero_count, "nonzero_count")?,
362 to_i64(values_size, "values_size")?,
363 to_i64(slice_size, "slice_size")?,
364 slice_offsets.as_mut_ptr().cast(),
365 column_indices.as_mut_ptr().cast(),
366 values.as_mut_ptr().cast(),
367 SliceOffsets::index_type().into(),
368 Columns::index_type().into(),
369 index_base.into(),
370 T::data_type().into(),
371 ))?;
372 }
373 ensure_spmat(raw)
374 }
375
376 pub fn format(&self) -> Result<Format> {
382 let mut format = sys::cusparseFormat_t::CUSPARSE_FORMAT_CSR;
383 unsafe {
384 try_ffi!(sys::cusparseSpMatGetFormat(
385 self.as_raw_const(),
386 &raw mut format,
387 ))?;
388 }
389 Ok(format.into())
390 }
391
392 pub fn index_base(&self) -> Result<IndexBase> {
398 let mut index_base = sys::cusparseIndexBase_t::CUSPARSE_INDEX_BASE_ZERO;
399 unsafe {
400 try_ffi!(sys::cusparseSpMatGetIndexBase(
401 self.as_raw_const(),
402 &raw mut index_base,
403 ))?;
404 }
405 Ok(index_base.into())
406 }
407
408 pub fn values(&self) -> Result<DevicePtr> {
414 let mut values = ptr::null_mut();
415 unsafe {
416 try_ffi!(sys::cusparseSpMatGetValues(self.as_raw(), &raw mut values))?;
417 }
418 Ok(values.into())
419 }
420
421 pub fn set_values<T: DataTypeLike>(&mut self, values: &'a mut DeviceMemory<T>) -> Result<()> {
429 unsafe {
430 try_ffi!(sys::cusparseSpMatSetValues(
431 self.as_raw(),
432 values.as_mut_ptr().cast(),
433 ))?;
434 }
435 Ok(())
436 }
437
438 pub fn shape(&self) -> Result<SparseMatrixShape> {
445 let mut rows = 0_i64;
446 let mut cols = 0_i64;
447 let mut nnz = 0_i64;
448 unsafe {
449 try_ffi!(sys::cusparseSpMatGetSize(
450 self.as_raw_const(),
451 &raw mut rows,
452 &raw mut cols,
453 &raw mut nnz,
454 ))?;
455 }
456 Ok(SparseMatrixShape {
457 rows: to_usize(rows, "rows")?,
458 cols: to_usize(cols, "cols")?,
459 nonzero_count: to_usize(nnz, "nonzero_count")?,
460 })
461 }
462
463 pub fn strided_batch_count(&self) -> Result<i32> {
469 let mut batch_count = 0;
470 unsafe {
471 try_ffi!(sys::cusparseSpMatGetStridedBatch(
472 self.as_raw_const(),
473 &raw mut batch_count,
474 ))?;
475 }
476 Ok(batch_count)
477 }
478
479 pub fn set_coo_strided_batch(&mut self, batch_count: usize, batch_stride: usize) -> Result<()> {
486 unsafe {
487 try_ffi!(sys::cusparseCooSetStridedBatch(
488 self.as_raw(),
489 to_i32(batch_count, "batch_count")?,
490 to_i64(batch_stride, "batch_stride")?,
491 ))?;
492 }
493 Ok(())
494 }
495
496 pub fn set_csr_strided_batch(
498 &mut self,
499 batch_count: usize,
500 offsets_batch_stride: usize,
501 columns_values_batch_stride: usize,
502 ) -> Result<()> {
503 unsafe {
504 try_ffi!(sys::cusparseCsrSetStridedBatch(
505 self.as_raw(),
506 to_i32(batch_count, "batch_count")?,
507 to_i64(offsets_batch_stride, "offsets_batch_stride")?,
508 to_i64(columns_values_batch_stride, "columns_values_batch_stride")?,
509 ))?;
510 }
511 Ok(())
512 }
513
514 pub fn set_bsr_strided_batch(
516 &mut self,
517 batch_count: usize,
518 offsets_batch_stride: usize,
519 columns_batch_stride: usize,
520 values_batch_stride: usize,
521 ) -> Result<()> {
522 unsafe {
523 try_ffi!(sys::cusparseBsrSetStridedBatch(
524 self.as_raw(),
525 to_i32(batch_count, "batch_count")?,
526 to_i64(offsets_batch_stride, "offsets_batch_stride")?,
527 to_i64(columns_batch_stride, "columns_batch_stride")?,
528 to_i64(values_batch_stride, "values_batch_stride")?,
529 ))?;
530 }
531 Ok(())
532 }
533
534 pub fn fill_mode(&self) -> Result<FillMode> {
535 let raw: sys::cusparseFillMode_t = self.raw_attribute(SparseMatrixAttribute::FillMode)?;
536 Ok(raw.into())
537 }
538
539 pub fn set_fill_mode(&mut self, fill_mode: FillMode) -> Result<()> {
540 self.set_attribute_raw::<sys::cusparseFillMode_t>(
541 SparseMatrixAttribute::FillMode,
542 fill_mode.into(),
543 )
544 }
545
546 pub fn diagonal_type(&self) -> Result<DiagonalType> {
547 let raw: sys::cusparseDiagType_t =
548 self.raw_attribute(SparseMatrixAttribute::DiagonalType)?;
549 Ok(raw.into())
550 }
551
552 pub fn set_diagonal_type(&mut self, diagonal_type: DiagonalType) -> Result<()> {
553 self.set_attribute_raw::<sys::cusparseDiagType_t>(
554 SparseMatrixAttribute::DiagonalType,
555 diagonal_type.into(),
556 )
557 }
558
559 pub fn set_csr_pointers(
563 &mut self,
564 row_offsets: &'a mut DeviceMemory<impl IndexTypeLike>,
565 column_indices: &'a mut DeviceMemory<impl IndexTypeLike>,
566 values: &'a mut DeviceMemory<impl DataTypeLike>,
567 ) -> Result<()> {
568 unsafe {
569 try_ffi!(sys::cusparseCsrSetPointers(
570 self.as_raw(),
571 row_offsets.as_mut_ptr().cast(),
572 column_indices.as_mut_ptr().cast(),
573 values.as_mut_ptr().cast(),
574 ))?;
575 }
576 Ok(())
577 }
578
579 pub fn set_csc_pointers(
583 &mut self,
584 column_offsets: &'a mut DeviceMemory<impl IndexTypeLike>,
585 row_indices: &'a mut DeviceMemory<impl IndexTypeLike>,
586 values: &'a mut DeviceMemory<impl DataTypeLike>,
587 ) -> Result<()> {
588 unsafe {
589 try_ffi!(sys::cusparseCscSetPointers(
590 self.as_raw(),
591 column_offsets.as_mut_ptr().cast(),
592 row_indices.as_mut_ptr().cast(),
593 values.as_mut_ptr().cast(),
594 ))?;
595 }
596 Ok(())
597 }
598
599 pub fn set_coo_pointers(
603 &mut self,
604 row_indices: &'a mut DeviceMemory<impl IndexTypeLike>,
605 column_indices: &'a mut DeviceMemory<impl IndexTypeLike>,
606 values: &'a mut DeviceMemory<impl DataTypeLike>,
607 ) -> Result<()> {
608 unsafe {
609 try_ffi!(sys::cusparseCooSetPointers(
610 self.as_raw(),
611 row_indices.as_mut_ptr().cast(),
612 column_indices.as_mut_ptr().cast(),
613 values.as_mut_ptr().cast(),
614 ))?;
615 }
616 Ok(())
617 }
618
619 pub fn as_raw(&self) -> sys::cusparseSpMatDescr_t {
620 self.handle
621 }
622
623 pub fn as_raw_const(&self) -> sys::cusparseConstSpMatDescr_t {
624 self.handle.cast_const()
625 }
626
627 fn raw_attribute<T: Copy>(&self, attribute: SparseMatrixAttribute) -> Result<T> {
628 let mut value = MaybeUninit::<T>::uninit();
629 unsafe {
630 try_ffi!(sys::cusparseSpMatGetAttribute(
631 self.as_raw_const(),
632 attribute.into(),
633 value.as_mut_ptr().cast(),
634 u64::try_from(size_of::<T>()).map_err(|_| Error::OutOfRange {
635 name: "attribute size".into(),
636 })?,
637 ))?;
638 Ok(value.assume_init())
639 }
640 }
641
642 fn set_attribute_raw<T>(&mut self, attribute: SparseMatrixAttribute, value: T) -> Result<()> {
643 let mut value = value;
644 unsafe {
645 try_ffi!(sys::cusparseSpMatSetAttribute(
646 self.as_raw(),
647 attribute.into(),
648 &raw mut value as *mut _,
649 u64::try_from(size_of::<T>()).map_err(|_| Error::OutOfRange {
650 name: "attribute size".into(),
651 })?,
652 ))?;
653 }
654 Ok(())
655 }
656}
657
658impl Drop for SparseMatrixDescriptor<'_> {
659 fn drop(&mut self) {
660 unsafe {
661 if let Err(err) = try_ffi!(sys::cusparseDestroySpMat(self.as_raw_const())) {
662 #[cfg(debug_assertions)]
663 eprintln!("failed to destroy cusparse sparse matrix descriptor: {err}");
664 }
665 }
666 }
667}
668
669impl<'a> DenseMatrixDescriptor<'a> {
670 pub fn create<T: DataTypeLike>(
675 rows: usize,
676 cols: usize,
677 leading_dimension: usize,
678 values: &'a mut DeviceMemory<T>,
679 order: Order,
680 ) -> Result<Self> {
681 let mut handle = ptr::null_mut();
682 unsafe {
683 try_ffi!(sys::cusparseCreateDnMat(
684 &raw mut handle,
685 to_i64(rows, "rows")?,
686 to_i64(cols, "cols")?,
687 to_i64(leading_dimension, "leading_dimension")?,
688 values.as_mut_ptr().cast(),
689 T::data_type().into(),
690 order.into(),
691 ))?;
692 }
693
694 if handle.is_null() {
695 return Err(Error::NullHandle);
696 }
697
698 Ok(Self {
699 handle,
700 _buffers: PhantomData,
701 })
702 }
703
704 pub fn values(&self) -> Result<DevicePtr> {
710 let mut values = ptr::null_mut();
711 unsafe {
712 try_ffi!(sys::cusparseDnMatGetValues(self.as_raw(), &raw mut values))?;
713 }
714 Ok(values.into())
715 }
716
717 pub fn set_values<T: DataTypeLike>(&mut self, values: &'a mut DeviceMemory<T>) -> Result<()> {
725 unsafe {
726 try_ffi!(sys::cusparseDnMatSetValues(
727 self.as_raw(),
728 values.as_mut_ptr().cast(),
729 ))?;
730 }
731 Ok(())
732 }
733
734 pub fn info(&self) -> Result<DenseMatrixInfo> {
741 let mut rows = 0_i64;
742 let mut cols = 0_i64;
743 let mut leading_dimension = 0_i64;
744 let mut values = ptr::null_mut();
745 let mut value_type = MaybeUninit::uninit();
746 let mut order = sys::cusparseOrder_t::CUSPARSE_ORDER_ROW;
747 unsafe {
748 try_ffi!(sys::cusparseDnMatGet(
749 self.as_raw(),
750 &raw mut rows,
751 &raw mut cols,
752 &raw mut leading_dimension,
753 &raw mut values,
754 value_type.as_mut_ptr(),
755 &raw mut order,
756 ))?;
757 }
758 Ok(DenseMatrixInfo {
759 rows: to_usize(rows, "rows")?,
760 cols: to_usize(cols, "cols")?,
761 leading_dimension: to_usize(leading_dimension, "leading_dimension")?,
762 values: values.into(),
763 order: order.into(),
764 })
765 }
766
767 pub fn set_strided_batch(&mut self, batch_count: usize, batch_stride: usize) -> Result<()> {
774 unsafe {
775 try_ffi!(sys::cusparseDnMatSetStridedBatch(
776 self.as_raw(),
777 to_i32(batch_count, "batch_count")?,
778 to_i64(batch_stride, "batch_stride")?,
779 ))?;
780 }
781 Ok(())
782 }
783
784 pub fn strided_batch(&self) -> Result<(i32, usize)> {
791 let mut batch_count = 0;
792 let mut batch_stride = 0_i64;
793 unsafe {
794 try_ffi!(sys::cusparseDnMatGetStridedBatch(
795 self.as_raw_const(),
796 &raw mut batch_count,
797 &raw mut batch_stride,
798 ))?;
799 }
800 Ok((batch_count, to_usize(batch_stride, "batch_stride")?))
801 }
802
803 pub fn as_raw(&self) -> sys::cusparseDnMatDescr_t {
804 self.handle
805 }
806
807 pub fn as_raw_const(&self) -> sys::cusparseConstDnMatDescr_t {
808 self.handle.cast_const()
809 }
810}
811
812impl Drop for DenseMatrixDescriptor<'_> {
813 fn drop(&mut self) {
814 unsafe {
815 if let Err(err) = try_ffi!(sys::cusparseDestroyDnMat(self.as_raw_const())) {
816 #[cfg(debug_assertions)]
817 eprintln!("failed to destroy cusparse dense matrix descriptor: {err}");
818 }
819 }
820 }
821}
822
823fn ensure_spmat<'a>(handle: sys::cusparseSpMatDescr_t) -> Result<SparseMatrixDescriptor<'a>> {
824 if handle.is_null() {
825 Err(Error::NullHandle)
826 } else {
827 Ok(SparseMatrixDescriptor {
828 handle,
829 _buffers: PhantomData,
830 })
831 }
832}
833
834pub fn csr_to_csc<T: DataTypeLike>(
887 ctx: &Context,
888 row_count: usize,
889 col_count: usize,
890 nonzero_count: usize,
891 csr_values: &DeviceMemory<T>,
892 csr_row_offsets: &DeviceMemory<i32>,
893 csr_column_indices: &DeviceMemory<i32>,
894 csc_values: &mut DeviceMemory<T>,
895 csc_column_offsets: &mut DeviceMemory<i32>,
896 csc_row_indices: &mut DeviceMemory<i32>,
897 action: crate::types::Action,
898 index_base: IndexBase,
899 algorithm: CsrToCscAlgorithm,
900 external_buffer: &mut DeviceMemory<u8>,
901) -> Result<()> {
902 ctx.bind()?;
903 unsafe {
904 try_ffi!(sys::cusparseCsr2cscEx2(
905 ctx.as_raw(),
906 to_i32(row_count, "row_count")?,
907 to_i32(col_count, "col_count")?,
908 to_i32(nonzero_count, "nonzero_count")?,
909 csr_values.as_ptr().cast(),
910 csr_row_offsets.as_ptr() as _,
911 csr_column_indices.as_ptr() as _,
912 csc_values.as_mut_ptr().cast(),
913 csc_column_offsets.as_mut_ptr(),
914 csc_row_indices.as_mut_ptr(),
915 T::data_type().into(),
916 action.into(),
917 index_base.into(),
918 algorithm.into(),
919 external_buffer.as_mut_ptr().cast(),
920 ))?;
921 }
922 Ok(())
923}
924
925pub fn sparse_to_dense(
967 ctx: &Context,
968 matrix_a: &SparseMatrixDescriptor,
969 matrix_b: &mut DenseMatrixDescriptor,
970 algorithm: SparseToDenseAlgorithm,
971 external_buffer: Option<DevicePtr>,
972) -> Result<()> {
973 ctx.bind()?;
974 unsafe {
975 try_ffi!(sys::cusparseSparseToDense(
976 ctx.as_raw(),
977 matrix_a.as_raw_const(),
978 matrix_b.as_raw(),
979 algorithm.into(),
980 external_buffer.unwrap_or(DevicePtr::null()).as_ptr() as _,
981 ))?;
982 }
983 Ok(())
984}
985
986pub fn dense_to_sparse_buffer_size(
987 ctx: &Context,
988 matrix_a: &DenseMatrixDescriptor,
989 matrix_b: &mut SparseMatrixDescriptor,
990 algorithm: DenseToSparseAlgorithm,
991) -> Result<usize> {
992 ctx.bind()?;
993 let mut size = 0;
994 unsafe {
995 try_ffi!(sys::cusparseDenseToSparse_bufferSize(
996 ctx.as_raw(),
997 matrix_a.as_raw_const(),
998 matrix_b.as_raw(),
999 algorithm.into(),
1000 &raw mut size,
1001 ))?;
1002 }
1003 to_usize(size, "dense-to-sparse buffer size")
1004}
1005
1006pub fn dense_to_sparse_analysis(
1007 ctx: &Context,
1008 matrix_a: &DenseMatrixDescriptor,
1009 matrix_b: &mut SparseMatrixDescriptor,
1010 algorithm: DenseToSparseAlgorithm,
1011 external_buffer: Option<DevicePtr>,
1012) -> Result<()> {
1013 ctx.bind()?;
1014 unsafe {
1015 try_ffi!(sys::cusparseDenseToSparse_analysis(
1016 ctx.as_raw(),
1017 matrix_a.as_raw_const(),
1018 matrix_b.as_raw(),
1019 algorithm.into(),
1020 external_buffer.unwrap_or(DevicePtr::null()).as_ptr() as _,
1021 ))?;
1022 }
1023 Ok(())
1024}
1025
1026pub fn dense_to_sparse_convert(
1027 ctx: &Context,
1028 matrix_a: &DenseMatrixDescriptor,
1029 matrix_b: &mut SparseMatrixDescriptor,
1030 algorithm: DenseToSparseAlgorithm,
1031 external_buffer: Option<DevicePtr>,
1032) -> Result<()> {
1033 ctx.bind()?;
1034 unsafe {
1035 try_ffi!(sys::cusparseDenseToSparse_convert(
1036 ctx.as_raw(),
1037 matrix_a.as_raw_const(),
1038 matrix_b.as_raw(),
1039 algorithm.into(),
1040 external_buffer.unwrap_or(DevicePtr::null()).as_ptr() as _,
1041 ))?;
1042 }
1043 Ok(())
1044}
1045
1046pub fn csr_to_csc_buffer_size<T: DataTypeLike>(
1047 ctx: &Context,
1048 row_count: usize,
1049 col_count: usize,
1050 nonzero_count: usize,
1051 csr_values: &DeviceMemory<T>,
1052 csr_row_offsets: &DeviceMemory<i32>,
1053 csr_column_indices: &DeviceMemory<i32>,
1054 csc_values: &mut DeviceMemory<T>,
1055 csc_column_offsets: &mut DeviceMemory<i32>,
1056 csc_row_indices: &mut DeviceMemory<i32>,
1057 action: crate::types::Action,
1058 index_base: IndexBase,
1059 algorithm: CsrToCscAlgorithm,
1060) -> Result<usize> {
1061 ctx.bind()?;
1062 let mut size = 0;
1063 unsafe {
1064 try_ffi!(sys::cusparseCsr2cscEx2_bufferSize(
1065 ctx.as_raw(),
1066 to_i32(row_count, "row_count")?,
1067 to_i32(col_count, "col_count")?,
1068 to_i32(nonzero_count, "nonzero_count")?,
1069 csr_values.as_ptr().cast(),
1070 csr_row_offsets.as_ptr() as _,
1071 csr_column_indices.as_ptr() as _,
1072 csc_values.as_mut_ptr().cast(),
1073 csc_column_offsets.as_mut_ptr(),
1074 csc_row_indices.as_mut_ptr(),
1075 T::data_type().into(),
1076 action.into(),
1077 index_base.into(),
1078 algorithm.into(),
1079 &raw mut size,
1080 ))?;
1081 }
1082 to_usize(size, "csr-to-csc buffer size")
1083}
1084
1085pub fn csr_to_coo(
1093 ctx: &Context,
1094 csr_row_offsets: &DeviceMemory<i32>,
1095 nonzero_count: usize,
1096 row_count: usize,
1097 coo_row_indices: &mut DeviceMemory<i32>,
1098 index_base: IndexBase,
1099) -> Result<()> {
1100 ctx.bind()?;
1101 if csr_row_offsets.len() < row_count.saturating_add(1) || coo_row_indices.len() < nonzero_count
1102 {
1103 return Err(Error::OutOfRange {
1104 name: "csr/coo buffer length".into(),
1105 });
1106 }
1107 unsafe {
1108 try_ffi!(sys::cusparseXcsr2coo(
1109 ctx.as_raw(),
1110 csr_row_offsets.as_ptr() as _,
1111 to_i32(nonzero_count, "nonzero_count")?,
1112 to_i32(row_count, "row_count")?,
1113 coo_row_indices.as_mut_ptr(),
1114 index_base.into(),
1115 ))?;
1116 }
1117 Ok(())
1118}
1119
1120pub fn sparse_to_dense_buffer_size(
1121 ctx: &Context,
1122 matrix_a: &SparseMatrixDescriptor,
1123 matrix_b: &mut DenseMatrixDescriptor,
1124 algorithm: SparseToDenseAlgorithm,
1125) -> Result<usize> {
1126 ctx.bind()?;
1127 let mut size = 0;
1128 unsafe {
1129 try_ffi!(sys::cusparseSparseToDense_bufferSize(
1130 ctx.as_raw(),
1131 matrix_a.as_raw_const(),
1132 matrix_b.as_raw(),
1133 algorithm.into(),
1134 &raw mut size,
1135 ))?;
1136 }
1137 to_usize(size, "sparse-to-dense buffer size")
1138}
1139
1140pub fn coo_to_csr(
1148 ctx: &Context,
1149 coo_row_indices: &DeviceMemory<i32>,
1150 row_count: usize,
1151 csr_row_offsets: &mut DeviceMemory<i32>,
1152 index_base: IndexBase,
1153) -> Result<()> {
1154 ctx.bind()?;
1155 let nonzero_count = coo_row_indices.len();
1156 if csr_row_offsets.len() < row_count.saturating_add(1) {
1157 return Err(Error::OutOfRange {
1158 name: "csr_row_offsets length".into(),
1159 });
1160 }
1161 unsafe {
1162 try_ffi!(sys::cusparseXcoo2csr(
1163 ctx.as_raw(),
1164 coo_row_indices.as_ptr() as _,
1165 to_i32(nonzero_count, "nonzero_count")?,
1166 to_i32(row_count, "row_count")?,
1167 csr_row_offsets.as_mut_ptr(),
1168 index_base.into(),
1169 ))?;
1170 }
1171 Ok(())
1172}