scipy 1.15.2__cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 1.15.3__cp310-cp310-manylinux_2_17_aarch64.manylinux2014_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 +3 -3
- scipy/_lib/_array_api.py +11 -0
- scipy/_lib/_ccallback_c.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/_lib/_test_ccallback.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/_lib/tests/test_array_api.py +5 -1
- scipy/cluster/_hierarchy.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/cluster/_optimal_leaf_ordering.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/cluster/_vq.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/fftpack/convolve.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/integrate/_dop.cpython-310-aarch64-linux-gnu.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-310-aarch64-linux-gnu.so +0 -0
- scipy/integrate/_quadpack.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/integrate/_tanhsinh.py +14 -12
- scipy/integrate/_test_odeint_banded.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/integrate/_vode.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/integrate/tests/test_tanhsinh.py +10 -0
- scipy/interpolate/_bspl.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/interpolate/_dfitpack.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/interpolate/_rgi_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/io/_test_fortran.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/io/matlab/_mio5_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/io/matlab/_mio_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_cythonized_array_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_decomp_interpolative.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_decomp_lu_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_decomp_update.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_fblas.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_flapack.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_matfuncs_sqrtm_triu.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/_solve_toeplitz.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/cython_blas.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/cython_lapack.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/linalg/tests/test_interpolative.py +17 -0
- scipy/ndimage/_cytest.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/ndimage/_nd_image.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/ndimage/_ndimage_api.py +2 -1
- scipy/ndimage/_ni_label.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/ndimage/_rank_filter_1d.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/ndimage/tests/test_filters.py +14 -0
- scipy/optimize/_bglu_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/optimize/_bracket.py +35 -8
- scipy/optimize/_cobyla.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/optimize/_cython_nnls.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/optimize/_highspy/_highs_wrapper.py +6 -4
- scipy/optimize/_linprog_highs.py +9 -9
- scipy/optimize/_linprog_util.py +4 -3
- scipy/optimize/_minpack.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/optimize/_moduleTNC.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/optimize/_slsqp.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/optimize/_trlib/_trlib.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/optimize/tests/test_bracket.py +35 -0
- scipy/signal/_peak_finding_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/signal/_short_time_fft.py +34 -6
- scipy/signal/_signaltools.py +4 -1
- scipy/signal/_sosfilt.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/signal/_upfirdn_apply.cpython-310-aarch64-linux-gnu.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-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/_dia.py +0 -3
- scipy/sparse/csgraph/_flow.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/csgraph/_matching.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/csgraph/_min_spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/csgraph/_reordering.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/csgraph/_shortest_path.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/csgraph/_tools.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/csgraph/_traversal.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/linalg/_eigen/arpack/_arpack.cpython-310-aarch64-linux-gnu.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-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/linalg/_propack/_dpropack.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/linalg/_propack/_spropack.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/sparse/linalg/_propack/_zpropack.cpython-310-aarch64-linux-gnu.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-310-aarch64-linux-gnu.so +0 -0
- scipy/spatial/_hausdorff.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/spatial/_qhull.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/spatial/_voronoi.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/spatial/tests/test_qhull.py +99 -0
- scipy/spatial/transform/_rotation.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/spatial/transform/tests/test_rotation.py +181 -10
- scipy/special/_ellip_harm_2.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/special/_logsumexp.py +21 -16
- scipy/special/_specfun.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/special/_special_ufuncs.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/special/_ufuncs.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/special/_ufuncs_cxx.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/special/cython_special.cpython-310-aarch64-linux-gnu.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-310-aarch64-linux-gnu.so +0 -0
- scipy/stats/_biasedurn.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/stats/_continuous_distns.py +25 -15
- scipy/stats/_mvn.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/stats/_qmc_cy.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/stats/_rcont/rcont.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/stats/_sobol.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/stats/_stats.cpython-310-aarch64-linux-gnu.so +0 -0
- scipy/stats/_unuran/unuran_wrapper.cpython-310-aarch64-linux-gnu.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 +1340 -1340
- {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/__config__.py
CHANGED
@@ -59,7 +59,7 @@ CONFIG = _cleanup(
|
|
59
59
|
},
|
60
60
|
"pythran": {
|
61
61
|
"version": r"0.17.0",
|
62
|
-
"include directory": r"../../tmp/pip-build-env-
|
62
|
+
"include directory": r"../../tmp/pip-build-env-tisjgmp9/overlay/lib/python3.10/site-packages/pythran"
|
63
63
|
},
|
64
64
|
},
|
65
65
|
"Machine Information": {
|
@@ -85,7 +85,7 @@ CONFIG = _cleanup(
|
|
85
85
|
"detection method": "pkgconfig",
|
86
86
|
"include directory": r"/opt/_internal/cpython-3.10.15/lib/python3.10/site-packages/scipy_openblas32/include",
|
87
87
|
"lib directory": r"/opt/_internal/cpython-3.10.15/lib/python3.10/site-packages/scipy_openblas32/lib",
|
88
|
-
"openblas configuration": r"OpenBLAS 0.3.28 DYNAMIC_ARCH NO_AFFINITY
|
88
|
+
"openblas configuration": r"OpenBLAS 0.3.28 DYNAMIC_ARCH NO_AFFINITY neoversen2 MAX_THREADS=64",
|
89
89
|
"pc file directory": r"/project",
|
90
90
|
},
|
91
91
|
"lapack": {
|
@@ -95,7 +95,7 @@ CONFIG = _cleanup(
|
|
95
95
|
"detection method": "pkgconfig",
|
96
96
|
"include directory": r"/opt/_internal/cpython-3.10.15/lib/python3.10/site-packages/scipy_openblas32/include",
|
97
97
|
"lib directory": r"/opt/_internal/cpython-3.10.15/lib/python3.10/site-packages/scipy_openblas32/lib",
|
98
|
-
"openblas configuration": r"OpenBLAS 0.3.28 DYNAMIC_ARCH NO_AFFINITY
|
98
|
+
"openblas configuration": r"OpenBLAS 0.3.28 DYNAMIC_ARCH NO_AFFINITY neoversen2 MAX_THREADS=64",
|
99
99
|
"pc file directory": r"/project",
|
100
100
|
},
|
101
101
|
"pybind11": {
|
scipy/_lib/_array_api.py
CHANGED
@@ -593,3 +593,14 @@ def xp_float_to_complex(arr: Array, xp: ModuleType | None = None) -> Array:
|
|
593
593
|
arr = xp.astype(arr, xp.complex128)
|
594
594
|
|
595
595
|
return arr
|
596
|
+
|
597
|
+
|
598
|
+
def xp_default_dtype(xp):
|
599
|
+
"""Query the namespace-dependent default floating-point dtype.
|
600
|
+
"""
|
601
|
+
if is_torch(xp):
|
602
|
+
# historically, we allow pytorch to keep its default of float32
|
603
|
+
return xp.get_default_dtype()
|
604
|
+
else:
|
605
|
+
# we default to float64
|
606
|
+
return xp.float64
|
Binary file
|
Binary file
|
@@ -4,7 +4,7 @@ import pytest
|
|
4
4
|
from scipy.conftest import array_api_compatible
|
5
5
|
from scipy._lib._array_api import (
|
6
6
|
_GLOBAL_CONFIG, array_namespace, _asarray, xp_copy, xp_assert_equal, is_numpy,
|
7
|
-
np_compat,
|
7
|
+
np_compat, xp_default_dtype
|
8
8
|
)
|
9
9
|
from scipy._lib._array_api_no_0d import xp_assert_equal as xp_assert_equal_no_0d
|
10
10
|
|
@@ -185,3 +185,7 @@ class TestArrayAPI:
|
|
185
185
|
# scalars-vs-0d passes (if values match) also with regular python objects
|
186
186
|
xp_assert_equal_no_0d(0., xp.asarray(0.))
|
187
187
|
xp_assert_equal_no_0d(42, xp.asarray(42))
|
188
|
+
|
189
|
+
@array_api_compatible
|
190
|
+
def test_default_dtype(self, xp):
|
191
|
+
assert xp_default_dtype(xp) == xp.asarray(1.).dtype
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
scipy/integrate/_ivp/common.py
CHANGED
@@ -65,7 +65,7 @@ def norm(x):
|
|
65
65
|
return np.linalg.norm(x) / x.size ** 0.5
|
66
66
|
|
67
67
|
|
68
|
-
def select_initial_step(fun, t0, y0, t_bound,
|
68
|
+
def select_initial_step(fun, t0, y0, t_bound,
|
69
69
|
max_step, f0, direction, order, rtol, atol):
|
70
70
|
"""Empirically select a good initial step.
|
71
71
|
|
@@ -80,7 +80,7 @@ def select_initial_step(fun, t0, y0, t_bound,
|
|
80
80
|
y0 : ndarray, shape (n,)
|
81
81
|
Initial value of the dependent variable.
|
82
82
|
t_bound : float
|
83
|
-
End-point of integration interval; used to ensure that t0+step<=tbound
|
83
|
+
End-point of integration interval; used to ensure that t0+step<=tbound
|
84
84
|
and that fun is only evaluated in the interval [t0,tbound]
|
85
85
|
max_step : float
|
86
86
|
Maximum allowable step size.
|
@@ -112,7 +112,7 @@ def select_initial_step(fun, t0, y0, t_bound,
|
|
112
112
|
interval_length = abs(t_bound - t0)
|
113
113
|
if interval_length == 0.0:
|
114
114
|
return 0.0
|
115
|
-
|
115
|
+
|
116
116
|
scale = atol + np.abs(y0) * rtol
|
117
117
|
d0 = norm(y0 / scale)
|
118
118
|
d1 = norm(f0 / scale)
|
scipy/integrate/_ivp/ivp.py
CHANGED
@@ -694,8 +694,15 @@ def solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False,
|
|
694
694
|
g = g_new
|
695
695
|
|
696
696
|
if t_eval is None:
|
697
|
-
ts
|
698
|
-
|
697
|
+
donot_append = (len(ts) > 1 and
|
698
|
+
ts[-1] == t and
|
699
|
+
dense_output)
|
700
|
+
if not donot_append:
|
701
|
+
ts.append(t)
|
702
|
+
ys.append(y)
|
703
|
+
else:
|
704
|
+
if len(interpolants) > 0:
|
705
|
+
interpolants.pop()
|
699
706
|
else:
|
700
707
|
# The value in t_eval equal to t will be included.
|
701
708
|
if solver.direction > 0:
|
@@ -151,6 +151,25 @@ def compute_error(y, y_true, rtol, atol):
|
|
151
151
|
e = (y - y_true) / (atol + rtol * np.abs(y_true))
|
152
152
|
return np.linalg.norm(e, axis=0) / np.sqrt(e.shape[0])
|
153
153
|
|
154
|
+
def test_duplicate_timestamps():
|
155
|
+
def upward_cannon(t, y):
|
156
|
+
return [y[1], -9.80665]
|
157
|
+
|
158
|
+
def hit_ground(t, y):
|
159
|
+
return y[0]
|
160
|
+
|
161
|
+
hit_ground.terminal = True
|
162
|
+
hit_ground.direction = -1
|
163
|
+
|
164
|
+
sol = solve_ivp(upward_cannon, [0, np.inf], [0, 0.01],
|
165
|
+
max_step=0.05 * 0.001 / 9.80665,
|
166
|
+
events=hit_ground, dense_output=True)
|
167
|
+
assert_allclose(sol.sol(0.01), np.asarray([-0.00039033, -0.08806632]),
|
168
|
+
rtol=1e-5, atol=1e-8)
|
169
|
+
assert_allclose(sol.t_events, np.asarray([[0.00203943]]), rtol=1e-5, atol=1e-8)
|
170
|
+
assert_allclose(sol.y_events, [np.asarray([[ 0.0, -0.01 ]])], atol=1e-9)
|
171
|
+
assert sol.success
|
172
|
+
assert_equal(sol.status, 1)
|
154
173
|
|
155
174
|
@pytest.mark.thread_unsafe
|
156
175
|
def test_integration():
|
Binary file
|
Binary file
|
scipy/integrate/_tanhsinh.py
CHANGED
@@ -98,8 +98,9 @@ def tanhsinh(f, a, b, *, args=(), log=False, maxlevel=None, minlevel=2,
|
|
98
98
|
Absolute termination tolerance (default: 0) and relative termination
|
99
99
|
tolerance (default: ``eps**0.75``, where ``eps`` is the precision of
|
100
100
|
the result dtype), respectively. Iteration will stop when
|
101
|
-
``res.error < atol
|
102
|
-
described in [1]_ Section 5
|
101
|
+
``res.error < atol`` or ``res.error < res.integral * rtol``. The error
|
102
|
+
estimate is as described in [1]_ Section 5 but with a lower bound of
|
103
|
+
``eps * res.integral``. While not theoretically rigorous or
|
103
104
|
conservative, it is said to work well in practice. Must be non-negative
|
104
105
|
and finite if `log` is False, and must be expressed as the log of a
|
105
106
|
non-negative and finite number if `log` is True.
|
@@ -445,9 +446,9 @@ def tanhsinh(f, a, b, *, args=(), log=False, maxlevel=None, minlevel=2,
|
|
445
446
|
stop[i] = True
|
446
447
|
else:
|
447
448
|
# Terminate if convergence criterion is met
|
448
|
-
|
449
|
-
i = (
|
450
|
-
|
449
|
+
rerr, aerr = _estimate_error(work, xp)
|
450
|
+
i = (rerr < rtol) | (aerr < atol)
|
451
|
+
work.aerr = xp.reshape(xp.astype(aerr, work.dtype), work.Sn.shape)
|
451
452
|
work.status[i] = eim._ECONVERGED
|
452
453
|
stop[i] = True
|
453
454
|
|
@@ -772,22 +773,23 @@ def _estimate_error(work, xp):
|
|
772
773
|
d2 = xp_real(special.logsumexp(xp.stack([work.Sn, Snm2 + work.pi*1j]), axis=0))
|
773
774
|
d3 = log_e1 + xp.max(xp_real(work.fjwj), axis=-1)
|
774
775
|
d4 = work.d4
|
775
|
-
|
776
|
+
d5 = log_e1 + xp.real(work.Sn)
|
777
|
+
temp = xp.where(d1 > -xp.inf, d1 ** 2 / d2, -xp.inf)
|
778
|
+
ds = xp.stack([temp, 2 * d1, d3, d4, d5])
|
776
779
|
aerr = xp.max(ds, axis=0)
|
777
|
-
rerr =
|
780
|
+
rerr = aerr - xp.real(work.Sn)
|
778
781
|
else:
|
779
782
|
# Note: explicit computation of log10 of each of these is unnecessary.
|
780
783
|
d1 = xp.abs(work.Sn - Snm1)
|
781
784
|
d2 = xp.abs(work.Sn - Snm2)
|
782
785
|
d3 = e1 * xp.max(xp.abs(work.fjwj), axis=-1)
|
783
786
|
d4 = work.d4
|
784
|
-
|
785
|
-
|
786
|
-
ds = xp.stack([
|
787
|
+
d5 = e1 * xp.abs(work.Sn)
|
788
|
+
temp = xp.where(d1 > 0, d1**(xp.log(d1)/xp.log(d2)), 0)
|
789
|
+
ds = xp.stack([temp, d1**2, d3, d4, d5])
|
787
790
|
aerr = xp.max(ds, axis=0)
|
788
|
-
rerr =
|
791
|
+
rerr = aerr/xp.abs(work.Sn)
|
789
792
|
|
790
|
-
aerr = xp.reshape(xp.astype(aerr, work.dtype), work.Sn.shape)
|
791
793
|
return rerr, aerr
|
792
794
|
|
793
795
|
|
Binary file
|
Binary file
|
@@ -753,6 +753,16 @@ class TestTanhSinh:
|
|
753
753
|
x[-1] = 1000
|
754
754
|
_tanhsinh(np.sin, 1, x)
|
755
755
|
|
756
|
+
def test_gh_22681_finite_error(self, xp):
|
757
|
+
# gh-22681 noted a case in which the error was NaN on some platforms;
|
758
|
+
# check that this does in fact fail in CI.
|
759
|
+
a = complex(12, -10)
|
760
|
+
b = complex(12, 39)
|
761
|
+
def f(t):
|
762
|
+
return xp.sin(a * (1 - t) + b * t)
|
763
|
+
res = _tanhsinh(f, xp.asarray(0.), xp.asarray(1.), atol=0, rtol=0, maxlevel=10)
|
764
|
+
assert xp.isfinite(res.error)
|
765
|
+
|
756
766
|
|
757
767
|
@array_api_compatible
|
758
768
|
@pytest.mark.usefixtures("skip_xp_backends")
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -213,3 +213,20 @@ class TestInterpolativeDecomposition:
|
|
213
213
|
B = A.copy()
|
214
214
|
interp_decomp(A.T, eps, rand=rand)
|
215
215
|
assert_array_equal(A, B)
|
216
|
+
|
217
|
+
def test_svd_aslinearoperator_shape_check(self):
|
218
|
+
# See gh-issue #22451
|
219
|
+
rng = np.random.default_rng(1744580941832515)
|
220
|
+
x = rng.uniform(size=[7, 5])
|
221
|
+
xl = aslinearoperator(x)
|
222
|
+
u, s, v = pymatrixid.svd(xl, 3)
|
223
|
+
assert_equal(u.shape, (7, 3))
|
224
|
+
assert_equal(s.shape, (3,))
|
225
|
+
assert_equal(v.shape, (5, 3))
|
226
|
+
|
227
|
+
x = rng.uniform(size=[4, 9])
|
228
|
+
xl = aslinearoperator(x)
|
229
|
+
u, s, v = pymatrixid.svd(xl, 2)
|
230
|
+
assert_equal(u.shape, (4, 2))
|
231
|
+
assert_equal(s.shape, (2,))
|
232
|
+
assert_equal(v.shape, (9, 2))
|
Binary file
|
Binary file
|
scipy/ndimage/_ndimage_api.py
CHANGED
@@ -12,4 +12,5 @@ from ._interpolation import * # noqa: F403
|
|
12
12
|
from ._measurements import * # noqa: F403
|
13
13
|
from ._morphology import * # noqa: F403
|
14
14
|
|
15
|
-
|
15
|
+
# '@' due to pytest bug, scipy/scipy#22236
|
16
|
+
__all__ = [s for s in dir() if not s.startswith(('_', '@'))]
|
Binary file
|
Binary file
|
@@ -6,6 +6,9 @@ import re
|
|
6
6
|
import numpy as np
|
7
7
|
import pytest
|
8
8
|
from numpy.testing import suppress_warnings, assert_allclose, assert_array_equal
|
9
|
+
from hypothesis import strategies as st
|
10
|
+
from hypothesis import given
|
11
|
+
import hypothesis.extra.numpy as npst
|
9
12
|
from pytest import raises as assert_raises
|
10
13
|
from scipy import ndimage
|
11
14
|
from scipy._lib._array_api import (
|
@@ -2904,3 +2907,14 @@ def test_gh_22333():
|
|
2904
2907
|
expected = [58, 67, 87, 108, 163, 108, 108, 108, 87]
|
2905
2908
|
actual = ndimage.median_filter(x, size=9, mode='constant')
|
2906
2909
|
assert_array_equal(actual, expected)
|
2910
|
+
|
2911
|
+
|
2912
|
+
@given(x=npst.arrays(dtype=np.float64,
|
2913
|
+
shape=st.integers(min_value=1, max_value=1000)),
|
2914
|
+
size=st.integers(min_value=1, max_value=50),
|
2915
|
+
mode=st.sampled_from(["constant", "mirror", "wrap", "reflect",
|
2916
|
+
"nearest"]),
|
2917
|
+
)
|
2918
|
+
def test_gh_22586_crash_property(x, size, mode):
|
2919
|
+
# property-based test for median_filter resilience to hard crashing
|
2920
|
+
ndimage.median_filter(x, size=size, mode=mode)
|
Binary file
|
scipy/optimize/_bracket.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import numpy as np
|
2
2
|
import scipy._lib._elementwise_iterative_method as eim
|
3
3
|
from scipy._lib._util import _RichResult
|
4
|
-
from scipy._lib._array_api import array_namespace, xp_ravel
|
4
|
+
from scipy._lib._array_api import array_namespace, xp_ravel, xp_default_dtype
|
5
5
|
|
6
6
|
_ELIMITS = -1 # used in _bracket_root
|
7
7
|
_ESTOPONESIDE = 2 # used in _bracket_root
|
@@ -19,8 +19,17 @@ def _bracket_root_iv(func, xl0, xr0, xmin, xmax, factor, args, maxiter):
|
|
19
19
|
if (not xp.isdtype(xl0.dtype, "numeric")
|
20
20
|
or xp.isdtype(xl0.dtype, "complex floating")):
|
21
21
|
raise ValueError('`xl0` must be numeric and real.')
|
22
|
+
if not xp.isdtype(xl0.dtype, "real floating"):
|
23
|
+
xl0 = xp.asarray(xl0, dtype=xp_default_dtype(xp))
|
24
|
+
|
25
|
+
# If xr0 is not supplied, fill with a dummy value for the sake of
|
26
|
+
# broadcasting. We need to wait until xmax has been validated to
|
27
|
+
# compute the default value.
|
28
|
+
xr0_not_supplied = False
|
29
|
+
if xr0 is None:
|
30
|
+
xr0 = xp.nan
|
31
|
+
xr0_not_supplied = True
|
22
32
|
|
23
|
-
xr0 = xl0 + 1 if xr0 is None else xr0
|
24
33
|
xmin = -xp.inf if xmin is None else xmin
|
25
34
|
xmax = xp.inf if xmax is None else xmax
|
26
35
|
factor = 2. if factor is None else factor
|
@@ -45,6 +54,12 @@ def _bracket_root_iv(func, xl0, xr0, xmin, xmax, factor, args, maxiter):
|
|
45
54
|
if not xp.all(factor > 1):
|
46
55
|
raise ValueError('All elements of `factor` must be greater than 1.')
|
47
56
|
|
57
|
+
# Calculate the default value of xr0 if a value has not been supplied.
|
58
|
+
# Be careful to ensure xr0 is not larger than xmax.
|
59
|
+
if xr0_not_supplied:
|
60
|
+
xr0 = xl0 + xp.minimum((xmax - xl0)/ 8, xp.asarray(1.0))
|
61
|
+
xr0 = xp.astype(xr0, xl0.dtype, copy=False)
|
62
|
+
|
48
63
|
maxiter = xp.asarray(maxiter)
|
49
64
|
message = '`maxiter` must be a non-negative integer.'
|
50
65
|
if (not xp.isdtype(maxiter.dtype, "numeric") or maxiter.shape != tuple()
|
@@ -281,14 +296,22 @@ def _bracket_root(func, xl0, xr0=None, *, xmin=None, xmax=None, factor=None,
|
|
281
296
|
# `work.status`.
|
282
297
|
# Get the integer indices of the elements that can also stop
|
283
298
|
also_stop = (work.active[i] + work.n) % (2*work.n)
|
284
|
-
# Check whether they are still active.
|
285
|
-
#
|
286
|
-
#
|
299
|
+
# Check whether they are still active. We want to find the indices
|
300
|
+
# in work.active where the associated values in work.active are
|
301
|
+
# contained in also_stop. xp.searchsorted let's us take advantage
|
302
|
+
# of work.active being sorted, but requires some hackery because
|
303
|
+
# searchsorted solves the separate but related problem of finding
|
304
|
+
# the indices where the values in also_stop should be added to
|
305
|
+
# maintain sorted order.
|
287
306
|
j = xp.searchsorted(work.active, also_stop)
|
288
307
|
# If the location exceeds the length of the `work.active`, they are
|
289
|
-
# not there.
|
290
|
-
|
291
|
-
#
|
308
|
+
# not there. This happens when a value in also_stop is larger than
|
309
|
+
# the greatest value in work.active. This case needs special handling
|
310
|
+
# because we cannot simply check that also_stop == work.active[j].
|
311
|
+
mask = j < work.active.shape[0]
|
312
|
+
# Note that we also have to use the mask to filter also_stop to ensure
|
313
|
+
# that also_stop and j will still have the same shape.
|
314
|
+
j, also_stop = j[mask], also_stop[mask]
|
292
315
|
j = j[also_stop == work.active[j]]
|
293
316
|
# Now convert these to boolean indices to use with `work.status`.
|
294
317
|
i = xp.zeros_like(stop)
|
@@ -407,6 +430,8 @@ def _bracket_minimum_iv(func, xm0, xl0, xr0, xmin, xmax, factor, args, maxiter):
|
|
407
430
|
if (not xp.isdtype(xm0.dtype, "numeric")
|
408
431
|
or xp.isdtype(xm0.dtype, "complex floating")):
|
409
432
|
raise ValueError('`xm0` must be numeric and real.')
|
433
|
+
if not xp.isdtype(xm0.dtype, "real floating"):
|
434
|
+
xm0 = xp.asarray(xm0, dtype=xp_default_dtype(xp))
|
410
435
|
|
411
436
|
xmin = -xp.inf if xmin is None else xmin
|
412
437
|
xmax = xp.inf if xmax is None else xmax
|
@@ -457,8 +482,10 @@ def _bracket_minimum_iv(func, xm0, xl0, xr0, xmin, xmax, factor, args, maxiter):
|
|
457
482
|
# of (xmin, xmax).
|
458
483
|
if xl0_not_supplied:
|
459
484
|
xl0 = xm0 - xp.minimum((xm0 - xmin)/16, xp.asarray(0.5))
|
485
|
+
xl0 = xp.astype(xl0, xm0.dtype, copy=False)
|
460
486
|
if xr0_not_supplied:
|
461
487
|
xr0 = xm0 + xp.minimum((xmax - xm0)/16, xp.asarray(0.5))
|
488
|
+
xr0 = xp.astype(xr0, xm0.dtype, copy=False)
|
462
489
|
|
463
490
|
maxiter = xp.asarray(maxiter)
|
464
491
|
message = '`maxiter` must be a non-negative integer.'
|
Binary file
|
Binary file
|
@@ -264,11 +264,13 @@ def _highs_wrapper(c, indptr, indices, data, lhs, rhs, lb, ub, integrality, opti
|
|
264
264
|
|
265
265
|
# Lagrangians for bounds based on column statuses
|
266
266
|
marg_bnds = np.zeros((2, numcol))
|
267
|
+
basis_col_status = basis.col_status
|
268
|
+
solution_col_dual = solution.col_dual
|
267
269
|
for ii in range(numcol):
|
268
|
-
if
|
269
|
-
marg_bnds[0, ii] =
|
270
|
-
elif
|
271
|
-
marg_bnds[1, ii] =
|
270
|
+
if basis_col_status[ii] == _h.HighsBasisStatus.kLower:
|
271
|
+
marg_bnds[0, ii] = solution_col_dual[ii]
|
272
|
+
elif basis_col_status[ii] == _h.HighsBasisStatus.kUpper:
|
273
|
+
marg_bnds[1, ii] = solution_col_dual[ii]
|
272
274
|
|
273
275
|
res.update(
|
274
276
|
{
|
scipy/optimize/_linprog_highs.py
CHANGED
@@ -23,13 +23,13 @@ from ._highspy._core import(
|
|
23
23
|
HighsDebugLevel,
|
24
24
|
ObjSense,
|
25
25
|
HighsModelStatus,
|
26
|
-
|
27
|
-
from ._highspy._core.simplex_constants import (
|
28
|
-
SimplexStrategy,
|
29
|
-
SimplexEdgeWeightStrategy,
|
26
|
+
simplex_constants as s_c, # [1]
|
30
27
|
)
|
31
28
|
from scipy.sparse import csc_matrix, vstack, issparse
|
32
29
|
|
30
|
+
# [1]: Directly importing from "._highspy._core.simplex_constants"
|
31
|
+
# causes problems when reloading.
|
32
|
+
# See https://github.com/scipy/scipy/pull/22869 for details.
|
33
33
|
|
34
34
|
def _highs_to_scipy_status_message(highs_status, highs_message):
|
35
35
|
"""Converts HiGHS status number/message to SciPy status number/message"""
|
@@ -293,13 +293,13 @@ def _linprog_highs(lp, solver, time_limit=None, presolve=True,
|
|
293
293
|
simplex_dual_edge_weight_strategy,
|
294
294
|
'simplex_dual_edge_weight_strategy',
|
295
295
|
choices={'dantzig': \
|
296
|
-
SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategyDantzig,
|
296
|
+
s_c.SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategyDantzig,
|
297
297
|
'devex': \
|
298
|
-
SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategyDevex,
|
298
|
+
s_c.SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategyDevex,
|
299
299
|
'steepest-devex': \
|
300
|
-
SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategyChoose,
|
300
|
+
s_c.SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategyChoose,
|
301
301
|
'steepest': \
|
302
|
-
SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategySteepestEdge,
|
302
|
+
s_c.SimplexEdgeWeightStrategy.kSimplexEdgeWeightStrategySteepestEdge,
|
303
303
|
None: None})
|
304
304
|
|
305
305
|
c, A_ub, b_ub, A_eq, b_eq, bounds, x0, integrality = lp
|
@@ -334,7 +334,7 @@ def _linprog_highs(lp, solver, time_limit=None, presolve=True,
|
|
334
334
|
'primal_feasibility_tolerance': primal_feasibility_tolerance,
|
335
335
|
'simplex_dual_edge_weight_strategy':
|
336
336
|
simplex_dual_edge_weight_strategy_enum,
|
337
|
-
'simplex_strategy': SimplexStrategy.kSimplexStrategyDual,
|
337
|
+
'simplex_strategy': s_c.SimplexStrategy.kSimplexStrategyDual,
|
338
338
|
'ipm_iteration_limit': maxiter,
|
339
339
|
'simplex_iteration_limit': maxiter,
|
340
340
|
'mip_rel_gap': mip_rel_gap,
|
scipy/optimize/_linprog_util.py
CHANGED
@@ -1409,9 +1409,10 @@ def _postsolve(x, postsolve_args, complete=False):
|
|
1409
1409
|
x = rev(x)
|
1410
1410
|
|
1411
1411
|
fun = x.dot(c)
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1412
|
+
with np.errstate(invalid="ignore"):
|
1413
|
+
slack = b_ub - A_ub.dot(x) # report slack for ORIGINAL UB constraints
|
1414
|
+
# report residuals of ORIGINAL EQ constraints
|
1415
|
+
con = b_eq - A_eq.dot(x)
|
1415
1416
|
|
1416
1417
|
return x, fun, slack, con
|
1417
1418
|
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -352,6 +352,41 @@ class TestBracketRoot:
|
|
352
352
|
xmin=1)
|
353
353
|
assert not res.success
|
354
354
|
|
355
|
+
def test_bug_fixes(self):
|
356
|
+
# 1. Bug in double sided bracket search.
|
357
|
+
# Happened in some cases where there are terminations on one side
|
358
|
+
# after corresponding searches on other side failed due to reaching the
|
359
|
+
# boundary.
|
360
|
+
|
361
|
+
# https://github.com/scipy/scipy/pull/22560#discussion_r1962853839
|
362
|
+
def f(x, p):
|
363
|
+
return np.exp(x) - p
|
364
|
+
|
365
|
+
p = np.asarray([0.29, 0.35])
|
366
|
+
res = _bracket_root(f, xl0=-1, xmin=-np.inf, xmax=0, args=(p, ))
|
367
|
+
|
368
|
+
# https://github.com/scipy/scipy/pull/22560/files#r1962952517
|
369
|
+
def f(x, p, c):
|
370
|
+
return np.exp(x*c) - p
|
371
|
+
|
372
|
+
p = [0.32061201, 0.39175242, 0.40047535, 0.50527218, 0.55654373,
|
373
|
+
0.11911647, 0.37507896, 0.66554191]
|
374
|
+
c = [1., -1., 1., 1., -1., 1., 1., 1.]
|
375
|
+
xl0 = [-7.63108551, 3.27840947, -8.36968526, -1.78124372,
|
376
|
+
0.92201295, -2.48930123, -0.66733533, -0.44606749]
|
377
|
+
xr0 = [-6.63108551, 4.27840947, -7.36968526, -0.78124372,
|
378
|
+
1.92201295, -1.48930123, 0., 0.]
|
379
|
+
xmin = [-np.inf, 0., -np.inf, -np.inf, 0., -np.inf, -np.inf,
|
380
|
+
-np.inf]
|
381
|
+
xmax = [0., np.inf, 0., 0., np.inf, 0., 0., 0.]
|
382
|
+
|
383
|
+
res = _bracket_root(f, xl0=xl0, xr0=xr0, xmin=xmin, xmax=xmax, args=(p, c))
|
384
|
+
|
385
|
+
# 2. Default xl0 + 1 for xr0 exceeds xmax.
|
386
|
+
# https://github.com/scipy/scipy/pull/22560#discussion_r1962947434
|
387
|
+
res = _bracket_root(lambda x: x + 0.25, xl0=-0.5, xmin=-np.inf, xmax=0)
|
388
|
+
assert res.success
|
389
|
+
|
355
390
|
|
356
391
|
@pytest.mark.skip_xp_backends('array_api_strict', reason=array_api_strict_skip_reason)
|
357
392
|
@pytest.mark.skip_xp_backends('jax.numpy', reason=jax_skip_reason)
|
Binary file
|