Repository: scipy/scipy

Issue:
Define __round__ for sparse matrices
<!-- 
Thank you for taking the time to report a SciPy issue.
Please describe the issue in detail, and for bug reports
fill in the fields below. You can delete the sections that 
don't apply to your issue. You can view the final output
by clicking the preview button above.
-->

My issue is about using ``assertAlmostEqual`` with sparse matrices. [``assertAlmostEqual``](https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertAlmostEqual) requires the types being compared to implement [``__round__``](https://docs.python.org/3/library/functions.html#round). Defining this, possibly by calling [``numpy.round``](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.round_.html) on the ``data`` attribute, following [this thread](https://stackoverflow.com/questions/51476588/how-do-round-off-the-elements-of-scipy-sparse-csr-matrix-to-2-decimal-places), would be useful.

### Reproducing code example:
<!-- 
If you place your code between the triple backticks below, 
it will be marked as a code block automatically 
-->


```python
from scipy.sparse import csr_matrix

a = csr_matrix((3, 4))

round(a)
```

### Error message:
<!-- If any, paste the *full* error message inside a code block
as above (starting from line Traceback)
-->

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type csr_matrix doesn't define __round__ method
```

### Scipy/Numpy/Python version information:
```
import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info)

1.1.0 1.14.3 sys.version_info(major=3, minor=6, micro=5, releaselevel='final', s
erial=0)
```



Discussion:
Seems like a good feature to add. It would look very similar to the existing `__abs__` implementation: https://github.com/scipy/scipy/blob/f992ba979227044fbd11da648d339c8026de91a1/scipy/sparse/data.py#L37

Resolving patch:
diff --git a/scipy/sparse/base.py b/scipy/sparse/base.py
--- a/scipy/sparse/base.py
+++ b/scipy/sparse/base.py
@@ -387,6 +387,9 @@ def __ge__(self, other):
     def __abs__(self):
         return abs(self.tocsr())
 
+    def __round__(self, ndigits=0):
+        return round(self.tocsr(), ndigits=ndigits)
+
     def _add_sparse(self, other):
         return self.tocsr()._add_sparse(other)
 
diff --git a/scipy/sparse/data.py b/scipy/sparse/data.py
--- a/scipy/sparse/data.py
+++ b/scipy/sparse/data.py
@@ -37,6 +37,9 @@ def _deduped_data(self):
     def __abs__(self):
         return self._with_data(abs(self._deduped_data()))
 
+    def __round__(self, ndigits=0):
+        return self._with_data(np.around(self._deduped_data(), decimals=ndigits))
+
     def _real(self):
         return self._with_data(self.data.real)
 


Test patch:
diff --git a/scipy/sparse/tests/test_base.py b/scipy/sparse/tests/test_base.py
--- a/scipy/sparse/tests/test_base.py
+++ b/scipy/sparse/tests/test_base.py
@@ -658,6 +658,12 @@ def test_abs(self):
         A = matrix([[-1, 0, 17],[0, -5, 0],[1, -4, 0],[0,0,0]],'d')
         assert_equal(abs(A),abs(self.spmatrix(A)).todense())
 
+    def test_round(self):
+        decimal = 1
+        A = matrix([[-1.35, 0.56], [17.25, -5.98]], 'd')
+        assert_equal(np.around(A, decimals=decimal),
+                     round(self.spmatrix(A), ndigits=decimal).todense())
+
     def test_elementwise_power(self):
         A = matrix([[-4, -3, -2],[-1, 0, 1],[2, 3, 4]], 'd')
         assert_equal(np.power(A, 2), self.spmatrix(A).power(2).todense())