Repository: scipy/scipy

Issue:
Wrong output format for empty sparse results of kron
<!-- 
Thank you for taking the time to file a bug report. 
Please fill in the fields below, deleting the sections that 
don't apply to your issue. You can view the final output
by clicking the preview button above.
Note: This is a comment, and won't appear in the output.
-->

My issue is about the default behaviour of the Kronecker product: If the input matrices have nnz == 0, the output defaults to the output format "coo" even if I explicitly ask for a format like 'csr'. I would add a ".asformat(format)" in line 333 of construct.py (and potentially also in lines 319/ 325) or add additional documentation if that behaviour is intended.



#### Reproducing code example:
<!-- 
If you place your code between the triple backticks below, 
it will be rendered as a code block. 
-->

```
# Sample code to reproduce the problem
import scipy.sparse as sp
type(sp.kron(sp.csr_matrix((3,4)), sp.csr_matrix((2,1)), format='csr')) # -> should be csr but is coo
```

#### 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>
  ...
```

#### Scipy/Numpy/Python version information:
<!-- You can simply run the following and paste the result in a code block
```
import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info)
```
--> 1.5.0/1.18.5/3.8.3 # but I don't think that matters



Discussion:
Thanks for the report. I can confirm that we're not respecting the given format here: 
https://github.com/scipy/scipy/blob/2a1dc2ae8d2c944209f3053d1285dbe5edaff6cc/scipy/sparse/construct.py#L333

Would you like to open a Pull Request with the changes? In addition to the small code change, it would be nice to have a test case that checks if we respect the format argument.

Resolving patch:
diff --git a/scipy/sparse/construct.py b/scipy/sparse/construct.py
--- a/scipy/sparse/construct.py
+++ b/scipy/sparse/construct.py
@@ -316,7 +316,7 @@ def kron(A, B, format=None):
 
         if A.nnz == 0 or B.nnz == 0:
             # kronecker product is the zero matrix
-            return coo_matrix(output_shape)
+            return coo_matrix(output_shape).asformat(format)
 
         B = B.toarray()
         data = A.data.repeat(B.size).reshape(-1,B.shape[0],B.shape[1])
@@ -330,7 +330,7 @@ def kron(A, B, format=None):
 
         if A.nnz == 0 or B.nnz == 0:
             # kronecker product is the zero matrix
-            return coo_matrix(output_shape)
+            return coo_matrix(output_shape).asformat(format)
 
         # expand entries of a into blocks
         row = A.row.repeat(B.nnz)


Test patch:
diff --git a/scipy/sparse/tests/test_construct.py b/scipy/sparse/tests/test_construct.py
--- a/scipy/sparse/tests/test_construct.py
+++ b/scipy/sparse/tests/test_construct.py
@@ -274,9 +274,11 @@ def test_kron(self):
 
         for a in cases:
             for b in cases:
-                result = construct.kron(csr_matrix(a),csr_matrix(b)).todense()
-                expected = np.kron(a,b)
-                assert_array_equal(result,expected)
+                expected = np.kron(a, b)
+                for fmt in sparse_formats:
+                    result = construct.kron(csr_matrix(a), csr_matrix(b), format=fmt) 
+                    assert_equal(result.format, fmt)
+                    assert_array_equal(result.todense(), expected)
 
     def test_kron_large(self):
         n = 2**16