Skip to content

Commit a875fa3

Browse files
dschultj-bowhayjjerphan
authored
BUG: fix pow method for sparrays with power zero (scipy#19335)
* fix pow method for sparrays with power 0 A**0 means every entry is 1, not just the originally non-zero entries. So, the A**x function changes the nonzero structure to dense in a discontinuous fashion near x=0. There is a question then as to whether this method should return a sparse array with all entries 1, or return a dense array, or raise an exception with a workaround described. This PR implements raising an exception for `n` a zero valued scalar. The message (and doc_string description of `n`) says if they want to compute A**x for x==0, they should special case that value to use `np.ones(A.shape, dtype=A.dtype)` * Update scipy/sparse/tests/test_array_api.py Co-authored-by: Jake Bowhay <[email protected]> * change from ValueError to NotImplementedError and update test * Thanks for these suggestions:) Co-authored-by: Julien Jerphanion <[email protected]> * fix error message --------- Co-authored-by: Jake Bowhay <[email protected]> Co-authored-by: Julien Jerphanion <[email protected]>
1 parent fd735fd commit a875fa3

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

scipy/sparse/_data.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,25 @@ def power(self, n, dtype=None):
107107
108108
Parameters
109109
----------
110-
n : n is a scalar
110+
n : scalar
111+
n is a non-zero scalar (nonzero avoids dense ones creation)
112+
If zero power is desired, special case it to use `np.ones`
111113
112114
dtype : If dtype is not specified, the current dtype will be preserved.
115+
116+
Raises
117+
------
118+
NotImplementedError : if n is a zero scalar
119+
If zero power is desired, special case it to use
120+
`np.ones(A.shape, dtype=A.dtype)`
113121
"""
114122
if not isscalarlike(n):
115123
raise NotImplementedError("input is not scalar")
124+
if not n:
125+
raise NotImplementedError(
126+
"zero power is not supported as it would densify the matrix.\n"
127+
"Use `np.ones(A.shape, dtype=A.dtype)` for this case."
128+
)
116129

117130
data = self._deduped_data()
118131
if dtype is not None:

scipy/sparse/tests/test_array_api.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,16 @@ def test_matmul(A):
140140
assert np.all((A @ A.T).todense() == A.dot(A.T).todense())
141141

142142

143-
@parametrize_square_sparrays
144-
def test_pow(B):
145-
assert isinstance((B**0), scipy.sparse.sparray), "Expected array, got matrix"
146-
assert isinstance((B**2), scipy.sparse.sparray), "Expected array, got matrix"
143+
@parametrize_sparrays
144+
def test_power_operator(A):
145+
assert isinstance((A**2), scipy.sparse.sparray), "Expected array, got matrix"
146+
147+
# https://github.com/scipy/scipy/issues/15948
148+
npt.assert_equal((A**2).todense(), (A.todense())**2)
149+
150+
# power of zero is all ones (dense) so helpful msg exception
151+
with pytest.raises(NotImplementedError, match="zero power"):
152+
A**0
147153

148154

149155
@parametrize_sparrays
@@ -354,12 +360,6 @@ def test_spilu():
354360
)
355361

356362

357-
@parametrize_sparrays
358-
def test_power_operator(A):
359-
# https://github.com/scipy/scipy/issues/15948
360-
npt.assert_equal((A**2).todense(), (A.todense())**2)
361-
362-
363363
@pytest.mark.parametrize(
364364
"cls,indices_attrs",
365365
[

0 commit comments

Comments
 (0)