Repository: dmlc/dgl
Pull request: [Sparse]Fix device check 
## Description
Add the device check for sparse operator. When user call the function and the device of input matrix is not the same as input tensor, raise an error.

Resolve #6393.

## Checklist
Please feel free to remove inapplicable items for your PR.
- [ ] The PR title starts with [$CATEGORY] (such as [NN], [Model], [Doc], [Feature]])
- [ ] I've leverage the [tools](https://docs.google.com/document/d/1iHyj7zlmygKSk5gBPsqIqL5ASPzJSPREaNT_QdsiYA4/edit) to beautify the python and c++ code.
- [ ] The PR is complete and small, read the [Google eng practice (CL equals to PR)](https://google.github.io/eng-practices/review/developer/small-cls.html) to understand more about small PR. In DGL, we consider PRs with less than 200 lines of core code change are small (example, test and documentation could be exempted).
- [ ] All changes have test coverage
- [ ] Code is well-documented
- [ ] To the best of my knowledge, examples are either not affected by this change, or have been fixed to be compatible with this change
- [ ] Related issue is referred in this PR
- [ ] If the PR is for a new model/paper, I've updated the example index [here](../examples/README.md).

## Changes


Problem statement:
[Bug]DGL sparse run error message is incomplete
## 🐛 Bug

<!-- A clear and concise description of what the bug is. -->
DGL sparse run error message is incomplete, make it hard to debug for user.

## To Reproduce

In DGL sparse, the op like bsddmm needs all inputs are on the same device, howerver, if inputs are not on the same device, it won't report "they are not on the same device" but report Segmentation fault, it is hard to debug for user.

Steps to reproduce the behavior:

```
>>> import torch
>>> import dgl.sparse as dglsp
>>> indices = torch.tensor([[1, 1, 2], [2, 3, 3]])
>>> val = torch.arange(1, 4).float()
>>> A = dglsp.spmatrix(indices, val, (3, 4))
>>> X1 = torch.arange(0, 3 * 5 * 2).view(3, 5, 2).float() 
>>> X2 = torch.arange(0, 5 * 4 * 2).view(5, 4, 2).float()
>>> X1 = X1.to("cuda:0")
>>> X2 = X2.to("cuda:0")
>>> dglsp.bsddmm(A, X1, X2) // A is still on the CPU
Segmentation fault (core dumped)
```

<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->

## Expected behavior

<!-- A clear and concise description of what you expected to happen. -->
Should we add the input device check for the DGL sparse operator?

Hints from issue discussion:

Commit message: add device check in c

Patch to review:
diff --git a/dgl_sparse/src/sddmm.cc b/dgl_sparse/src/sddmm.cc
index b32f1640de45..810583e01a99 100644
--- a/dgl_sparse/src/sddmm.cc
+++ b/dgl_sparse/src/sddmm.cc
@@ -61,8 +61,9 @@ void _SDDMMSanityCheck(
       mat1.dtype() == mat2.dtype(),
       "SDDMM: the two dense matrices should have the same dtype.");
   TORCH_CHECK(
-      mat1.device() == mat2.device(),
-      "SDDMM: the two dense matrices should on the same device.");
+      mat1.device() == mat2.device() && sparse_mat->device() == mat2.device(),
+      "SDDMM: the two dense matrices and sparse matrix should on the same "
+      "device.");
 }
 
 torch::Tensor SDDMMAutoGrad::forward(
diff --git a/python/dgl/sparse/matmul.py b/python/dgl/sparse/matmul.py
index b933339bcd0d..a664eed0649b 100644
--- a/python/dgl/sparse/matmul.py
+++ b/python/dgl/sparse/matmul.py
@@ -123,7 +123,6 @@ def spspmm(A: SparseMatrix, B: SparseMatrix) -> SparseMatrix:
     assert isinstance(
         B, SparseMatrix
     ), f"Expect A2 to be a SparseMatrix object, got {type(B)}."
-
     return SparseMatrix(
         torch.ops.dgl_sparse.spspmm(A.c_sparse_matrix, B.c_sparse_matrix)
     )


Code review comments:
diff_hunk: @@ -123,7 +123,6 @@ def spspmm(A: SparseMatrix, B: SparseMatrix) -> SparseMatrix:
     assert isinstance(
         B, SparseMatrix
     ), f"Expect A2 to be a SparseMatrix object, got {type(B)}."
-
path: python/dgl/sparse/matmul.py
text: @user1:
Remove this change.