scipy 1.15.2__cp313-cp313t-macosx_12_0_arm64.whl → 1.15.3__cp313-cp313t-macosx_12_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scipy/__config__.py +6 -6
- scipy/_lib/_array_api.py +11 -0
- scipy/_lib/_ccallback_c.cpython-313t-darwin.so +0 -0
- scipy/_lib/_test_ccallback.cpython-313t-darwin.so +0 -0
- scipy/_lib/_test_deprecation_call.cpython-313t-darwin.so +0 -0
- scipy/_lib/_test_deprecation_def.cpython-313t-darwin.so +0 -0
- scipy/_lib/messagestream.cpython-313t-darwin.so +0 -0
- scipy/_lib/tests/test_array_api.py +5 -1
- scipy/cluster/_hierarchy.cpython-313t-darwin.so +0 -0
- scipy/cluster/_optimal_leaf_ordering.cpython-313t-darwin.so +0 -0
- scipy/cluster/_vq.cpython-313t-darwin.so +0 -0
- scipy/fftpack/convolve.cpython-313t-darwin.so +0 -0
- scipy/integrate/_dop.cpython-313t-darwin.so +0 -0
- scipy/integrate/_ivp/common.py +3 -3
- scipy/integrate/_ivp/ivp.py +9 -2
- scipy/integrate/_ivp/tests/test_ivp.py +19 -0
- scipy/integrate/_lsoda.cpython-313t-darwin.so +0 -0
- scipy/integrate/_odepack.cpython-313t-darwin.so +0 -0
- scipy/integrate/_quadpack.cpython-313t-darwin.so +0 -0
- scipy/integrate/_tanhsinh.py +14 -12
- scipy/integrate/_test_odeint_banded.cpython-313t-darwin.so +0 -0
- scipy/integrate/_vode.cpython-313t-darwin.so +0 -0
- scipy/integrate/tests/test_tanhsinh.py +10 -0
- scipy/interpolate/_bspl.cpython-313t-darwin.so +0 -0
- scipy/interpolate/_dfitpack.cpython-313t-darwin.so +0 -0
- scipy/interpolate/_dierckx.cpython-313t-darwin.so +0 -0
- scipy/interpolate/_interpnd.cpython-313t-darwin.so +0 -0
- scipy/interpolate/_ppoly.cpython-313t-darwin.so +0 -0
- scipy/interpolate/_rgi_cython.cpython-313t-darwin.so +0 -0
- scipy/io/_test_fortran.cpython-313t-darwin.so +0 -0
- scipy/io/matlab/_mio5_utils.cpython-313t-darwin.so +0 -0
- scipy/io/matlab/_mio_utils.cpython-313t-darwin.so +0 -0
- scipy/io/matlab/_streams.cpython-313t-darwin.so +0 -0
- scipy/linalg/_cythonized_array_utils.cpython-313t-darwin.so +0 -0
- scipy/linalg/_decomp_interpolative.cpython-313t-darwin.so +0 -0
- scipy/linalg/_decomp_lu_cython.cpython-313t-darwin.so +0 -0
- scipy/linalg/_decomp_update.cpython-313t-darwin.so +0 -0
- scipy/linalg/_fblas.cpython-313t-darwin.so +0 -0
- scipy/linalg/_flapack.cpython-313t-darwin.so +0 -0
- scipy/linalg/_matfuncs_expm.cpython-313t-darwin.so +0 -0
- scipy/linalg/_matfuncs_sqrtm_triu.cpython-313t-darwin.so +0 -0
- scipy/linalg/_solve_toeplitz.cpython-313t-darwin.so +0 -0
- scipy/linalg/cython_blas.cpython-313t-darwin.so +0 -0
- scipy/linalg/cython_lapack.cpython-313t-darwin.so +0 -0
- scipy/linalg/tests/test_interpolative.py +17 -0
- scipy/ndimage/_cytest.cpython-313t-darwin.so +0 -0
- scipy/ndimage/_nd_image.cpython-313t-darwin.so +0 -0
- scipy/ndimage/_ndimage_api.py +2 -1
- scipy/ndimage/_ni_label.cpython-313t-darwin.so +0 -0
- scipy/ndimage/_rank_filter_1d.cpython-313t-darwin.so +0 -0
- scipy/ndimage/tests/test_filters.py +14 -0
- scipy/odr/__odrpack.cpython-313t-darwin.so +0 -0
- scipy/optimize/_bglu_dense.cpython-313t-darwin.so +0 -0
- scipy/optimize/_bracket.py +35 -8
- scipy/optimize/_cobyla.cpython-313t-darwin.so +0 -0
- scipy/optimize/_cython_nnls.cpython-313t-darwin.so +0 -0
- scipy/optimize/_highspy/_highs_wrapper.py +6 -4
- scipy/optimize/_lbfgsb.cpython-313t-darwin.so +0 -0
- scipy/optimize/_linprog_highs.py +9 -9
- scipy/optimize/_linprog_util.py +4 -3
- scipy/optimize/_lsq/givens_elimination.cpython-313t-darwin.so +0 -0
- scipy/optimize/_minpack.cpython-313t-darwin.so +0 -0
- scipy/optimize/_moduleTNC.cpython-313t-darwin.so +0 -0
- scipy/optimize/_slsqp.cpython-313t-darwin.so +0 -0
- scipy/optimize/_trlib/_trlib.cpython-313t-darwin.so +0 -0
- scipy/optimize/cython_optimize/_zeros.cpython-313t-darwin.so +0 -0
- scipy/optimize/tests/test_bracket.py +35 -0
- scipy/signal/_peak_finding_utils.cpython-313t-darwin.so +0 -0
- scipy/signal/_short_time_fft.py +34 -6
- scipy/signal/_signaltools.py +4 -1
- scipy/signal/_sosfilt.cpython-313t-darwin.so +0 -0
- scipy/signal/_upfirdn_apply.cpython-313t-darwin.so +0 -0
- scipy/signal/tests/_scipy_spectral_test_shim.py +3 -11
- scipy/signal/tests/test_short_time_fft.py +10 -2
- scipy/signal/tests/test_signaltools.py +5 -0
- scipy/sparse/_base.py +2 -15
- scipy/sparse/_compressed.py +0 -3
- scipy/sparse/_csparsetools.cpython-313t-darwin.so +0 -0
- scipy/sparse/_dia.py +0 -3
- scipy/sparse/csgraph/_flow.cpython-313t-darwin.so +0 -0
- scipy/sparse/csgraph/_matching.cpython-313t-darwin.so +0 -0
- scipy/sparse/csgraph/_min_spanning_tree.cpython-313t-darwin.so +0 -0
- scipy/sparse/csgraph/_reordering.cpython-313t-darwin.so +0 -0
- scipy/sparse/csgraph/_shortest_path.cpython-313t-darwin.so +0 -0
- scipy/sparse/csgraph/_tools.cpython-313t-darwin.so +0 -0
- scipy/sparse/csgraph/_traversal.cpython-313t-darwin.so +0 -0
- scipy/sparse/linalg/_dsolve/_superlu.cpython-313t-darwin.so +0 -0
- scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-313t-darwin.so +0 -0
- scipy/sparse/linalg/_eigen/arpack/arpack.py +5 -3
- scipy/sparse/linalg/_expm_multiply.py +8 -3
- scipy/sparse/linalg/_interface.py +12 -8
- scipy/sparse/linalg/_isolve/_gcrotmk.py +2 -1
- scipy/sparse/linalg/_propack/_cpropack.cpython-313t-darwin.so +0 -0
- scipy/sparse/linalg/_propack/_dpropack.cpython-313t-darwin.so +0 -0
- scipy/sparse/linalg/_propack/_spropack.cpython-313t-darwin.so +0 -0
- scipy/sparse/linalg/_propack/_zpropack.cpython-313t-darwin.so +0 -0
- scipy/sparse/linalg/tests/test_expm_multiply.py +10 -0
- scipy/sparse/linalg/tests/test_interface.py +35 -0
- scipy/sparse/linalg/tests/test_pydata_sparse.py +4 -0
- scipy/sparse/tests/test_base.py +12 -0
- scipy/sparse/tests/test_common1d.py +11 -6
- scipy/spatial/_ckdtree.cpython-313t-darwin.so +0 -0
- scipy/spatial/_hausdorff.cpython-313t-darwin.so +0 -0
- scipy/spatial/_qhull.cpython-313t-darwin.so +0 -0
- scipy/spatial/_voronoi.cpython-313t-darwin.so +0 -0
- scipy/spatial/tests/test_qhull.py +99 -0
- scipy/spatial/transform/_rotation.cpython-313t-darwin.so +0 -0
- scipy/spatial/transform/tests/test_rotation.py +181 -10
- scipy/special/_comb.cpython-313t-darwin.so +0 -0
- scipy/special/_ellip_harm_2.cpython-313t-darwin.so +0 -0
- scipy/special/_logsumexp.py +21 -16
- scipy/special/_specfun.cpython-313t-darwin.so +0 -0
- scipy/special/_special_ufuncs.cpython-313t-darwin.so +0 -0
- scipy/special/_test_internal.cpython-313t-darwin.so +0 -0
- scipy/special/_ufuncs.cpython-313t-darwin.so +0 -0
- scipy/special/_ufuncs_cxx.cpython-313t-darwin.so +0 -0
- scipy/special/cython_special.cpython-313t-darwin.so +0 -0
- scipy/special/tests/test_hyp2f1.py +21 -0
- scipy/special/tests/test_logsumexp.py +14 -0
- scipy/special/xsf/hyp2f1.h +3 -3
- scipy/stats/_ansari_swilk_statistics.cpython-313t-darwin.so +0 -0
- scipy/stats/_biasedurn.cpython-313t-darwin.so +0 -0
- scipy/stats/_continuous_distns.py +25 -15
- scipy/stats/_levy_stable/levyst.cpython-313t-darwin.so +0 -0
- scipy/stats/_mvn.cpython-313t-darwin.so +0 -0
- scipy/stats/_qmc_cy.cpython-313t-darwin.so +0 -0
- scipy/stats/_rcont/rcont.cpython-313t-darwin.so +0 -0
- scipy/stats/_sobol.cpython-313t-darwin.so +0 -0
- scipy/stats/_stats.cpython-313t-darwin.so +0 -0
- scipy/stats/_unuran/unuran_wrapper.cpython-313t-darwin.so +0 -0
- scipy/stats/tests/test_distributions.py +22 -0
- scipy/version.py +2 -2
- {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/METADATA +2 -2
- {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/RECORD +136 -136
- {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/LICENSE.txt +0 -0
- {scipy-1.15.2.dist-info → scipy-1.15.3.dist-info}/WHEEL +0 -0
scipy/signal/_short_time_fft.py
CHANGED
@@ -206,14 +206,14 @@ class ShortTimeFFT:
|
|
206
206
|
|
207
207
|
It is possible to calculate the SFT of signal parts:
|
208
208
|
|
209
|
-
>>>
|
210
|
-
>>> Sx0 = SFT.stft(x[:
|
211
|
-
>>> Sx1 = SFT.stft(x[
|
209
|
+
>>> N2 = SFT.nearest_k_p(N // 2)
|
210
|
+
>>> Sx0 = SFT.stft(x[:N2])
|
211
|
+
>>> Sx1 = SFT.stft(x[N2:])
|
212
212
|
|
213
213
|
When assembling sequential STFT parts together, the overlap needs to be
|
214
214
|
considered:
|
215
215
|
|
216
|
-
>>> p0_ub = SFT.upper_border_begin(
|
216
|
+
>>> p0_ub = SFT.upper_border_begin(N2)[1] - SFT.p_min
|
217
217
|
>>> p1_le = SFT.lower_border_end[1] - SFT.p_min
|
218
218
|
>>> Sx01 = np.hstack((Sx0[:, :p0_ub],
|
219
219
|
... Sx0[:, p0_ub:] + Sx1[:, :p1_le],
|
@@ -1226,7 +1226,15 @@ class ShortTimeFFT:
|
|
1226
1226
|
|
1227
1227
|
@lru_cache(maxsize=256)
|
1228
1228
|
def _post_padding(self, n: int) -> tuple[int, int]:
|
1229
|
-
"""Largest signal index and slice index due to padding.
|
1229
|
+
"""Largest signal index and slice index due to padding.
|
1230
|
+
|
1231
|
+
Parameters
|
1232
|
+
----------
|
1233
|
+
n : int
|
1234
|
+
Number of samples of input signal (must be ≥ half of the window length).
|
1235
|
+
"""
|
1236
|
+
if not (n >= (m2p := self.m_num - self.m_num_mid)):
|
1237
|
+
raise ValueError(f"Parameter n must be >= ceil(m_num/2) = {m2p}!")
|
1230
1238
|
w2 = self.win.real**2 + self.win.imag**2
|
1231
1239
|
# move window to the right until the overlap for t < t[n] vanishes:
|
1232
1240
|
q1 = n // self.hop # last slice index with t[p1] <= t[n]
|
@@ -1247,6 +1255,11 @@ class ShortTimeFFT:
|
|
1247
1255
|
A detailed example is provided in the :ref:`tutorial_stft_sliding_win`
|
1248
1256
|
section of the :ref:`user_guide`.
|
1249
1257
|
|
1258
|
+
Parameters
|
1259
|
+
----------
|
1260
|
+
n : int
|
1261
|
+
Number of samples of input signal (must be ≥ half of the window length).
|
1262
|
+
|
1250
1263
|
See Also
|
1251
1264
|
--------
|
1252
1265
|
k_min: The smallest possible signal index.
|
@@ -1348,6 +1361,19 @@ class ShortTimeFFT:
|
|
1348
1361
|
A detailed example is given :ref:`tutorial_stft_sliding_win` section
|
1349
1362
|
of the :ref:`user_guide`.
|
1350
1363
|
|
1364
|
+
Parameters
|
1365
|
+
----------
|
1366
|
+
n : int
|
1367
|
+
Number of samples of input signal (must be ≥ half of the window length).
|
1368
|
+
|
1369
|
+
Returns
|
1370
|
+
-------
|
1371
|
+
k_ub : int
|
1372
|
+
Lowest signal index, where a touching time slice sticks out past the
|
1373
|
+
signal end.
|
1374
|
+
p_ub : int
|
1375
|
+
Lowest index of time slice of which the end sticks out past the signal end.
|
1376
|
+
|
1351
1377
|
See Also
|
1352
1378
|
--------
|
1353
1379
|
k_min: The smallest possible signal index.
|
@@ -1359,13 +1385,15 @@ class ShortTimeFFT:
|
|
1359
1385
|
p_range: Determine and validate slice index range.
|
1360
1386
|
ShortTimeFFT: Class this method belongs to.
|
1361
1387
|
"""
|
1388
|
+
if not (n >= (m2p := self.m_num - self.m_num_mid)):
|
1389
|
+
raise ValueError(f"Parameter n must be >= ceil(m_num/2) = {m2p}!")
|
1362
1390
|
w2 = self.win.real**2 + self.win.imag**2
|
1363
1391
|
q2 = n // self.hop + 1 # first t[q] >= t[n]
|
1364
1392
|
q1 = max((n-self.m_num) // self.hop - 1, -1)
|
1365
1393
|
# move window left until does not stick out to the right:
|
1366
1394
|
for q_ in range(q2, q1, -1):
|
1367
1395
|
k_ = q_ * self.hop + (self.m_num - self.m_num_mid)
|
1368
|
-
if k_
|
1396
|
+
if k_ <= n or all(w2[n-k_:] == 0):
|
1369
1397
|
return (q_ + 1) * self.hop - self.m_num_mid, q_ + 1
|
1370
1398
|
return 0, 0 # border starts at first slice
|
1371
1399
|
|
scipy/signal/_signaltools.py
CHANGED
@@ -3703,7 +3703,10 @@ def resample_poly(x, up, down, axis=0, window=('kaiser', 5.0),
|
|
3703
3703
|
max_rate = max(up, down)
|
3704
3704
|
f_c = 1. / max_rate # cutoff of FIR filter (rel. to Nyquist)
|
3705
3705
|
half_len = 10 * max_rate # reasonable cutoff for sinc-like function
|
3706
|
-
if np.issubdtype(x.dtype, np.
|
3706
|
+
if np.issubdtype(x.dtype, np.complexfloating):
|
3707
|
+
h = firwin(2 * half_len + 1, f_c,
|
3708
|
+
window=window).astype(x.dtype) # match dtype of x
|
3709
|
+
elif np.issubdtype(x.dtype, np.floating):
|
3707
3710
|
h = firwin(2 * half_len + 1, f_c,
|
3708
3711
|
window=window).astype(x.dtype) # match dtype of x
|
3709
3712
|
else:
|
Binary file
|
Binary file
|
@@ -103,7 +103,7 @@ def _stft_wrapper(x, fs=1.0, window='hann', nperseg=256, noverlap=None,
|
|
103
103
|
# This is an edge case where shortTimeFFT returns one more time slice
|
104
104
|
# than the Scipy stft() shorten to remove last time slice:
|
105
105
|
if n % 2 == 1 and nperseg % 2 == 1 and noverlap % 2 == 1:
|
106
|
-
x = x[..., :
|
106
|
+
x = x[..., : -1]
|
107
107
|
|
108
108
|
nadd = (-(x.shape[-1]-nperseg) % nstep) % nperseg
|
109
109
|
zeros_shape = list(x.shape[:-1]) + [nadd]
|
@@ -124,11 +124,8 @@ def _stft_wrapper(x, fs=1.0, window='hann', nperseg=256, noverlap=None,
|
|
124
124
|
k_off = nperseg // 2
|
125
125
|
p0 = 0 # ST.lower_border_end[1] + 1
|
126
126
|
nn = x.shape[axis] if padded else n+k_off+1
|
127
|
-
|
128
|
-
|
129
|
-
# This is bad hack to pass the test test_roundtrip_boundary_extension():
|
130
|
-
if padded is True and nperseg - noverlap == 1:
|
131
|
-
p1 -= nperseg // 2 - 1 # the reasoning behind this is not clear to me
|
127
|
+
# number of frames akin to legacy stft computation
|
128
|
+
p1 = (x.shape[axis] - nperseg) // nstep + 1
|
132
129
|
|
133
130
|
detr = None if detrend is False else detrend
|
134
131
|
Sxx = ST.stft_detrend(x, detr, p0, p1, k_offset=k_off, axis=axis)
|
@@ -136,11 +133,6 @@ def _stft_wrapper(x, fs=1.0, window='hann', nperseg=256, noverlap=None,
|
|
136
133
|
if x.dtype in (np.float32, np.complex64):
|
137
134
|
Sxx = Sxx.astype(np.complex64)
|
138
135
|
|
139
|
-
# workaround for test_average_all_segments() - seems to be buggy behavior:
|
140
|
-
if boundary is None and padded is False:
|
141
|
-
t, Sxx = t[1:-1], Sxx[..., :-2]
|
142
|
-
t -= k_off / fs
|
143
|
-
|
144
136
|
return ST.f, t, Sxx
|
145
137
|
|
146
138
|
|
@@ -332,7 +332,11 @@ def test_border_values():
|
|
332
332
|
assert SFT.p_max(10) == 4
|
333
333
|
assert SFT.k_max(10) == 16
|
334
334
|
assert SFT.upper_border_begin(10) == (4, 2)
|
335
|
-
|
335
|
+
# Raise exceptions:
|
336
|
+
with pytest.raises(ValueError, match="^Parameter n must be"):
|
337
|
+
SFT.upper_border_begin(3)
|
338
|
+
with pytest.raises(ValueError, match="^Parameter n must be"):
|
339
|
+
SFT._post_padding(3)
|
336
340
|
|
337
341
|
def test_border_values_exotic():
|
338
342
|
"""Ensure that the border calculations are correct for windows with
|
@@ -342,7 +346,11 @@ def test_border_values_exotic():
|
|
342
346
|
assert SFT.lower_border_end == (0, 0)
|
343
347
|
|
344
348
|
SFT = ShortTimeFFT(np.flip(w), hop=20, fs=1)
|
345
|
-
assert SFT.upper_border_begin(4) == (
|
349
|
+
assert SFT.upper_border_begin(4) == (16, 1)
|
350
|
+
assert SFT.upper_border_begin(5) == (16, 1)
|
351
|
+
assert SFT.upper_border_begin(23) == (36, 2)
|
352
|
+
assert SFT.upper_border_begin(24) == (36, 2)
|
353
|
+
assert SFT.upper_border_begin(25) == (36, 2)
|
346
354
|
|
347
355
|
SFT._hop = -1 # provoke unreachable line
|
348
356
|
with pytest.raises(RuntimeError):
|
@@ -3926,3 +3926,8 @@ class TestUniqueRoots:
|
|
3926
3926
|
unique, multiplicity = unique_roots(p, 2)
|
3927
3927
|
assert_almost_equal(unique, [np.min(p)], decimal=15)
|
3928
3928
|
assert_equal(multiplicity, [100])
|
3929
|
+
|
3930
|
+
|
3931
|
+
def test_gh_22684():
|
3932
|
+
actual = signal.resample_poly(np.arange(2000, dtype=np.complex64), 6, 4)
|
3933
|
+
assert actual.dtype == np.complex64
|
scipy/sparse/_base.py
CHANGED
@@ -1141,13 +1141,8 @@ class _spbase:
|
|
1141
1141
|
if self.ndim == 1:
|
1142
1142
|
if axis not in (None, -1, 0):
|
1143
1143
|
raise ValueError("axis must be None, -1 or 0")
|
1144
|
-
|
1145
|
-
|
1146
|
-
if out is not None:
|
1147
|
-
if any(dim != 1 for dim in out.shape):
|
1148
|
-
raise ValueError("dimensions do not match")
|
1149
|
-
out[...] = ret
|
1150
|
-
return ret
|
1144
|
+
res = self @ np.ones(self.shape, dtype=res_dtype)
|
1145
|
+
return res.sum(dtype=dtype, out=out)
|
1151
1146
|
|
1152
1147
|
# We use multiplication by a matrix of ones to achieve this.
|
1153
1148
|
# For some sparse array formats more efficient methods are
|
@@ -1175,14 +1170,6 @@ class _spbase:
|
|
1175
1170
|
np.ones((N, 1), dtype=res_dtype)
|
1176
1171
|
)
|
1177
1172
|
|
1178
|
-
if out is not None:
|
1179
|
-
if isinstance(self, sparray):
|
1180
|
-
ret_shape = ret.shape[:axis] + ret.shape[axis + 1:]
|
1181
|
-
else:
|
1182
|
-
ret_shape = ret.shape
|
1183
|
-
if out.shape != ret_shape:
|
1184
|
-
raise ValueError("dimensions do not match")
|
1185
|
-
|
1186
1173
|
return ret.sum(axis=axis, dtype=dtype, out=out)
|
1187
1174
|
|
1188
1175
|
def mean(self, axis=None, dtype=None, out=None):
|
scipy/sparse/_compressed.py
CHANGED
@@ -677,9 +677,6 @@ class _cs_matrix(_data_matrix, _minmax_mixin, IndexMixin):
|
|
677
677
|
if axis % 2 == 1:
|
678
678
|
ret = ret.T
|
679
679
|
|
680
|
-
if out is not None and out.shape != ret.shape:
|
681
|
-
raise ValueError('dimensions do not match')
|
682
|
-
|
683
680
|
return ret.sum(axis=(), dtype=dtype, out=out)
|
684
681
|
else:
|
685
682
|
# _spbase handles the situations when axis is in {None, -2, -1, 0, 1}
|
Binary file
|
scipy/sparse/_dia.py
CHANGED
@@ -174,9 +174,6 @@ class _dia_base(_data_matrix):
|
|
174
174
|
|
175
175
|
ret = self._ascontainer(row_sums.sum(axis=axis))
|
176
176
|
|
177
|
-
if out is not None and out.shape != ret.shape:
|
178
|
-
raise ValueError("dimensions do not match")
|
179
|
-
|
180
177
|
return ret.sum(axis=(), dtype=dtype, out=out)
|
181
178
|
|
182
179
|
sum.__doc__ = _spbase.sum.__doc__
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -46,7 +46,6 @@ from scipy.sparse._sputils import (
|
|
46
46
|
from scipy.sparse.linalg import gmres, splu
|
47
47
|
from scipy._lib._util import _aligned_zeros
|
48
48
|
from scipy._lib._threadsafety import ReentrancyLock
|
49
|
-
|
50
49
|
from . import _arpack
|
51
50
|
arpack_int = _arpack.timing.nbx.dtype
|
52
51
|
|
@@ -277,9 +276,12 @@ class ArpackError(RuntimeError):
|
|
277
276
|
ARPACK error
|
278
277
|
"""
|
279
278
|
|
280
|
-
def __init__(self, info, infodict=
|
279
|
+
def __init__(self, info, infodict=None):
|
280
|
+
if infodict is None:
|
281
|
+
infodict = _NAUPD_ERRORS
|
282
|
+
|
281
283
|
msg = infodict.get(info, "Unknown error")
|
282
|
-
|
284
|
+
super().__init__(f"ARPACK error {info}: {msg}")
|
283
285
|
|
284
286
|
|
285
287
|
class ArpackNoConvergence(ArpackError):
|
@@ -115,7 +115,7 @@ def expm_multiply(A, B, start=None, stop=None, num=None,
|
|
115
115
|
----------
|
116
116
|
A : transposable linear operator
|
117
117
|
The operator whose exponential is of interest.
|
118
|
-
B : ndarray
|
118
|
+
B : ndarray, sparse array
|
119
119
|
The matrix or vector to be multiplied by the matrix exponential of A.
|
120
120
|
start : scalar, optional
|
121
121
|
The starting time point of the sequence.
|
@@ -443,7 +443,7 @@ class LazyOperatorNormInfo:
|
|
443
443
|
|
444
444
|
def d(self, p):
|
445
445
|
"""
|
446
|
-
Lazily estimate :math:`d_p(A) ~= || A^p ||^(1/p)`
|
446
|
+
Lazily estimate :math:`d_p(A) ~= || A^p ||^(1/p)`
|
447
447
|
where :math:`||.||` is the 1-norm.
|
448
448
|
"""
|
449
449
|
if p not in self._d:
|
@@ -702,7 +702,12 @@ def _expm_multiply_interval(A, B, start=None, stop=None, num=None,
|
|
702
702
|
m_star, s = _fragment_3_1(norm_info, n0, tol, ell=ell)
|
703
703
|
|
704
704
|
# Compute the expm action up to the initial time point.
|
705
|
-
|
705
|
+
action_t0 = _expm_multiply_simple_core(A, B, t_0, mu, m_star, s)
|
706
|
+
if scipy.sparse.issparse(action_t0):
|
707
|
+
action_t0 = action_t0.toarray()
|
708
|
+
elif is_pydata_spmatrix(action_t0):
|
709
|
+
action_t0 = action_t0.todense()
|
710
|
+
X[0] = action_t0
|
706
711
|
|
707
712
|
# Compute the expm action at the rest of the time points.
|
708
713
|
if q <= s:
|
@@ -322,6 +322,10 @@ class LinearOperator:
|
|
322
322
|
"""Default implementation of _rmatvec; defers to adjoint."""
|
323
323
|
if type(self)._adjoint == LinearOperator._adjoint:
|
324
324
|
# _adjoint not overridden, prevent infinite recursion
|
325
|
+
if (hasattr(self, "_rmatmat")
|
326
|
+
and type(self)._rmatmat != LinearOperator._rmatmat):
|
327
|
+
# Try to use _rmatmat as a fallback
|
328
|
+
return self._rmatmat(x.reshape(-1, 1)).reshape(-1)
|
325
329
|
raise NotImplementedError
|
326
330
|
else:
|
327
331
|
return self.H.matvec(x)
|
@@ -822,22 +826,22 @@ class MatrixLinearOperator(LinearOperator):
|
|
822
826
|
|
823
827
|
def _adjoint(self):
|
824
828
|
if self.__adj is None:
|
825
|
-
self.__adj = _AdjointMatrixOperator(self)
|
829
|
+
self.__adj = _AdjointMatrixOperator(self.A)
|
826
830
|
return self.__adj
|
827
831
|
|
832
|
+
|
828
833
|
class _AdjointMatrixOperator(MatrixLinearOperator):
|
829
|
-
def __init__(self,
|
830
|
-
self.A =
|
831
|
-
self.
|
832
|
-
self.
|
833
|
-
self.shape = adjoint.shape[1], adjoint.shape[0]
|
834
|
+
def __init__(self, adjoint_array):
|
835
|
+
self.A = adjoint_array.T.conj()
|
836
|
+
self.args = (adjoint_array,)
|
837
|
+
self.shape = adjoint_array.shape[1], adjoint_array.shape[0]
|
834
838
|
|
835
839
|
@property
|
836
840
|
def dtype(self):
|
837
|
-
return self.
|
841
|
+
return self.args[0].dtype
|
838
842
|
|
839
843
|
def _adjoint(self):
|
840
|
-
return self.
|
844
|
+
return MatrixLinearOperator(self.args[0])
|
841
845
|
|
842
846
|
|
843
847
|
class IdentityOperator(LinearOperator):
|
@@ -433,7 +433,8 @@ def gcrotmk(A, b, x0=None, *, rtol=1e-5, atol=0., maxiter=1000, M=None, callback
|
|
433
433
|
ux = axpy(u, ux, ux.shape[0], -byc) # ux -= u*byc
|
434
434
|
|
435
435
|
# cx := V H y
|
436
|
-
|
436
|
+
with np.errstate(invalid="ignore"):
|
437
|
+
hy = Q.dot(R.dot(y))
|
437
438
|
cx = vs[0] * hy[0]
|
438
439
|
for v, hyc in zip(vs[1:], hy[1:]):
|
439
440
|
cx = axpy(v, cx, cx.shape[0], hyc) # cx += v*hyc
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -7,6 +7,7 @@ import pytest
|
|
7
7
|
from numpy.testing import (assert_allclose, assert_, assert_equal,
|
8
8
|
suppress_warnings)
|
9
9
|
from scipy.sparse import SparseEfficiencyWarning
|
10
|
+
import scipy.sparse
|
10
11
|
from scipy.sparse.linalg import aslinearoperator
|
11
12
|
import scipy.linalg
|
12
13
|
from scipy.sparse.linalg import expm as sp_expm
|
@@ -260,19 +261,28 @@ class TestExpmActionInterval:
|
|
260
261
|
A = scipy.sparse.diags_array(np.arange(5),format='csr', dtype=int)
|
261
262
|
B = np.ones(5, dtype=int)
|
262
263
|
Aexpm = scipy.sparse.diags_array(np.exp(np.arange(5)),format='csr')
|
264
|
+
BI = np.identity(5, dtype=int)
|
265
|
+
BI_sparse = scipy.sparse.csr_array(BI)
|
263
266
|
assert_allclose(expm_multiply(A,B,0,1)[-1], Aexpm.dot(B))
|
267
|
+
assert_allclose(np.diag(expm_multiply(A, BI_sparse, 0, 1)[-1]), Aexpm.dot(B))
|
264
268
|
|
265
269
|
# Test A complex, B int
|
266
270
|
A = scipy.sparse.diags_array(-1j*np.arange(5),format='csr', dtype=complex)
|
267
271
|
B = np.ones(5, dtype=int)
|
268
272
|
Aexpm = scipy.sparse.diags_array(np.exp(-1j*np.arange(5)),format='csr')
|
269
273
|
assert_allclose(expm_multiply(A,B,0,1)[-1], Aexpm.dot(B))
|
274
|
+
assert_allclose(np.diag(expm_multiply(A, BI_sparse, 0, 1)[-1]), Aexpm.dot(B))
|
270
275
|
|
271
276
|
# Test A int, B complex
|
272
277
|
A = scipy.sparse.diags_array(np.arange(5),format='csr', dtype=int)
|
273
278
|
B = np.full(5, 1j, dtype=complex)
|
274
279
|
Aexpm = scipy.sparse.diags_array(np.exp(np.arange(5)),format='csr')
|
275
280
|
assert_allclose(expm_multiply(A,B,0,1)[-1], Aexpm.dot(B))
|
281
|
+
BI = np.identity(5, dtype=complex)*1j
|
282
|
+
assert_allclose(
|
283
|
+
np.diag(expm_multiply(A, scipy.sparse.csr_array(BI), 0, 1)[-1]),
|
284
|
+
Aexpm.dot(B)
|
285
|
+
)
|
276
286
|
|
277
287
|
def test_expm_multiply_interval_status_0(self):
|
278
288
|
self._help_test_specific_expm_interval_status(0)
|
@@ -13,6 +13,7 @@ import scipy.sparse as sparse
|
|
13
13
|
|
14
14
|
import scipy.sparse.linalg._interface as interface
|
15
15
|
from scipy.sparse._sputils import matrix
|
16
|
+
from scipy._lib._gcutils import assert_deallocated, IS_PYPY
|
16
17
|
|
17
18
|
|
18
19
|
class TestLinearOperator:
|
@@ -512,6 +513,30 @@ def test_transpose_noconjugate():
|
|
512
513
|
assert_equal(B.dot(v), Y.dot(v))
|
513
514
|
assert_equal(B.T.dot(v), Y.T.dot(v))
|
514
515
|
|
516
|
+
def test_transpose_multiplication():
|
517
|
+
class MyMatrix(interface.LinearOperator):
|
518
|
+
def __init__(self, A):
|
519
|
+
super().__init__(A.dtype, A.shape)
|
520
|
+
self.A = A
|
521
|
+
def _matmat(self, other): return self.A @ other
|
522
|
+
def _rmatmat(self, other): return self.A.T @ other
|
523
|
+
|
524
|
+
A = MyMatrix(np.array([[1, 2], [3, 4]]))
|
525
|
+
X = np.array([1, 2])
|
526
|
+
B = np.array([[10, 20], [30, 40]])
|
527
|
+
X2 = X.reshape(-1, 1)
|
528
|
+
Y = np.array([[1, 2], [3, 4]])
|
529
|
+
|
530
|
+
assert_equal(A @ B, Y @ B)
|
531
|
+
assert_equal(B.T @ A, B.T @ Y)
|
532
|
+
assert_equal(A.T @ B, Y.T @ B)
|
533
|
+
assert_equal(A @ X, Y @ X)
|
534
|
+
assert_equal(X.T @ A, X.T @ Y)
|
535
|
+
assert_equal(A.T @ X, Y.T @ X)
|
536
|
+
assert_equal(A @ X2, Y @ X2)
|
537
|
+
assert_equal(X2.T @ A, X2.T @ Y)
|
538
|
+
assert_equal(A.T @ X2, Y.T @ X2)
|
539
|
+
|
515
540
|
def test_sparse_matmat_exception():
|
516
541
|
A = interface.LinearOperator((2, 2), matvec=lambda x: x)
|
517
542
|
B = sparse.eye_array(2)
|
@@ -524,3 +549,13 @@ def test_sparse_matmat_exception():
|
|
524
549
|
A @ np.identity(4)
|
525
550
|
with assert_raises(ValueError):
|
526
551
|
np.identity(4) @ A
|
552
|
+
|
553
|
+
|
554
|
+
@pytest.mark.skipif(IS_PYPY, reason="Test not meaningful on PyPy")
|
555
|
+
def test_MatrixLinearOperator_refcycle():
|
556
|
+
# gh-10634
|
557
|
+
# Test that MatrixLinearOperator can be automatically garbage collected
|
558
|
+
A = np.eye(2)
|
559
|
+
with assert_deallocated(interface.MatrixLinearOperator, A) as op:
|
560
|
+
op.adjoint()
|
561
|
+
del op
|
@@ -239,6 +239,10 @@ def test_expm_multiply(matrices):
|
|
239
239
|
x = splin.expm_multiply(A_sparse, b)
|
240
240
|
assert_allclose(x, x0)
|
241
241
|
|
242
|
+
x0 = splin.expm_multiply(A_dense, A_dense)
|
243
|
+
x = splin.expm_multiply(A_sparse, A_sparse)
|
244
|
+
assert_allclose(x.todense(), x0)
|
245
|
+
|
242
246
|
|
243
247
|
def test_eq(same_matrix):
|
244
248
|
sp_sparse, pd_sparse = same_matrix
|
scipy/sparse/tests/test_base.py
CHANGED
@@ -1087,6 +1087,12 @@ class _TestCommon:
|
|
1087
1087
|
datsp.sum(axis=1, out=datsp_out)
|
1088
1088
|
assert_array_almost_equal(dat_out, datsp_out)
|
1089
1089
|
|
1090
|
+
# check that wrong shape out parameter raises
|
1091
|
+
with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
|
1092
|
+
datsp.sum(out=array([0]))
|
1093
|
+
with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
|
1094
|
+
datsp.sum(out=array([[0]] if self.is_array_test else 0))
|
1095
|
+
|
1090
1096
|
def test_numpy_sum(self):
|
1091
1097
|
# See gh-5987
|
1092
1098
|
dat = array([[0, 1, 2],
|
@@ -1184,6 +1190,12 @@ class _TestCommon:
|
|
1184
1190
|
datsp.mean(axis=1, out=datsp_out)
|
1185
1191
|
assert_array_almost_equal(dat_out, datsp_out)
|
1186
1192
|
|
1193
|
+
# check that wrong shape out parameter raises
|
1194
|
+
with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
|
1195
|
+
datsp.mean(out=array([0]))
|
1196
|
+
with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
|
1197
|
+
datsp.mean(out=array([[0]] if self.is_array_test else 0))
|
1198
|
+
|
1187
1199
|
def test_numpy_mean(self):
|
1188
1200
|
# See gh-5987
|
1189
1201
|
dat = array([[0, 1, 2],
|
@@ -142,7 +142,7 @@ class TestCommon1D:
|
|
142
142
|
datsp.sum(axis=(0, 1))
|
143
143
|
with pytest.raises(TypeError, match='axis must be an integer'):
|
144
144
|
datsp.sum(axis=1.5)
|
145
|
-
with pytest.raises(ValueError, match='
|
145
|
+
with pytest.raises(ValueError, match='output parameter.*wrong.*dimension'):
|
146
146
|
datsp.sum(axis=0, out=out)
|
147
147
|
|
148
148
|
def test_numpy_sum(self, spcreator):
|
@@ -180,7 +180,7 @@ class TestCommon1D:
|
|
180
180
|
datsp.mean(axis=(0, 1))
|
181
181
|
with pytest.raises(TypeError, match='axis must be an integer'):
|
182
182
|
datsp.mean(axis=1.5)
|
183
|
-
with pytest.raises(ValueError, match='
|
183
|
+
with pytest.raises(ValueError, match='output parameter.*wrong.*dimension'):
|
184
184
|
datsp.mean(axis=1, out=out)
|
185
185
|
|
186
186
|
def test_sum_dtype(self, spcreator):
|
@@ -209,17 +209,22 @@ class TestCommon1D:
|
|
209
209
|
dat = np.array([0, 1, 2])
|
210
210
|
datsp = spcreator(dat)
|
211
211
|
|
212
|
-
dat_out = np.array(
|
213
|
-
datsp_out = np.array(
|
212
|
+
dat_out = np.array(0)
|
213
|
+
datsp_out = np.array(0)
|
214
214
|
|
215
|
-
dat.mean(out=dat_out
|
215
|
+
dat.mean(out=dat_out)
|
216
216
|
datsp.mean(out=datsp_out)
|
217
217
|
assert_allclose(dat_out, datsp_out)
|
218
218
|
|
219
|
-
dat.mean(axis=0, out=dat_out
|
219
|
+
dat.mean(axis=0, out=dat_out)
|
220
220
|
datsp.mean(axis=0, out=datsp_out)
|
221
221
|
assert_allclose(dat_out, datsp_out)
|
222
222
|
|
223
|
+
with pytest.raises(ValueError, match="output parameter.*dimension"):
|
224
|
+
datsp.mean(out=np.array([0]))
|
225
|
+
with pytest.raises(ValueError, match="output parameter.*dimension"):
|
226
|
+
datsp.mean(out=np.array([[0]]))
|
227
|
+
|
223
228
|
def test_numpy_mean(self, spcreator):
|
224
229
|
dat = np.array([0, 1, 2])
|
225
230
|
datsp = spcreator(dat)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|