Hello,
I am finding very strange results from mkl_sparse_spmm()
My code looks like below.
The strange thing is:
1. if I pass the routine a "small" pair of sparse matrices (A[m x k] dot B[k x n], m = 40,000, k = 1000, n = 40,000, sparsity is ~ 99% and 65% for B and A, respectively), then the result is correct; by correct, I mean that the diagonal of the resultant sparse matrix has the correct spectrum (known a priori), and element by element comparison to the result from scipy.sparse matrix product is within floating point error
2. however, if I pass it a larger pair of matrices (m ~ 70k, n ~ 70k, similar sparsity) then the result is strange; notably, "number of 0 elements" printed in the code is almost as large as the total number of elements returned (i.e., rows_e[n-1] - nzero ~ few 10k out of O(100M) total), which means that mkl_sparse_spmm is reporting a large number of non-zero elements that are actually set to zero in the output array; the diagonal elements are all crazy, and comparison to scipy.sparse matrix product is waaaay off
Are there any guesses what I might be doing wrong? Here are my compiler settings (gcc v6.3):
CFLAGS = -march=native -m64 -fPIC -O3 -fopenmp -DMKL_ILP64
LDFLAGS = -pthread -L$(EXTERN)/usr/lib -lgomp -lboost_python -lboost_numpy -lpython$(PYVERS) \
-L/opt/intel/compilers_and_libraries/linux/mkl/lib/intel64 \
-lmkl_intel_ilp64 -lmkl_core -lmkl_def -lmkl_rt -lmkl_gnu_thread
SYSTEM: MKL version is 2019.4.243; system is Intel(R) Xeon(R) CPU E5-2630 v4 dual socket with 64GB RAM, g++ (GCC) 6.3.0 / CENTOS 7
Output on the Python side:
G shape = (1296, 64827)
Range(G) = [3.76e-06, 4.31]
Sparsity of G = 99.721%
Sparsity of G_g[64827 x 1296] = 0.529
Range of G_g = [-0.00227, 0.000266]
>>> p = numeric.mkl.sp_mm_csr(m, k, n, G_g.count_nonzero(), G_g.data, G_g.indptr.astype(int), G_g.indices.astype(int), G.count_nonzero(), G.data, G.indptr.astype(int), G.indices.astype(int))
number of 0 elements: 881856376
>>> Rp = csr_matrix(p(), shape=(m,n))
>>> Rp.count_nonzero()
9134960
>>> R = G_g * G
>>> R.count_nonzero()
890991336
## NOTE: 890991336 - 9134960 = 881856376
Somewhat redacted C++ side code is below (I don't think I have removed anything that is relevant ...).
sp_mm_csr(MKL_INT m, MKL_INT k, MKL_INT n, MKL_INT nnz_a, np::ndarray a_vals, np::ndarray a_rows, np::ndarray a_cols, MKL_INT nnz_b, np::ndarray b_vals, np::ndarray b_rows, np::ndarray b_cols) {
// np::ndarray are boost::python::numpy arrays; omitted code ensures that
// all arrays have correct types (np.int64 and double) and dimensions
mkl_sparse_d_create_csr(
&csr_a, SPARSE_INDEX_BASE_ZERO, m, k,
reinterpret_cast<MKL_INT *>(a_rows.get_data()),
reinterpret_cast<MKL_INT *>(a_rows.get_data()) + 1,
reinterpret_cast<MKL_INT *>(a_cols.get_data()),
reinterpret_cast<sp_mm_csr_res::real_t *>(a_vals.get_data()));
mkl_sparse_d_create_csr(
&csr_b, SPARSE_INDEX_BASE_ZERO, k, n,
reinterpret_cast<MKL_INT *>(b_rows.get_data()),
reinterpret_cast<MKL_INT *>(b_rows.get_data()) + 1,
reinterpret_cast<MKL_INT *>(b_cols.get_data()),
reinterpret_cast<sp_mm_csr_res::real_t *>(b_vals.get_data()));
sparse_matrix_t csr_c = NULL;
auto status =
mkl_sparse_spmm(SPARSE_OPERATION_NON_TRANSPOSE, csr_a, csr_b, &csr_c);
// m_XX variables are all MKL_INT or real_t = double class members
MKL_INT *rows_b;
MKL_INT *rows_e;
mkl_sparse_d_export_csr(csr_c, &m_indexing, &m_nrows, &m_ncols, &rows_b,
&rows_e, &m_mat_cols, &m_mat_vals);
m_nnz = rows_e[m_nrows - 1];
MKL_INT nzero = 0;
for(MKL_INT i=0; i < m_nnz; ++i) {
if ((*(m_mat_vals + i)) == 0) {
nzero += 1;
}
}
std::cout << "number of 0 elements: "<< nzero << std::endl;
// ...
}