Repository: dmlc/dgl

Issue:
[Sparse] Support SparseMatrix transposition
## 🔨Work Item

**IMPORTANT:**
* This template is only for dev team to track project progress. For feature request or bug report, please use the corresponding issue templates.
* DO NOT create a new work item if the purpose is to fix an existing issue or feature request. We will directly use the issue in the project tracker.

Project tracker: https://github.com/orgs/dmlc/projects/2

## Description

<!-- short description of the work item -->

## Depending work items or issues

<!-- what must be done before this -->



Discussion:

Resolving patch:
diff --git a/python/dgl/mock_sparse2/sparse_matrix.py b/python/dgl/mock_sparse2/sparse_matrix.py
--- a/python/dgl/mock_sparse2/sparse_matrix.py
+++ b/python/dgl/mock_sparse2/sparse_matrix.py
@@ -149,6 +149,39 @@ def dense(self) -> torch.Tensor:
         mat[row, col] = val
         return mat
 
+    def t(self):
+        """Alias of :meth:`transpose()`"""
+        return self.transpose()
+
+    @property
+    def T(self):  # pylint: disable=C0103
+        """Alias of :meth:`transpose()`"""
+        return self.transpose()
+
+    def transpose(self):
+        """Return the transpose of this sparse matrix.
+
+        Returns
+        -------
+        SparseMatrix
+            The transpose of this sparse matrix.
+
+        Example
+        -------
+
+        >>> row = torch.tensor([1, 1, 3])
+        >>> col = torch.tensor([2, 1, 3])
+        >>> val = torch.tensor([1, 1, 2])
+        >>> A = create_from_coo(row, col, val)
+        >>> A = A.transpose()
+        >>> print(A)
+        SparseMatrix(indices=tensor([[2, 1, 3],
+                [1, 1, 3]]),
+        values=tensor([1, 1, 2]),
+        shape=(4, 4), nnz=3)
+        """
+        return SparseMatrix(self.c_sparse_matrix.transpose())
+
 
 def create_from_coo(
     row: torch.Tensor,


Test patch:
diff --git a/tests/pytorch/mock_sparse2/test_diag.py b/tests/pytorch/mock_sparse2/test_diag.py
--- a/tests/pytorch/mock_sparse2/test_diag.py
+++ b/tests/pytorch/mock_sparse2/test_diag.py
@@ -4,7 +4,7 @@
 
 from dgl.mock_sparse2 import diag, identity, DiagMatrix
 
-# FIXME: Skipping tests on win.
+# FIXME(issue #4818): Skipping tests on win.
 if not sys.platform.startswith("linux"):
     pytest.skip("skipping tests on win", allow_module_level=True)
 
diff --git a/tests/pytorch/mock_sparse2/test_elementwise_op_diag.py b/tests/pytorch/mock_sparse2/test_elementwise_op_diag.py
--- a/tests/pytorch/mock_sparse2/test_elementwise_op_diag.py
+++ b/tests/pytorch/mock_sparse2/test_elementwise_op_diag.py
@@ -4,9 +4,9 @@
 import pytest
 import torch
 import sys
-from dgl.mock_sparse import diag
+from dgl.mock_sparse2 import diag
 
-# FIXME: Skipping tests on win.
+# FIXME(issue #4818): Skipping tests on win.
 if not sys.platform.startswith("linux"):
     pytest.skip("skipping tests on win", allow_module_level=True)
 
diff --git a/tests/pytorch/mock_sparse2/test_elementwise_op_sp.py b/tests/pytorch/mock_sparse2/test_elementwise_op_sp.py
--- a/tests/pytorch/mock_sparse2/test_elementwise_op_sp.py
+++ b/tests/pytorch/mock_sparse2/test_elementwise_op_sp.py
@@ -7,7 +7,7 @@
 import dgl
 from dgl.mock_sparse2 import create_from_coo, diag
 
-# FIXME: Skipping tests on win.
+# FIXME(issue #4818): Skipping tests on win.
 if not sys.platform.startswith("linux"):
     pytest.skip("skipping tests on win", allow_module_level=True)
 
diff --git a/tests/pytorch/mock_sparse2/test_sparse_matrix.py b/tests/pytorch/mock_sparse2/test_sparse_matrix.py
--- a/tests/pytorch/mock_sparse2/test_sparse_matrix.py
+++ b/tests/pytorch/mock_sparse2/test_sparse_matrix.py
@@ -6,7 +6,7 @@
 
 from dgl.mock_sparse2 import create_from_coo, create_from_csr, create_from_csc
 
-# FIXME: Skipping tests on win.
+# FIXME(issue #4818): Skipping tests on win.
 if not sys.platform.startswith("linux"):
     pytest.skip("skipping tests on win", allow_module_level=True)
 
diff --git a/tests/pytorch/mock_sparse2/test_transpose.py b/tests/pytorch/mock_sparse2/test_transpose.py
new file mode 100644
--- /dev/null
+++ b/tests/pytorch/mock_sparse2/test_transpose.py
@@ -0,0 +1,46 @@
+import pytest
+import torch
+import sys
+
+from dgl.mock_sparse2 import diag, create_from_coo
+
+import backend as F
+
+# FIXME(issue #4818): Skipping tests on win.
+if not sys.platform.startswith("linux"):
+    pytest.skip("skipping tests on win", allow_module_level=True)
+
+@pytest.mark.parametrize("val_shape", [(3,), (3, 2)])
+@pytest.mark.parametrize("mat_shape", [None, (3, 5), (5, 3)])
+def test_diag_matrix_transpose(val_shape, mat_shape):
+    ctx = F.ctx()
+    val = torch.randn(val_shape).to(ctx)
+    mat = diag(val, mat_shape).transpose()
+
+    assert torch.allclose(mat.val, val)
+    if mat_shape is None:
+        mat_shape = (val_shape[0], val_shape[0])
+    assert mat.shape == mat_shape[::-1]
+
+
+@pytest.mark.parametrize("dense_dim", [None, 2])
+@pytest.mark.parametrize("row", [[0, 0, 1, 2], (0, 1, 2, 4)])
+@pytest.mark.parametrize("col", [(0, 1, 2, 2), (1, 3, 3, 4)])
+@pytest.mark.parametrize("extra_shape", [(0, 1), (2, 1)])
+def test_sparse_matrix_transpose(dense_dim, row, col, extra_shape):
+    mat_shape = (max(row) + 1 + extra_shape[0], max(col) + 1 + extra_shape[1])
+    val_shape = (len(row),)
+    if dense_dim is not None:
+        val_shape += (dense_dim,)
+    ctx = F.ctx()
+    val = torch.randn(val_shape).to(ctx)
+    row = torch.tensor(row).to(ctx)
+    col = torch.tensor(col).to(ctx)
+    mat = create_from_coo(row, col, val, mat_shape).transpose()
+    mat_row, mat_col = mat.coo()
+    mat_val = mat.val
+
+    assert mat.shape == mat_shape[::-1]
+    assert torch.allclose(mat_val, val)
+    assert torch.allclose(mat_row, col)
+    assert torch.allclose(mat_col, row)
\ No newline at end of file