scipy 1.16.0rc2__cp311-cp311-musllinux_1_2_aarch64.whl → 1.16.2__cp311-cp311-musllinux_1_2_aarch64.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 +12 -12
- scipy/_cyutility.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/_lib/_ccallback_c.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/_lib/_fpumode.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/_lib/_test_ccallback.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/_lib/_test_deprecation_call.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/_lib/_test_deprecation_def.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/_lib/_uarray/_uarray.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/_lib/_util.py +7 -0
- scipy/_lib/messagestream.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/cluster/_hierarchy.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/cluster/_optimal_leaf_ordering.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/cluster/_vq.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/conftest.py +25 -0
- scipy/fft/_pocketfft/pypocketfft.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/fftpack/convolve.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/integrate/_dop.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/integrate/_lsoda.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/integrate/_odepack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/integrate/_quadpack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/integrate/_test_multivariate.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/integrate/_test_odeint_banded.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/integrate/_vode.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/interpolate/_dfitpack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/interpolate/_dierckx.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/interpolate/_fitpack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/interpolate/_interpnd.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/interpolate/_ppoly.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/interpolate/_rbfinterp_pythran.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/interpolate/_rgi_cython.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/io/_fast_matrix_market/_fmm_core.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/io/_test_fortran.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/io/matlab/_mio5_utils.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/io/matlab/_mio_utils.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/io/matlab/_streams.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/io/matlab/tests/test_streams.py +9 -0
- scipy/linalg/_cythonized_array_utils.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_decomp_interpolative.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_decomp_lu_cython.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_decomp_update.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_fblas.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_flapack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_linalg_pythran.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_matfuncs_expm.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_matfuncs_schur_sqrtm.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_matfuncs_sqrtm_triu.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/_solve_toeplitz.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/blas.py +35 -24
- scipy/linalg/cython_blas.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/cython_lapack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/linalg/tests/test_lapack.py +5 -1
- scipy/linalg/tests/test_matfuncs.py +7 -0
- scipy/ndimage/_ctest.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/ndimage/_cytest.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/ndimage/_filters.py +11 -2
- scipy/ndimage/_nd_image.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/ndimage/_ni_label.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/ndimage/_rank_filter_1d.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/ndimage/tests/test_filters.py +52 -0
- scipy/odr/__odrpack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_bglu_dense.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_direct.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_group_columns.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_highspy/_core.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_highspy/_highs_options.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_lbfgsb.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_lbfgsb_py.py +25 -10
- scipy/optimize/_lsap.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_lsq/givens_elimination.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_lsq/least_squares.py +2 -2
- scipy/optimize/_minimize.py +0 -1
- scipy/optimize/_minpack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_moduleTNC.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_pava_pybind.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_shgo_lib/_complex.py +2 -2
- scipy/optimize/_slsqp_py.py +5 -5
- scipy/optimize/_slsqplib.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_trlib/_trlib.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/_zeros.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/cython_optimize/_zeros.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/optimize/tests/test_optimize.py +12 -3
- scipy/signal/_filter_design.py +13 -1
- scipy/signal/_fir_filter_design.py +1 -1
- scipy/signal/_max_len_seq_inner.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/signal/_peak_finding_utils.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/signal/_polyutils.py +1 -1
- scipy/signal/_short_time_fft.py +74 -33
- scipy/signal/_sigtools.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/signal/_sosfilt.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/signal/_spectral_py.py +2 -2
- scipy/signal/_spline.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/signal/_upfirdn_apply.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/signal/tests/test_filter_design.py +19 -0
- scipy/signal/tests/test_fir_filter_design.py +5 -0
- scipy/signal/tests/test_short_time_fft.py +9 -0
- scipy/signal/tests/test_signaltools.py +9 -3
- scipy/signal/tests/test_spectral.py +39 -1
- scipy/sparse/_base.py +4 -1
- scipy/sparse/_csparsetools.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/_sparsetools.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/csgraph/_flow.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/csgraph/_matching.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/csgraph/_min_spanning_tree.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/csgraph/_reordering.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/csgraph/_shortest_path.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/csgraph/_tools.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/csgraph/_traversal.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/linalg/_dsolve/_superlu.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/linalg/_propack/_cpropack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/linalg/_propack/_dpropack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/linalg/_propack/_spropack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/linalg/_propack/_zpropack.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/sparse/tests/test_base.py +3 -0
- scipy/spatial/_ckdtree.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/spatial/_distance_pybind.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/spatial/_distance_wrap.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/spatial/_hausdorff.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/spatial/_qhull.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/spatial/_voronoi.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/spatial/qhull_src/COPYING_QHULL.txt +39 -0
- scipy/spatial/tests/test_distance.py +5 -4
- scipy/spatial/transform/_rigid_transform.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/spatial/transform/_rotation.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_comb.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_ellip_harm_2.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_gufuncs.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_specfun.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_special_ufuncs.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_test_internal.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_ufuncs.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/_ufuncs_cxx.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/special/cython_special.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_ansari_swilk_statistics.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_biasedurn.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_continuous_distns.py +19 -16
- scipy/stats/_distribution_infrastructure.py +20 -0
- scipy/stats/_levy_stable/levyst.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_qmc_cy.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_qmvnt_cy.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_rcont/rcont.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_resampling.py +1 -1
- scipy/stats/_sobol.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_stats.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_stats_py.py +1 -1
- scipy/stats/_stats_pythran.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/_unuran/unuran_wrapper.cpython-311-aarch64-linux-musl.so +0 -0
- scipy/stats/tests/test_distributions.py +13 -0
- scipy/stats/tests/test_fast_gen_inversion.py +2 -0
- scipy/stats/tests/test_morestats.py +4 -4
- scipy/version.py +2 -2
- {scipy-1.16.0rc2.dist-info → scipy-1.16.2.dist-info}/METADATA +3 -2
- {scipy-1.16.0rc2.dist-info → scipy-1.16.2.dist-info}/RECORD +161 -160
- scipy.libs/{libgcc_s-7393e603-ec6fbefc.so.1 → libgcc_s-2d945d6c-767fb991.so.1} +0 -0
- scipy.libs/{libgcc_s-69c45f16.so.1 → libgcc_s-2d945d6c.so.1} +0 -0
- scipy.libs/libgfortran-67378ab2-e7e7cfab.so.5.0.0 +0 -0
- scipy.libs/{libgfortran-db0b6589.so.5.0.0 → libgfortran-67378ab2.so.5.0.0} +0 -0
- scipy.libs/{libscipy_openblas-3735f320.so → libscipy_openblas-98df47d3.so} +0 -0
- scipy.libs/{libstdc++-1f1a71be.so.6.0.33 → libstdc++-85f2cd6d.so.6.0.33} +0 -0
- scipy.libs/libgfortran-eb933d8e-d975c928.so.5.0.0 +0 -0
- {scipy-1.16.0rc2.dist-info → scipy-1.16.2.dist-info}/LICENSE.txt +0 -0
- {scipy-1.16.0rc2.dist-info → scipy-1.16.2.dist-info}/WHEEL +0 -0
@@ -17,7 +17,7 @@ from .trf import trf
|
|
17
17
|
from .dogbox import dogbox
|
18
18
|
from .common import EPS, in_bounds, make_strictly_feasible
|
19
19
|
|
20
|
-
|
20
|
+
|
21
21
|
from scipy.optimize._optimize import _wrap_callback
|
22
22
|
|
23
23
|
TERMINATION_MESSAGES = {
|
@@ -392,7 +392,7 @@ def least_squares(
|
|
392
392
|
|
393
393
|
* For 'trf' : ``x_scale == 1``
|
394
394
|
* For 'dogbox' : ``x_scale == 1``
|
395
|
-
* For '
|
395
|
+
* For 'lm' : ``x_scale == 'jac'``
|
396
396
|
|
397
397
|
.. versionchanged:: 1.16.0
|
398
398
|
The default keyword value is changed from 1 to None to indicate that
|
scipy/optimize/_minimize.py
CHANGED
@@ -188,7 +188,6 @@ def minimize(fun, x0, args=(), method=None, jac=None, hess=None,
|
|
188
188
|
|
189
189
|
Equality constraint means that the constraint function result is to
|
190
190
|
be zero whereas inequality means that it is to be non-negative.
|
191
|
-
Note that COBYLA only supports inequality constraints.
|
192
191
|
|
193
192
|
tol : float, optional
|
194
193
|
Tolerance for termination. When `tol` is specified, the selected
|
Binary file
|
Binary file
|
Binary file
|
@@ -183,6 +183,7 @@ class Complex:
|
|
183
183
|
self.V = VertexCacheIndex()
|
184
184
|
|
185
185
|
self.V_non_symm = [] # List of non-symmetric vertices
|
186
|
+
self.split_edge = cache(self._split_edge)
|
186
187
|
|
187
188
|
def __call__(self):
|
188
189
|
return self.H
|
@@ -995,8 +996,7 @@ class Complex:
|
|
995
996
|
d_v0v1.connect(d_v1v2)
|
996
997
|
return
|
997
998
|
|
998
|
-
|
999
|
-
def split_edge(self, v1, v2):
|
999
|
+
def _split_edge(self, v1, v2):
|
1000
1000
|
v1 = self.V[v1]
|
1001
1001
|
v2 = self.V[v2]
|
1002
1002
|
# Destroy original edge, if it exists:
|
scipy/optimize/_slsqp_py.py
CHANGED
@@ -234,8 +234,8 @@ def _minimize_slsqp(func, x0, args=(), jac=None, bounds=None,
|
|
234
234
|
disp : bool
|
235
235
|
Set to True to print convergence messages. If False,
|
236
236
|
`verbosity` is ignored and set to 0.
|
237
|
-
maxiter : int
|
238
|
-
Maximum number of iterations.
|
237
|
+
maxiter : int, optional
|
238
|
+
Maximum number of iterations. Default value is 100.
|
239
239
|
finite_diff_rel_step : None or array_like, optional
|
240
240
|
If ``jac in ['2-point', '3-point', 'cs']`` the relative step size to
|
241
241
|
use for numerical approximation of `jac`. The absolute step
|
@@ -268,8 +268,8 @@ def _minimize_slsqp(func, x0, args=(), jac=None, bounds=None,
|
|
268
268
|
attribute as a NumPy array. Denoting the dimension of the equality constraints
|
269
269
|
with ``meq``, and of inequality constraints with ``mineq``, then the returned
|
270
270
|
array slice ``m[:meq]`` contains the multipliers for the equality constraints,
|
271
|
-
and the remaining ``m[meq:meq + mineq]`` contains the multipliers for the
|
272
|
-
inequality constraints. The multipliers corresponding to bound inequalities
|
271
|
+
and the remaining ``m[meq:meq + mineq]`` contains the multipliers for the
|
272
|
+
inequality constraints. The multipliers corresponding to bound inequalities
|
273
273
|
are not returned. See [1]_ pp. 321 or [2]_ for an explanation of how to interpret
|
274
274
|
these multipliers. The internal QP problem is solved using the methods given
|
275
275
|
in [3]_ Chapter 25.
|
@@ -461,7 +461,7 @@ def _minimize_slsqp(func, x0, args=(), jac=None, bounds=None,
|
|
461
461
|
"inconsistent": 0,
|
462
462
|
"reset": 0,
|
463
463
|
"iter": 0,
|
464
|
-
"itermax": maxiter,
|
464
|
+
"itermax": int(maxiter),
|
465
465
|
"line": 0,
|
466
466
|
"m": m,
|
467
467
|
"meq": meq,
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -1126,7 +1126,7 @@ class TestOptimizeSimple(CheckOptimize):
|
|
1126
1126
|
|
1127
1127
|
def test_minimize_l_bfgs_b(self):
|
1128
1128
|
# Minimize with L-BFGS-B method
|
1129
|
-
opts = {'
|
1129
|
+
opts = {'maxiter': self.maxiter}
|
1130
1130
|
r = optimize.minimize(self.func, self.startparams,
|
1131
1131
|
method='L-BFGS-B', jac=self.grad,
|
1132
1132
|
options=opts)
|
@@ -1156,7 +1156,7 @@ class TestOptimizeSimple(CheckOptimize):
|
|
1156
1156
|
# Check that the `ftol` parameter in l_bfgs_b works as expected
|
1157
1157
|
v0 = None
|
1158
1158
|
for tol in [1e-1, 1e-4, 1e-7, 1e-10]:
|
1159
|
-
opts = {'
|
1159
|
+
opts = {'maxiter': self.maxiter, 'ftol': tol}
|
1160
1160
|
sol = optimize.minimize(self.func, self.startparams,
|
1161
1161
|
method='L-BFGS-B', jac=self.grad,
|
1162
1162
|
options=opts)
|
@@ -1173,7 +1173,7 @@ class TestOptimizeSimple(CheckOptimize):
|
|
1173
1173
|
# check that the maxls is passed down to the Fortran routine
|
1174
1174
|
sol = optimize.minimize(optimize.rosen, np.array([-1.2, 1.0]),
|
1175
1175
|
method='L-BFGS-B', jac=optimize.rosen_der,
|
1176
|
-
options={'
|
1176
|
+
options={'maxls': 1})
|
1177
1177
|
assert not sol.success
|
1178
1178
|
|
1179
1179
|
def test_minimize_l_bfgs_b_maxfun_interruption(self):
|
@@ -3167,6 +3167,15 @@ def test_bounds_with_list():
|
|
3167
3167
|
)
|
3168
3168
|
|
3169
3169
|
|
3170
|
+
@pytest.mark.parametrize('method', (
|
3171
|
+
'slsqp', 'cg', 'cobyqa', 'powell','nelder-mead', 'bfgs', 'l-bfgs-b',
|
3172
|
+
'trust-constr'))
|
3173
|
+
def test_minimize_maxiter_noninteger(method):
|
3174
|
+
# Regression test for gh-23430
|
3175
|
+
x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])
|
3176
|
+
optimize.minimize(rosen, x0, method=method, options={'maxiter': 100.1})
|
3177
|
+
|
3178
|
+
|
3170
3179
|
def test_x_overwritten_user_function():
|
3171
3180
|
# if the user overwrites the x-array in the user function it's likely
|
3172
3181
|
# that the minimizer stops working properly.
|
scipy/signal/_filter_design.py
CHANGED
@@ -60,6 +60,17 @@ def _is_int_type(x):
|
|
60
60
|
return True
|
61
61
|
|
62
62
|
|
63
|
+
def _real_dtype_for_complex(dtyp, *, xp):
|
64
|
+
if xp.isdtype(dtyp, 'real floating'):
|
65
|
+
return dtyp
|
66
|
+
if dtyp == xp.complex64:
|
67
|
+
return xp.float32
|
68
|
+
elif dtyp == xp.complex128:
|
69
|
+
return xp.float64
|
70
|
+
else:
|
71
|
+
raise ValueError(f"Unknown dtype {dtyp}.")
|
72
|
+
|
73
|
+
|
63
74
|
# https://github.com/numpy/numpy/blob/v2.2.0/numpy/_core/function_base.py#L195-L302
|
64
75
|
def _logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, *, xp):
|
65
76
|
if not isinstance(base, float | int) and xp.asarray(base).ndim > 0:
|
@@ -488,6 +499,7 @@ def freqz(b, a=1, worN=512, whole=False, plot=None, fs=2*pi,
|
|
488
499
|
if xp.isdtype(a.dtype, 'integral'):
|
489
500
|
a = xp.astype(a, xp_default_dtype(xp))
|
490
501
|
res_dtype = xp.result_type(b, a)
|
502
|
+
real_dtype = _real_dtype_for_complex(res_dtype, xp=xp)
|
491
503
|
|
492
504
|
b = xpx.atleast_nd(b, ndim=1, xp=xp)
|
493
505
|
a = xpx.atleast_nd(a, ndim=1, xp=xp)
|
@@ -509,7 +521,7 @@ def freqz(b, a=1, worN=512, whole=False, plot=None, fs=2*pi,
|
|
509
521
|
# if include_nyquist is true and whole is false, w should
|
510
522
|
# include end point
|
511
523
|
w = xp.linspace(0, lastpoint, N,
|
512
|
-
endpoint=include_nyquist and not whole, dtype=
|
524
|
+
endpoint=include_nyquist and not whole, dtype=real_dtype)
|
513
525
|
n_fft = N if whole else 2 * (N - 1) if include_nyquist else 2 * N
|
514
526
|
if (xp_size(a) == 1 and (b.ndim == 1 or (b.shape[-1] == 1))
|
515
527
|
and n_fft >= b.shape[0]
|
@@ -834,7 +834,7 @@ def remez(numtaps, bands, desired, *, weight=None, type='bandpass',
|
|
834
834
|
xp = array_namespace(bands, desired, weight)
|
835
835
|
bands = np.asarray(bands)
|
836
836
|
desired = np.asarray(desired)
|
837
|
-
if weight:
|
837
|
+
if weight is not None:
|
838
838
|
weight = np.asarray(weight)
|
839
839
|
|
840
840
|
fs = _validate_fs(fs, allow_none=True)
|
Binary file
|
Binary file
|
scipy/signal/_polyutils.py
CHANGED
@@ -117,7 +117,7 @@ def poly(seq_of_zeros, *, xp):
|
|
117
117
|
if xp.isdtype(a.dtype, 'complex floating'):
|
118
118
|
# if complex roots are all complex conjugates, the roots are real.
|
119
119
|
roots = xp.asarray(seq_of_zeros, dtype=xp.complex128)
|
120
|
-
if xp.all(
|
120
|
+
if xp.all(xp.sort(xp.imag(roots)) == xp.sort(xp.imag(xp.conj(roots)))):
|
121
121
|
a = xp.asarray(xp.real(a), copy=True)
|
122
122
|
|
123
123
|
return a
|
scipy/signal/_short_time_fft.py
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
"""Implementation of an FFT-based Short-time Fourier Transform. """
|
2
2
|
|
3
|
-
# Implementation Notes for this file (as of
|
3
|
+
# Implementation Notes for this file (as of 2025-08)
|
4
4
|
# --------------------------------------------------
|
5
|
-
# * MyPy version 1.1.1 does not seem to support decorated property methods
|
6
|
-
# properly. Hence, applying ``@property`` to methods decorated with `@cache``
|
7
|
-
# (as tried with the ``lower_border_end`` method) causes a mypy error when
|
8
|
-
# accessing it as an index (e.g., ``SFT.lower_border_end[0]``).
|
9
5
|
# * Since the method `stft` and `istft` have identical names as the legacy
|
10
6
|
# functions in the signal module, referencing them as HTML link in the
|
11
7
|
# docstrings has to be done by an explicit `~ShortTimeFFT.stft` instead of an
|
@@ -17,10 +13,9 @@
|
|
17
13
|
# (currently 0.9). Consult Issue 18512 and PR 16660 for further details.
|
18
14
|
|
19
15
|
|
20
|
-
# Provides typing union operator ``|`` in Python 3.9:
|
21
16
|
# Linter does not allow to import ``Generator`` from ``typing`` module:
|
22
17
|
from collections.abc import Generator, Callable
|
23
|
-
from functools import
|
18
|
+
from functools import partial, cached_property
|
24
19
|
from typing import get_args, Literal
|
25
20
|
|
26
21
|
import numpy as np
|
@@ -419,6 +414,15 @@ class ShortTimeFFT:
|
|
419
414
|
_fac_mag: float | None = None
|
420
415
|
_fac_psd: float | None = None
|
421
416
|
_lower_border_end: tuple[int, int] | None = None
|
417
|
+
# The following tuples store parameter(s) and return value(s) of methods for caching
|
418
|
+
# (initialized with invalid parameters; should only be accessed by atomic
|
419
|
+
# read/writes to alleviate potential multithreading issues):
|
420
|
+
_cache_post_padding: tuple[int, tuple[int, int]] = -1, (0, 0)
|
421
|
+
_cache_upper_border_begin: tuple[int, tuple[int, int]] = -1, (0, 0)
|
422
|
+
_cache_t: tuple[tuple[int, int | None, int | None, int, float], np.ndarray] = \
|
423
|
+
(-1, None, None, 0, 0.), np.ndarray([])
|
424
|
+
_cache_f: tuple[tuple[FFT_MODE_TYPE, int, float], np.ndarray] = \
|
425
|
+
('onesided', -1, 1.), np.ndarray([])
|
422
426
|
|
423
427
|
def __init__(self, win: np.ndarray, hop: int, fs: float, *,
|
424
428
|
fft_mode: FFT_MODE_TYPE = 'onesided',
|
@@ -1607,7 +1611,7 @@ class ShortTimeFFT:
|
|
1607
1611
|
"""
|
1608
1612
|
return self.m_num // 2
|
1609
1613
|
|
1610
|
-
@
|
1614
|
+
@cached_property
|
1611
1615
|
def _pre_padding(self) -> tuple[int, int]:
|
1612
1616
|
"""Smallest signal index and slice index due to padding.
|
1613
1617
|
|
@@ -1617,13 +1621,12 @@ class ShortTimeFFT:
|
|
1617
1621
|
w2 = self.win.real**2 + self.win.imag**2
|
1618
1622
|
# move window to the left until the overlap with t >= 0 vanishes:
|
1619
1623
|
n0 = -self.m_num_mid
|
1620
|
-
for
|
1624
|
+
for p_, n_ in enumerate(range(n0, n0-self.m_num-1, -self.hop)):
|
1621
1625
|
n_next = n_ - self.hop
|
1622
1626
|
if n_next + self.m_num <= 0 or all(w2[n_next:] == 0):
|
1623
|
-
return n_, -
|
1624
|
-
|
1625
|
-
|
1626
|
-
# returned, i.e.: return n0, 0
|
1627
|
+
return n_, -p_
|
1628
|
+
# Make the linter happy:
|
1629
|
+
raise RuntimeError("This code line should never run! Please file a bug.")
|
1627
1630
|
|
1628
1631
|
@property
|
1629
1632
|
def k_min(self) -> int:
|
@@ -1646,7 +1649,7 @@ class ShortTimeFFT:
|
|
1646
1649
|
upper_border_begin: Where post-padding effects start.
|
1647
1650
|
ShortTimeFFT: Class this property belongs to.
|
1648
1651
|
"""
|
1649
|
-
return self._pre_padding
|
1652
|
+
return self._pre_padding[0]
|
1650
1653
|
|
1651
1654
|
@property
|
1652
1655
|
def p_min(self) -> int:
|
@@ -1671,9 +1674,8 @@ class ShortTimeFFT:
|
|
1671
1674
|
p_range: Determine and validate slice index range.
|
1672
1675
|
ShortTimeFFT: Class this property belongs to.
|
1673
1676
|
"""
|
1674
|
-
return self._pre_padding
|
1677
|
+
return self._pre_padding[1]
|
1675
1678
|
|
1676
|
-
@lru_cache(maxsize=256)
|
1677
1679
|
def _post_padding(self, n: int) -> tuple[int, int]:
|
1678
1680
|
"""Largest signal index and slice index due to padding.
|
1679
1681
|
|
@@ -1681,9 +1683,17 @@ class ShortTimeFFT:
|
|
1681
1683
|
----------
|
1682
1684
|
n : int
|
1683
1685
|
Number of samples of input signal (must be ≥ half of the window length).
|
1686
|
+
|
1687
|
+
Notes
|
1688
|
+
-----
|
1689
|
+
Note that the return values are cached together with the parameter `n` to avoid
|
1690
|
+
unnecessary recalculations.
|
1684
1691
|
"""
|
1685
1692
|
if not (n >= (m2p := self.m_num - self.m_num_mid)):
|
1686
1693
|
raise ValueError(f"Parameter n must be >= ceil(m_num/2) = {m2p}!")
|
1694
|
+
last_arg, last_return_value = self._cache_post_padding
|
1695
|
+
if n == last_arg: # use cached value:
|
1696
|
+
return last_return_value
|
1687
1697
|
w2 = self.win.real**2 + self.win.imag**2
|
1688
1698
|
# move window to the right until the overlap for t < t[n] vanishes:
|
1689
1699
|
q1 = n // self.hop # last slice index with t[p1] <= t[n]
|
@@ -1691,15 +1701,17 @@ class ShortTimeFFT:
|
|
1691
1701
|
for q_, k_ in enumerate(range(k1, n+self.m_num, self.hop), start=q1):
|
1692
1702
|
n_next = k_ + self.hop
|
1693
1703
|
if n_next >= n or all(w2[:n-n_next] == 0):
|
1694
|
-
|
1695
|
-
|
1704
|
+
return_value = k_ + self.m_num, q_ + 1
|
1705
|
+
self._cache_post_padding = n, return_value
|
1706
|
+
return return_value
|
1707
|
+
raise RuntimeError("This code line should never run! Please file a bug.")
|
1696
1708
|
# If this case is reached, it probably means the last slice should be
|
1697
1709
|
# returned, i.e.: return k1 + self.m_num - self.m_num_mid, q1 + 1
|
1698
1710
|
|
1699
1711
|
def k_max(self, n: int) -> int:
|
1700
1712
|
"""First sample index after signal end not touched by a time slice.
|
1701
1713
|
|
1702
|
-
`k_max` - 1 is the largest sample index of the slice `p_max` for a
|
1714
|
+
`k_max` - 1 is the largest sample index of the slice `p_max` - 1 for a
|
1703
1715
|
given input signal of `n` samples.
|
1704
1716
|
A detailed example is provided in the :ref:`tutorial_stft_sliding_win`
|
1705
1717
|
section of the :ref:`user_guide`.
|
@@ -1785,7 +1797,6 @@ class ShortTimeFFT:
|
|
1785
1797
|
upper_border_begin: Where post-padding effects start.
|
1786
1798
|
ShortTimeFFT: Class this property belongs to.
|
1787
1799
|
"""
|
1788
|
-
# not using @cache decorator due to MyPy limitations
|
1789
1800
|
if self._lower_border_end is not None:
|
1790
1801
|
return self._lower_border_end
|
1791
1802
|
|
@@ -1801,7 +1812,6 @@ class ShortTimeFFT:
|
|
1801
1812
|
self._lower_border_end = (0, max(self.p_min, 0)) # ends at first slice
|
1802
1813
|
return self._lower_border_end
|
1803
1814
|
|
1804
|
-
@lru_cache(maxsize=256)
|
1805
1815
|
def upper_border_begin(self, n: int) -> tuple[int, int]:
|
1806
1816
|
"""First signal index and first slice index affected by post-padding.
|
1807
1817
|
|
@@ -1823,6 +1833,11 @@ class ShortTimeFFT:
|
|
1823
1833
|
p_ub : int
|
1824
1834
|
Lowest index of time slice of which the end sticks out past the signal end.
|
1825
1835
|
|
1836
|
+
Notes
|
1837
|
+
-----
|
1838
|
+
Note that the return values are cached together with the parameter `n` to avoid
|
1839
|
+
unnecessary recalculations.
|
1840
|
+
|
1826
1841
|
See Also
|
1827
1842
|
--------
|
1828
1843
|
k_min: The smallest possible signal index.
|
@@ -1836,6 +1851,9 @@ class ShortTimeFFT:
|
|
1836
1851
|
"""
|
1837
1852
|
if not (n >= (m2p := self.m_num - self.m_num_mid)):
|
1838
1853
|
raise ValueError(f"Parameter n must be >= ceil(m_num/2) = {m2p}!")
|
1854
|
+
last_arg, last_return_value = self._cache_upper_border_begin
|
1855
|
+
if n == last_arg: # use cached value:
|
1856
|
+
return last_return_value
|
1839
1857
|
w2 = self.win.real**2 + self.win.imag**2
|
1840
1858
|
q2 = n // self.hop + 1 # first t[q] >= t[n]
|
1841
1859
|
q1 = max((n-self.m_num) // self.hop - 1, -1)
|
@@ -1843,8 +1861,11 @@ class ShortTimeFFT:
|
|
1843
1861
|
for q_ in range(q2, q1, -1):
|
1844
1862
|
k_ = q_ * self.hop + (self.m_num - self.m_num_mid)
|
1845
1863
|
if k_ <= n or all(w2[n-k_:] == 0):
|
1846
|
-
|
1847
|
-
|
1864
|
+
return_value = (q_ + 1) * self.hop - self.m_num_mid, q_ + 1
|
1865
|
+
self. _cache_upper_border_begin = n, return_value
|
1866
|
+
return return_value
|
1867
|
+
# make linter happy:
|
1868
|
+
raise RuntimeError("This code line should never run! Please file a bug.")
|
1848
1869
|
|
1849
1870
|
@property
|
1850
1871
|
def delta_t(self) -> float:
|
@@ -1912,7 +1933,6 @@ class ShortTimeFFT:
|
|
1912
1933
|
f"does not hold for signal length {n=}!")
|
1913
1934
|
return p0_, p1_
|
1914
1935
|
|
1915
|
-
@lru_cache(maxsize=1)
|
1916
1936
|
def t(self, n: int, p0: int | None = None, p1: int | None = None,
|
1917
1937
|
k_offset: int = 0) -> np.ndarray:
|
1918
1938
|
"""Times of STFT for an input signal with `n` samples.
|
@@ -1934,6 +1954,10 @@ class ShortTimeFFT:
|
|
1934
1954
|
k_offset
|
1935
1955
|
Index of first sample (t = 0) in `x`.
|
1936
1956
|
|
1957
|
+
Notes
|
1958
|
+
-----
|
1959
|
+
Note that the returned array is cached together with the method's call
|
1960
|
+
parameters to avoid unnecessary recalculations.
|
1937
1961
|
|
1938
1962
|
See Also
|
1939
1963
|
--------
|
@@ -1944,8 +1968,18 @@ class ShortTimeFFT:
|
|
1944
1968
|
fs: Sampling frequency (being ``1/T``)
|
1945
1969
|
ShortTimeFFT: Class this method belongs to.
|
1946
1970
|
"""
|
1971
|
+
if not (n > 0 and isinstance(n, int | np.integer)):
|
1972
|
+
raise ValueError(f"Parameter {n=} is not a positive integer!")
|
1973
|
+
args = n, p0, p1, k_offset, self.T # since `self.T` is mutable, it's needed too
|
1974
|
+
last_args, last_return_value = self._cache_t
|
1975
|
+
if args == last_args: # use cached value:
|
1976
|
+
return last_return_value
|
1977
|
+
|
1947
1978
|
p0, p1 = self.p_range(n, p0, p1)
|
1948
|
-
|
1979
|
+
return_value = np.arange(p0, p1) * self.delta_t + k_offset * self.T
|
1980
|
+
|
1981
|
+
self._cache_t = args, return_value
|
1982
|
+
return return_value
|
1949
1983
|
|
1950
1984
|
def nearest_k_p(self, k: int, left: bool = True) -> int:
|
1951
1985
|
"""Return nearest sample index k_p for which t[k_p] == t[p] holds.
|
@@ -2022,6 +2056,7 @@ class ShortTimeFFT:
|
|
2022
2056
|
"""Frequencies values of the STFT.
|
2023
2057
|
|
2024
2058
|
A 1d array of length `f_pts` with `delta_f` spaced entries is returned.
|
2059
|
+
This array is calculated lazily.
|
2025
2060
|
|
2026
2061
|
See Also
|
2027
2062
|
--------
|
@@ -2030,15 +2065,22 @@ class ShortTimeFFT:
|
|
2030
2065
|
mfft: Length of the input for FFT used.
|
2031
2066
|
ShortTimeFFT: Class this property belongs to.
|
2032
2067
|
"""
|
2068
|
+
last_state, last_return_value = self._cache_f
|
2069
|
+
current_state = self.fft_mode, self.mfft, self.T
|
2070
|
+
if current_state == last_state: # use cached value:
|
2071
|
+
return last_return_value
|
2072
|
+
|
2033
2073
|
if self.fft_mode in {'onesided', 'onesided2X'}:
|
2034
|
-
|
2074
|
+
return_value = fft_lib.rfftfreq(self.mfft, self.T)
|
2035
2075
|
elif self.fft_mode == 'twosided':
|
2036
|
-
|
2076
|
+
return_value = fft_lib.fftfreq(self.mfft, self.T)
|
2037
2077
|
elif self.fft_mode == 'centered':
|
2038
|
-
|
2039
|
-
# This should never happen but makes the Linters happy:
|
2040
|
-
|
2041
|
-
|
2078
|
+
return_value = fft_lib.fftshift(fft_lib.fftfreq(self.mfft, self.T))
|
2079
|
+
else: # This should never happen but makes the Linters happy:
|
2080
|
+
fft_modes = get_args(FFT_MODE_TYPE)
|
2081
|
+
raise RuntimeError(f"{self.fft_mode=} not in {fft_modes}!")
|
2082
|
+
self._cache_f = current_state, return_value
|
2083
|
+
return return_value
|
2042
2084
|
|
2043
2085
|
def _fft_func(self, x: np.ndarray) -> np.ndarray:
|
2044
2086
|
"""FFT based on the `fft_mode`, `mfft`, `scaling` and `phase_shift`
|
@@ -2095,8 +2137,7 @@ class ShortTimeFFT:
|
|
2095
2137
|
Xc[..., 1:q1] /= fac
|
2096
2138
|
x = fft_lib.irfft(Xc, n=self.mfft, axis=-1)
|
2097
2139
|
else: # This should never happen but makes the Linter happy:
|
2098
|
-
|
2099
|
-
raise RuntimeError(error_str)
|
2140
|
+
raise RuntimeError(f"{self.fft_mode=} not in {get_args(FFT_MODE_TYPE)}!")
|
2100
2141
|
|
2101
2142
|
if self.phase_shift is None:
|
2102
2143
|
return x[..., :self.m_num]
|
Binary file
|
Binary file
|
scipy/signal/_spectral_py.py
CHANGED
@@ -243,11 +243,11 @@ def lombscargle(
|
|
243
243
|
)
|
244
244
|
|
245
245
|
# weight vector must sum to 1
|
246
|
-
weights
|
246
|
+
weights = weights * (1.0 / weights.sum())
|
247
247
|
|
248
248
|
# if requested, perform precenter
|
249
249
|
if precenter:
|
250
|
-
y
|
250
|
+
y = y - y.mean()
|
251
251
|
|
252
252
|
# transform arrays
|
253
253
|
# row vector
|
Binary file
|
Binary file
|
@@ -382,6 +382,19 @@ class TestTf2Sos:
|
|
382
382
|
sos2 = tf2sos(b, a, analog=analog)
|
383
383
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
384
384
|
|
385
|
+
def test_gh_23221(self):
|
386
|
+
# Tests that this tf2sos call below does not produce ComplexWarnings
|
387
|
+
# This test is specific for scipy==1.16.0: later scipy versions do not produce
|
388
|
+
# the warning.
|
389
|
+
with suppress_warnings():
|
390
|
+
warnings.simplefilter("error")
|
391
|
+
tf2sos([0.21860986786301265, -0.4372197357260253, -0.2186098678630126,
|
392
|
+
0.8744394714520509, -0.21860986786301248, -0.4372197357260253,
|
393
|
+
0.21860986786301265],
|
394
|
+
[1., -4.18323041786553, 6.829924151626914, -5.407777865686045,
|
395
|
+
2.0773105450802336, -0.33482732571537893, 0.0186009178695853 ]
|
396
|
+
)
|
397
|
+
|
385
398
|
|
386
399
|
@skip_xp_backends(
|
387
400
|
cpu_only=True, reason="XXX zpk2sos is numpy-only", exceptions=['cupy']
|
@@ -754,6 +767,12 @@ class TestFreqz:
|
|
754
767
|
xp_assert_equal(w, xp.asarray([0. , 0.1]))
|
755
768
|
xp_assert_equal(h, xp.asarray([1.+0.j, 1.+0.j]))
|
756
769
|
|
770
|
+
def test_gh_23277(self):
|
771
|
+
# backwards compatibility: `w` array must be real, not complex
|
772
|
+
filt = [0.5 + 0.0j, 0.5 + 0.0j]
|
773
|
+
w, _ = freqz(filt, worN=8)
|
774
|
+
assert w.dtype == np.float64
|
775
|
+
|
757
776
|
def test_basic(self, xp):
|
758
777
|
w, h = freqz(xp.asarray([1.0]), worN=8)
|
759
778
|
assert_array_almost_equal(w, xp.pi * xp.arange(8, dtype=w.dtype) / 8.)
|
@@ -546,6 +546,11 @@ class TestRemez:
|
|
546
546
|
with pytest.raises(ValueError, match="Sampling.*single scalar"):
|
547
547
|
remez(11, .1, 1, fs=np.array([10, 20]))
|
548
548
|
|
549
|
+
def test_gh_23266(self, xp):
|
550
|
+
bands = xp.asarray([0.0, 0.2, 0.3, 0.5])
|
551
|
+
desired = xp.asarray([1.0, 0.0])
|
552
|
+
weight = xp.asarray([1.0, 2.0])
|
553
|
+
remez(21, bands, desired, weight=weight)
|
549
554
|
|
550
555
|
|
551
556
|
@skip_xp_backends(cpu_only=True, reason="lstsq")
|
@@ -531,11 +531,15 @@ def test_border_values():
|
|
531
531
|
assert SFT.p_max(10) == 4
|
532
532
|
assert SFT.k_max(10) == 16
|
533
533
|
assert SFT.upper_border_begin(10) == (4, 2)
|
534
|
+
assert SFT.upper_border_begin(10) == (4, 2) # needed to test caching
|
534
535
|
# Raise exceptions:
|
535
536
|
with pytest.raises(ValueError, match="^Parameter n must be"):
|
536
537
|
SFT.upper_border_begin(3)
|
537
538
|
with pytest.raises(ValueError, match="^Parameter n must be"):
|
538
539
|
SFT._post_padding(3)
|
540
|
+
with pytest.raises(RuntimeError):
|
541
|
+
SFT._hop = -1 # illegal hop interval
|
542
|
+
SFT.upper_border_begin(8)
|
539
543
|
|
540
544
|
def test_border_values_exotic():
|
541
545
|
"""Ensure that the border calculations are correct for windows with
|
@@ -573,6 +577,11 @@ def test_t():
|
|
573
577
|
SFT.fs = 1/8
|
574
578
|
assert SFT.fs == 1/8
|
575
579
|
assert SFT.T == 8
|
580
|
+
with pytest.raises(ValueError):
|
581
|
+
# noinspection PyTypeChecker
|
582
|
+
SFT.t(1.5) # only integers allowed
|
583
|
+
with pytest.raises(ValueError):
|
584
|
+
SFT.t(-1) # only positive `n` allowed
|
576
585
|
|
577
586
|
|
578
587
|
@pytest.mark.parametrize('fft_mode, f',
|
@@ -1295,7 +1295,7 @@ class TestMedFilt:
|
|
1295
1295
|
# us into wrong memory if used (but it does not need to be used)
|
1296
1296
|
dummy = xp.arange(10, dtype=xp.float64)
|
1297
1297
|
a = dummy[5:6]
|
1298
|
-
a.strides
|
1298
|
+
a = np.lib.stride_tricks.as_strided(a, strides=(16,))
|
1299
1299
|
xp_assert_close(signal.medfilt(a, 1), xp.asarray([5.]))
|
1300
1300
|
|
1301
1301
|
@skip_xp_backends(
|
@@ -2084,7 +2084,9 @@ class _TestLinearFilter:
|
|
2084
2084
|
a = self.convert_dtype(a, xp)
|
2085
2085
|
x = self.convert_dtype(x, xp)
|
2086
2086
|
zi = self.convert_dtype(zi, xp)
|
2087
|
-
|
2087
|
+
# NOTE: MemoryError is currently allowed below because of:
|
2088
|
+
# https://github.com/numpy/numpy/issues/29721
|
2089
|
+
assert_raises((ValueError, MemoryError), lfilter, b, a, x, axis, zi)
|
2088
2090
|
|
2089
2091
|
@skip_xp_backends('cupy', reason='cupy does not raise')
|
2090
2092
|
def test_bad_size_zi(self, xp):
|
@@ -2134,7 +2136,11 @@ class _TestLinearFilter:
|
|
2134
2136
|
self.base_bad_size_zi([1, 1, 1], [1], x2, 0, [[0, 1, 2, 3], [4, 5, 6, 7]], xp)
|
2135
2137
|
|
2136
2138
|
self.base_bad_size_zi([1], [1, 1], x2, 0, [0, 1, 2], xp)
|
2137
|
-
|
2139
|
+
# this case is disabled on the release branch
|
2140
|
+
# because of:
|
2141
|
+
# https://github.com/scipy/scipy/pull/23543#issuecomment-3276286172
|
2142
|
+
# https://github.com/numpy/numpy/issues/29721
|
2143
|
+
#self.base_bad_size_zi([1], [1, 1], x2, 0, [[[0, 1, 2]]], xp)
|
2138
2144
|
self.base_bad_size_zi([1], [1, 1], x2, 0, [[0], [1], [2]], xp)
|
2139
2145
|
self.base_bad_size_zi([1], [1, 1], x2, 0, [[0, 1]], xp)
|
2140
2146
|
self.base_bad_size_zi([1], [1, 1], x2, 0, [[0, 1, 2, 3]], xp)
|
@@ -1055,7 +1055,6 @@ class TestLombscargle:
|
|
1055
1055
|
delta = f[1] - f[0]
|
1056
1056
|
assert(w - f[np.argmax(P)] < (delta/2.))
|
1057
1057
|
|
1058
|
-
|
1059
1058
|
def test_amplitude(self):
|
1060
1059
|
# Test if height of peak in unnormalized Lomb-Scargle periodogram
|
1061
1060
|
# corresponds to amplitude of the generated input signal.
|
@@ -1503,6 +1502,45 @@ class TestLombscargle:
|
|
1503
1502
|
|
1504
1503
|
lombscargle(t, y, freqs)
|
1505
1504
|
|
1505
|
+
def test_input_mutation(self):
|
1506
|
+
# this tests for mutation of the input arrays
|
1507
|
+
# https://github.com/scipy/scipy/issues/23474
|
1508
|
+
|
1509
|
+
# Input parameters
|
1510
|
+
ampl = 2.
|
1511
|
+
w = 1.
|
1512
|
+
phi = 0.5 * np.pi
|
1513
|
+
nin = 100
|
1514
|
+
nout = 1000
|
1515
|
+
p = 0.7 # Fraction of points to select
|
1516
|
+
|
1517
|
+
# Randomly select a fraction of an array with timesteps
|
1518
|
+
rng = np.random.default_rng()
|
1519
|
+
r = rng.random(nin)
|
1520
|
+
t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p]
|
1521
|
+
|
1522
|
+
# Plot a sine wave for the selected times
|
1523
|
+
y = ampl * np.sin(w*t + phi)
|
1524
|
+
|
1525
|
+
# Define the array of frequencies for which to compute the periodogram
|
1526
|
+
f = np.linspace(0.01, 10., nout)
|
1527
|
+
|
1528
|
+
weights = np.ones_like(y)
|
1529
|
+
|
1530
|
+
# create original copies before passing
|
1531
|
+
t_org = t.copy()
|
1532
|
+
y_org = y.copy()
|
1533
|
+
f_org = f.copy()
|
1534
|
+
weights_org = weights.copy()
|
1535
|
+
|
1536
|
+
lombscargle(t, y, f, precenter=True, weights=weights)
|
1537
|
+
|
1538
|
+
# check all 4 array inputs
|
1539
|
+
assert_array_equal(t, t_org)
|
1540
|
+
assert_array_equal(y, y_org)
|
1541
|
+
assert_array_equal(f, f_org)
|
1542
|
+
assert_array_equal(weights, weights_org)
|
1543
|
+
|
1506
1544
|
|
1507
1545
|
class TestSTFT:
|
1508
1546
|
@pytest.mark.thread_unsafe
|
scipy/sparse/_base.py
CHANGED
@@ -494,7 +494,10 @@ class _spbase(SparseABC):
|
|
494
494
|
return self._mul_scalar(other)
|
495
495
|
|
496
496
|
if self.ndim < 3:
|
497
|
-
|
497
|
+
try:
|
498
|
+
return self._multiply_2d_with_broadcasting(other)
|
499
|
+
except AttributeError:
|
500
|
+
return self.tocsr()._multiply_2d_with_broadcasting(other)
|
498
501
|
|
499
502
|
if not (issparse(other) or isdense(other)):
|
500
503
|
# If it's a list or whatever, treat it like an array
|
Binary file
|