Repository: scipy/scipy

Issue:
BUG: scipy.sparse.linalg.norm does not work on sparse arrays
### Describe your issue.

Greetings.
As from the document of sparse matrices : https://docs.scipy.org/doc/scipy/reference/sparse.html,
both "Sparse array classes" and "Sparse matrix classes" belong to sparse matrices.

Also, from the document of sparse.linalg.norm, the input array arr is only mentioned as sparse matrix, 
so I expect that norm function should work on both sparse array classes and sparse matrix classes.

However, norm does not work on sparse array classes, and the error message is shown below.
I think the main reason of this is that: Since the intermediate output M in: https://github.com/scipy/scipy/blob/main/scipy/sparse/linalg/_norm.py#L180
returns numpy.ndarray rather than numpy.matrix, and numpy.ndarray does not have attribute A.

Since sparse array classes will pass issparse(), maybe we should add another assert for this if norm only supports sparse matrix classes.

Thank you.

### Reproducing Code Example

```python
import numpy as np
from scipy.sparse import coo_array
from scipy.sparse import linalg
row  = np.array([0, 0, 1, 1])
col  = np.array([0, 1, 2, 3])
data = np.array([4, 5, 7, 9])
test_arr = coo_array((data, (row, col)), shape=(2, 4))
linalg.norm(test_arr, ord=1, axis=0)
```


### Error message

```shell
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [73], in <cell line: 8>()
      6 data = np.array([4, 5, 7, 9])
      7 test_arr = coo_array((data, (row, col)), shape=(2, 4))
----> 8 linalg.norm(test_arr, ord=1, axis=0)

File ~/.local/lib/python3.9/site-packages/scipy/sparse/linalg/_norm.py:180, in norm(x, ord, axis)
    178             raise ValueError('Invalid norm order for vectors.') from e
    179         M = np.power(abs(x).power(ord).sum(axis=a), 1 / ord)
--> 180     return M.A.ravel()
    181 else:
    182     raise ValueError("Improper number of dimensions to norm.")

AttributeError: 'numpy.ndarray' object has no attribute 'A'
```


### SciPy/NumPy/Python version information

1.8.0 1.22.3 sys.version_info(major=3, minor=9, micro=10, releaselevel='final', serial=0)


Discussion:

Resolving patch:
diff --git a/scipy/sparse/linalg/_norm.py b/scipy/sparse/linalg/_norm.py
--- a/scipy/sparse/linalg/_norm.py
+++ b/scipy/sparse/linalg/_norm.py
@@ -177,6 +177,11 @@ def norm(x, ord=None, axis=None):
             except TypeError as e:
                 raise ValueError('Invalid norm order for vectors.') from e
             M = np.power(abs(x).power(ord).sum(axis=a), 1 / ord)
-        return M.A.ravel()
+        if hasattr(M, 'toarray'):
+            return M.toarray().ravel()
+        elif hasattr(M, 'A'):
+            return M.A.ravel()
+        else:
+            return M.ravel()
     else:
         raise ValueError("Improper number of dimensions to norm.")


Test patch:
diff --git a/scipy/sparse/linalg/tests/test_norm.py b/scipy/sparse/linalg/tests/test_norm.py
--- a/scipy/sparse/linalg/tests/test_norm.py
+++ b/scipy/sparse/linalg/tests/test_norm.py
@@ -3,13 +3,26 @@
 
 import numpy as np
 from numpy.linalg import norm as npnorm
-from numpy.testing import assert_allclose
+from numpy.testing import assert_allclose, assert_equal
 from pytest import raises as assert_raises
 
 import scipy.sparse
 from scipy.sparse.linalg import norm as spnorm
 
 
+# https://github.com/scipy/scipy/issues/16031
+def test_sparray_norm():
+    row = np.array([0, 0, 1, 1])
+    col = np.array([0, 1, 2, 3])
+    data = np.array([4, 5, 7, 9])
+    test_arr = scipy.sparse.coo_array((data, (row, col)), shape=(2, 4))
+    test_mat = scipy.sparse.coo_matrix((data, (row, col)), shape=(2, 4))
+    assert_equal(spnorm(test_arr, ord=1, axis=0), np.array([4, 5, 7, 9]))
+    assert_equal(spnorm(test_mat, ord=1, axis=0), np.array([4, 5, 7, 9]))
+    assert_equal(spnorm(test_arr, ord=1, axis=1), np.array([9, 16]))
+    assert_equal(spnorm(test_mat, ord=1, axis=1), np.array([9, 16]))
+
+
 class TestNorm:
     def setup_method(self):
         a = np.arange(9) - 4