Intel® oneAPI Math Kernel Library
Ask questions and share information with other developers who use Intel® Math Kernel Library.

migrating cursparseDense2Sparse()

sycl-developer
New Contributor I
673 Views

What are the oneMKL functions for migrating the cusparseDense2Sparse() functions ?  Thanks.

 

https://docs.nvidia.com/cuda/cusparse/index.html

0 Kudos
5 Replies
ShanmukhS_Intel
Moderator
634 Views

Hi Zheming Jin,


Thanks for posting in Intel Communities.

Based on your query, you would like to get information on MKL routine which converts a dense matrix into a sparse matrix in CSR, CSC, etc. formats. Could you please correct us if there is any difference in our understanding?


Best Regards,

Shanmukh.SS


0 Kudos
sycl-developer
New Contributor I
629 Views
0 Kudos
Spencer_P_Intel
Employee
622 Views

There is currently (as of oneMKL 2023.2) no function that converts dense to sparse or sparse to dense in oneMKL.  It is however something we will consider adding in some future release as conversion routines are convenient for many, including those who are not as familiar with sparse data structures.  Sparse to dense is very straight forward, but dense to sparse is not as simple.  As such, I will provide a rough outline here (dense -> CSR) for those who might want to implement such a function themselves

A basic breakdown with a pseudo code algorithm (for dense -> CSR with 0 base indexing) is as follows:

 

typedef int int_type;
typedef double data_type;

// Step 1.
// setup a rule to govern whether you consider a value 0 or not, for
// instance this lambda function to return true/false for isNonzero
const data_type TOL = 1e-14;
auto isNonzero = [=](data_type value){ return std::abs(value) < TOL ? false : true; };

// Step 2.
// allocate rowptr as int_type of nrows+1 and fill it with
// count of nonzeros on each row (offset by one for prefix sum
// in next step)
int_type *rowptr = malloc( (nrows+1) * sizeof(int_type) );

for (int_type row = 0; row < nrows; ++row) {
  int_type row_count = 0;
  for (int_type col = 0; col < ncols; ++col) {
    if (isNonzero(denseMat[row][col]) ) {
      row_count++;
    }
  }
  rowptr[row+1] = row_count;
}

// Step 3
// perform a prefix_sum on rowptr values to get total count of nnz
// and offsets ptr for each row, allocate colind and values arrays
rowptr[0] = 0;
for (int_type row = 0; row < nrows; ++row) {
  rowptr[row+1] += rowptr[row];
}

const int_type nnz = rowptr[nrows];
int_type *colind = malloc(nnz * sizeof(int_type));
data_type *values = malloc(nnz * sizeof(data_type));

// Step 4:
// fill the colind/values arrays
for (int_type row = 0; row < nrows; ++row) {
  int_type row_offset = rowptr[row];
  for (int_type col = 0; col < ncols; ++col) {
    if (isNonzero(denseMat[row][col]) ) {
        colind[row_offset] = col;
        values[row_offset] = denseMat[row][col];
        row_offset++;
    }
  }
}

That should give you the CSR format with { nrows, ncols, nnz, rowptr, colind, values }

 

Of course much of this can be done in parallel with OpenMP or with SYCL language... and you should probably add some safety checks that mallocs succeed or nnz > 0, but I think you get the point etc. 

 

Spencer

0 Kudos
sycl-developer
New Contributor I
571 Views

Thank you for considering adding it in the future release. 

0 Kudos
ShanmukhS_Intel
Moderator
540 Views

Hi,

 

Thanks for helping us improve our products! We’ve submitted the feature request to the dev team Once it is included in an upcoming release, it would be documented in the release notes.

 

Best Regards,

Shanmukh.SS

 

0 Kudos
Reply