Skip to content

Commit ed7c850

Browse files
Merge pull request scipy#22233 from tylerjereddy/treddy_backports_1.15.0_final
* DEP: linalg.solve_toeplitz/matmul_toeplitz: warn on n-D `c`, `r` (scipy#22193) * DEP: linalg.solve_toeplitz: warn on n-D c, r * MAINT: linalg.matmul_toeplitz: add admonition to documentation; test warning * DOC: update release notes [docs only] * DOC: differentiate.jacobian: correct/improve documentation about callable interface [docs only] * Update scipy/differentiate/_differentiate.py [docs only] * DOC: Update 1.15.0 relnotes * Update the SciPy `1.15.0` release notes following additional backport activity. * MAINT: PR 22233 wheel build [wheel build] * Test wheel builds in above PR before release process starts. [wheel build] --------- Co-authored-by: Matt Haberland <[email protected]>
2 parents 256c1a2 + 2e2f2cd commit ed7c850

File tree

6 files changed

+100
-44
lines changed

6 files changed

+100
-44
lines changed

doc/source/release/1.15.0-notes.rst

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
SciPy 1.15.0 Release Notes
33
==========================
44

5-
.. note:: SciPy 1.15.0 is not released yet!
6-
75
.. contents::
86

97
SciPy 1.15.0 is the culmination of 6 months of hard work. It contains
@@ -376,9 +374,9 @@ with support added for SciPy ``1.15.0`` include:
376374
and for other backends will transit via NumPy arrays on the host.
377375

378376

379-
*******************
380-
Deprecated features
381-
*******************
377+
**************************************
378+
Deprecated features and future changes
379+
**************************************
382380
- Functions `scipy.linalg.interpolative.rand` and
383381
`scipy.linalg.interpolative.seed` have been deprecated and will be removed
384382
in SciPy ``1.17.0``.
@@ -388,16 +386,15 @@ Deprecated features
388386
- `scipy.spatial.distance.kulczynski1` and
389387
`scipy.spatial.distance.sokalmichener` were deprecated and will be removed
390388
in SciPy ``1.17.0``.
391-
- `scipy.stats.find_repeats` is deprecated as of SciPy ``1.15.0`` and will be
389+
- `scipy.stats.find_repeats` is deprecated and will be
392390
removed in SciPy ``1.17.0``. Please use
393391
``numpy.unique``/``numpy.unique_counts`` instead.
394392
- `scipy.linalg.kron` is deprecated in favour of ``numpy.kron``.
395393
- Using object arrays and longdouble arrays in `scipy.signal`
396394
convolution/correlation functions (`scipy.signal.correlate`,
397395
`scipy.signal.convolve` and `scipy.signal.choose_conv_method`) and
398396
filtering functions (`scipy.signal.lfilter`, `scipy.signal.sosfilt`) has
399-
been deprecated as of SciPy ``1.15.0`` and will be removed in SciPy
400-
``1.17.0``.
397+
been deprecated and will be removed in SciPy ``1.17.0``.
401398
- `scipy.stats.linregress` has deprecated one-argument use; the two
402399
variables must be specified as separate arguments.
403400
- ``scipy.stats.trapz`` is deprecated in favor of `scipy.stats.trapezoid`.
@@ -406,8 +403,9 @@ Deprecated features
406403
`scipy.special.assoc_legendre_p_all`.
407404
- `scipy.special.sph_harm` has been deprecated in favor of
408405
`scipy.special.sph_harm_y`.
409-
- The raveling of multi-dimensional input by `scipy.linalg.toeplitz` has
410-
been deprecated. It will support batching in SciPy ``1.17.0``.
406+
- Multi-dimensional ``r`` and ``c`` arrays passed to `scipy.linalg.toeplitz`,
407+
`scipy.linalg.matmul_toeplitz`, or `scipy.linalg.solve_toeplitz` will be
408+
treated as batches of 1-D coefficients beginning in SciPy ``1.17.0``.
411409
- The ``random_state`` and ``permutations`` arguments of
412410
`scipy.stats.ttest_ind` are deprecated. Use ``method`` to perform a
413411
permutation test, instead.
@@ -557,11 +555,11 @@ Authors (commits)
557555
* Sahil Garje (1) +
558556
* Gabriel Gerlero (2)
559557
* Yotam Gingold (1) +
560-
* Ralf Gommers (110)
558+
* Ralf Gommers (111)
561559
* Rohit Goswami (62)
562560
* Anil Gurses (1) +
563561
* Oscar Gustafsson (1) +
564-
* Matt Haberland (389)
562+
* Matt Haberland (392)
565563
* Matt Hall (1) +
566564
* Joren Hammudoglu (6) +
567565
* CY Han (1) +
@@ -616,7 +614,7 @@ Authors (commits)
616614
* Tom M. Ragonneau (2)
617615
* Peter Ralph (1) +
618616
* Stephan Rave (1) +
619-
* Tyler Reddy (182)
617+
* Tyler Reddy (192)
620618
* redha2404 (2) +
621619
* Ritvik1sharma (1) +
622620
* Érico Nogueira Rolim (1) +
@@ -939,9 +937,11 @@ Issues closed for 1.15.0
939937
* `#22097 <https://github.com/scipy/scipy/issues/22097>`__: DEP: ``interpolate.interpnd.GradientEstimationWarning`` still...
940938
* `#22112 <https://github.com/scipy/scipy/issues/22112>`__: BUG/DOC: sparse: ND COO unexpected behaviour 1.15.0rc1
941939
* `#22123 <https://github.com/scipy/scipy/issues/22123>`__: DOC: stats: random variable transition guide launches wrong notebook
940+
* `#22128 <https://github.com/scipy/scipy/issues/22128>`__: BUG/DOC: it's not clear how to use ``differentiate.jacobian``...
942941
* `#22137 <https://github.com/scipy/scipy/issues/22137>`__: BUG: ``stats._distribution_infrastructure._Domain.symbols`` class...
943942
* `#22143 <https://github.com/scipy/scipy/issues/22143>`__: BUG: Fail to call ``BSpline`` after unpickling with ``mmap_mode="r"``
944943
* `#22146 <https://github.com/scipy/scipy/issues/22146>`__: BUG:``stats.ContinuousDistribution.llf``\ : should not be public
944+
* `#22204 <https://github.com/scipy/scipy/issues/22204>`__: BUG: signal.ShortTimeFFT: ``istft`` with ``mfft > len(win)``...
945945

946946
************************
947947
Pull requests for 1.15.0
@@ -1368,6 +1368,7 @@ Pull requests for 1.15.0
13681368
* `#21668 <https://github.com/scipy/scipy/pull/21668>`__: BUG: fft.fht: set ``u.imag[-1] = 0`` only when ``n`` is even
13691369
* `#21672 <https://github.com/scipy/scipy/pull/21672>`__: BUG: ndimage: fix 0d arrays in ``_normalize_sequence``
13701370
* `#21673 <https://github.com/scipy/scipy/pull/21673>`__: BUG: signal.ShortTimeFFT: fix multichannel roundtrip with ``mfft``...
1371+
* `#21678 <https://github.com/scipy/scipy/pull/21678>`__: BUG: fix ``nan`` output of ``special.betaincinv``
13711372
* `#21680 <https://github.com/scipy/scipy/pull/21680>`__: MAINT:integrate: Silence a few QUADPACK compiler warnings
13721373
* `#21682 <https://github.com/scipy/scipy/pull/21682>`__: DOC: Reduce duplication in user guide
13731374
* `#21686 <https://github.com/scipy/scipy/pull/21686>`__: BUG: signal: int handling for ``resample_poly``
@@ -1573,11 +1574,15 @@ Pull requests for 1.15.0
15731574
* `#22135 <https://github.com/scipy/scipy/pull/22135>`__: MAINT: _lib: add missing f string to _deprecate_positional_args
15741575
* `#22139 <https://github.com/scipy/scipy/pull/22139>`__: MAINT: stats._SimpleDomain: ensure that instances do not share...
15751576
* `#22149 <https://github.com/scipy/scipy/pull/22149>`__: MAINT: stats.ContinuousDistribution.llf: remove method
1577+
* `#22150 <https://github.com/scipy/scipy/pull/22150>`__: MAINT: SciPy 1.15.0rc2 backports
15761578
* `#22156 <https://github.com/scipy/scipy/pull/22156>`__: DEP: deprecation warnings for ``special.lpn`` and ``[c]lpmn``
15771579
* `#22158 <https://github.com/scipy/scipy/pull/22158>`__: MAINT: accept ndarray subclasses in interpolate._dierckx
15781580
* `#22162 <https://github.com/scipy/scipy/pull/22162>`__: TYP: temporarily ignore the ``numpy==2.2.1`` mypy errors
15791581
* `#22167 <https://github.com/scipy/scipy/pull/22167>`__: DEP: special: deprecation warning for ``sph_harm`` + comments
15801582
* `#22168 <https://github.com/scipy/scipy/pull/22168>`__: BUG: fix incorrect values in factorial for 0 with uint dtypes
15811583
* `#22175 <https://github.com/scipy/scipy/pull/22175>`__: MAINT: stats: fix thread-safety issues under free-threaded CPython
15821584
* `#22177 <https://github.com/scipy/scipy/pull/22177>`__: MAINT: fix extension module not declaring free-threading support,...
1585+
* `#22181 <https://github.com/scipy/scipy/pull/22181>`__: REL: set 1.15.0rc3 unreleased
1586+
* `#22193 <https://github.com/scipy/scipy/pull/22193>`__: DEP: linalg.solve_toeplitz/matmul_toeplitz: warn on n-D ``c``\...
1587+
* `#22225 <https://github.com/scipy/scipy/pull/22225>`__: DOC: differentiate.jacobian: correct/improve documentation about...
15831588

scipy/differentiate/_differentiate.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -802,27 +802,47 @@ def jacobian(f, x, *, tolerances=None, maxiter=10, order=8, initial_step=0.5,
802802
Notes
803803
-----
804804
Suppose we wish to evaluate the Jacobian of a function
805-
:math:`f: \mathbf{R}^m \rightarrow \mathbf{R}^n`, and assign to variables
805+
:math:`f: \mathbf{R}^m \rightarrow \mathbf{R}^n`. Assign to variables
806806
``m`` and ``n`` the positive integer values of :math:`m` and :math:`n`,
807-
respectively. If we wish to evaluate the Jacobian at a single point,
808-
then:
807+
respectively, and let ``...`` represent an arbitrary tuple of integers.
808+
If we wish to evaluate the Jacobian at a single point, then:
809809
810810
- argument `x` must be an array of shape ``(m,)``
811-
- argument `f` must be vectorized to accept an array of shape ``(m, p)``.
812-
The first axis represents the :math:`m` inputs of :math:`f`; the second
813-
is for evaluating the function at multiple points in a single call.
814-
- argument `f` must return an array of shape ``(n, p)``. The first
815-
axis represents the :math:`n` outputs of :math:`f`; the second
816-
is for the result of evaluating the function at multiple points.
811+
- argument `f` must be vectorized to accept an array of shape ``(m, ...)``.
812+
The first axis represents the :math:`m` inputs of :math:`f`; the remainder
813+
are for evaluating the function at multiple points in a single call.
814+
- argument `f` must return an array of shape ``(n, ...)``. The first
815+
axis represents the :math:`n` outputs of :math:`f`; the remainder
816+
are for the result of evaluating the function at multiple points.
817817
- attribute ``df`` of the result object will be an array of shape ``(n, m)``,
818818
the Jacobian.
819819
820820
This function is also vectorized in the sense that the Jacobian can be
821821
evaluated at ``k`` points in a single call. In this case, `x` would be an
822822
array of shape ``(m, k)``, `f` would accept an array of shape
823-
``(m, k, p)`` and return an array of shape ``(n, k, p)``, and the ``df``
823+
``(m, k, ...)`` and return an array of shape ``(n, k, ...)``, and the ``df``
824824
attribute of the result would have shape ``(n, m, k)``.
825825
826+
Suppose the desired callable ``f_not_vectorized`` is not vectorized; it can
827+
only accept an array of shape ``(m,)``. A simple solution to satisfy the required
828+
interface is to wrap ``f_not_vectorized`` as follows::
829+
830+
def f(x):
831+
return np.apply_along_axis(f_not_vectorized, axis=0, arr=x)
832+
833+
Alternatively, suppose the desired callable ``f_vec_q`` is vectorized, but
834+
only for 2-D arrays of shape ``(m, q)``. To satisfy the required interface,
835+
consider::
836+
837+
def f(x):
838+
m, batch = x.shape[0], x.shape[1:] # x.shape is (m, ...)
839+
x = np.reshape(x, (m, -1)) # `-1` is short for q = prod(batch)
840+
res = f_vec_q(x) # pass shape (m, q) to function
841+
n = res.shape[0]
842+
return np.reshape(res, (n,) + batch) # return shape (n, ...)
843+
844+
Then pass the wrapped callable ``f`` as the first argument of `jacobian`.
845+
826846
References
827847
----------
828848
.. [1] Jacobian matrix and determinant, *Wikipedia*,

scipy/linalg/_basic.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# w/ additions by Travis Oliphant, March 2002
55
# and Jake Vanderplas, August 2012
66

7+
import warnings
78
from warnings import warn
89
from itertools import product
910
import numpy as np
@@ -782,21 +783,25 @@ def solveh_banded(ab, b, overwrite_ab=False, overwrite_b=False, lower=False,
782783

783784

784785
def solve_toeplitz(c_or_cr, b, check_finite=True):
785-
"""Solve a Toeplitz system using Levinson Recursion
786+
r"""Solve a Toeplitz system using Levinson Recursion
786787
787788
The Toeplitz matrix has constant diagonals, with c as its first column
788789
and r as its first row. If r is not given, ``r == conjugate(c)`` is
789790
assumed.
790791
792+
.. warning::
793+
794+
Beginning in SciPy 1.17, multidimensional input will be treated as a batch,
795+
not ``ravel``\ ed. To preserve the existing behavior, ``ravel`` arguments
796+
before passing them to `solve_toeplitz`.
797+
791798
Parameters
792799
----------
793800
c_or_cr : array_like or tuple of (array_like, array_like)
794-
The vector ``c``, or a tuple of arrays (``c``, ``r``). Whatever the
795-
actual shape of ``c``, it will be converted to a 1-D array. If not
801+
The vector ``c``, or a tuple of arrays (``c``, ``r``). If not
796802
supplied, ``r = conjugate(c)`` is assumed; in this case, if c[0] is
797803
real, the Toeplitz matrix is Hermitian. r[0] is ignored; the first row
798-
of the Toeplitz matrix is ``[c[0], r[1:]]``. Whatever the actual shape
799-
of ``r``, it will be converted to a 1-D array.
804+
of the Toeplitz matrix is ``[c[0], r[1:]]``.
800805
b : (M,) or (M, K) array_like
801806
Right-hand side in ``T x = b``.
802807
check_finite : bool, optional
@@ -1915,12 +1920,21 @@ def _validate_args_for_toeplitz_ops(c_or_cr, b, check_finite, keep_b_shape,
19151920

19161921
if isinstance(c_or_cr, tuple):
19171922
c, r = c_or_cr
1918-
c = _asarray_validated(c, check_finite=check_finite).ravel()
1919-
r = _asarray_validated(r, check_finite=check_finite).ravel()
1923+
c = _asarray_validated(c, check_finite=check_finite)
1924+
r = _asarray_validated(r, check_finite=check_finite)
19201925
else:
1921-
c = _asarray_validated(c_or_cr, check_finite=check_finite).ravel()
1926+
c = _asarray_validated(c_or_cr, check_finite=check_finite)
19221927
r = c.conjugate()
19231928

1929+
if c.ndim > 1 or r.ndim > 1:
1930+
msg = ("Beginning in SciPy 1.17, multidimensional input will be treated as a "
1931+
"batch, not `ravel`ed. To preserve the existing behavior and silence "
1932+
"this warning, `ravel` arguments before passing them to "
1933+
"`toeplitz`, `matmul_toeplitz`, and `solve_toeplitz`.")
1934+
warnings.warn(msg, FutureWarning, stacklevel=2)
1935+
c = c.ravel()
1936+
r = r.ravel()
1937+
19241938
if b is None:
19251939
raise ValueError('`b` must be an array, not None.')
19261940

@@ -1944,7 +1958,7 @@ def _validate_args_for_toeplitz_ops(c_or_cr, b, check_finite, keep_b_shape,
19441958

19451959

19461960
def matmul_toeplitz(c_or_cr, x, check_finite=False, workers=None):
1947-
"""Efficient Toeplitz Matrix-Matrix Multiplication using FFT
1961+
r"""Efficient Toeplitz Matrix-Matrix Multiplication using FFT
19481962
19491963
This function returns the matrix multiplication between a Toeplitz
19501964
matrix and a dense matrix.
@@ -1953,15 +1967,19 @@ def matmul_toeplitz(c_or_cr, x, check_finite=False, workers=None):
19531967
and r as its first row. If r is not given, ``r == conjugate(c)`` is
19541968
assumed.
19551969
1970+
.. warning::
1971+
1972+
Beginning in SciPy 1.17, multidimensional input will be treated as a batch,
1973+
not ``ravel``\ ed. To preserve the existing behavior, ``ravel`` arguments
1974+
before passing them to `matmul_toeplitz`.
1975+
19561976
Parameters
19571977
----------
19581978
c_or_cr : array_like or tuple of (array_like, array_like)
1959-
The vector ``c``, or a tuple of arrays (``c``, ``r``). Whatever the
1960-
actual shape of ``c``, it will be converted to a 1-D array. If not
1979+
The vector ``c``, or a tuple of arrays (``c``, ``r``). If not
19611980
supplied, ``r = conjugate(c)`` is assumed; in this case, if c[0] is
19621981
real, the Toeplitz matrix is Hermitian. r[0] is ignored; the first row
1963-
of the Toeplitz matrix is ``[c[0], r[1:]]``. Whatever the actual shape
1964-
of ``r``, it will be converted to a 1-D array.
1982+
of the Toeplitz matrix is ``[c[0], r[1:]]``.
19651983
x : (M,) or (M, K) array_like
19661984
Matrix with which to multiply.
19671985
check_finite : bool, optional

scipy/linalg/_special_matrices.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,17 @@ def toeplitz(c, r=None):
2727
Parameters
2828
----------
2929
c : array_like
30-
First column of the matrix. Whatever the actual shape of `c`, it
31-
will be converted to a 1-D array.
30+
First column of the matrix.
3231
r : array_like, optional
3332
First row of the matrix. If None, ``r = conjugate(c)`` is assumed;
3433
in this case, if c[0] is real, the result is a Hermitian matrix.
3534
r[0] is ignored; the first row of the returned matrix is
36-
``[c[0], r[1:]]``. Whatever the actual shape of `r`, it will be
37-
converted to a 1-D array.
35+
``[c[0], r[1:]]``.
3836
3937
.. warning::
4038
4139
Beginning in SciPy 1.17, multidimensional input will be treated as a batch,
42-
not ``ravel``\ ed. To preserve the existing behavior, ``ravel`` aruments
40+
not ``ravel``\ ed. To preserve the existing behavior, ``ravel`` arguments
4341
before passing them to `toeplitz`.
4442
4543
Returns
@@ -81,7 +79,7 @@ def toeplitz(c, r=None):
8179
if c.ndim > 1 or r.ndim > 1:
8280
msg = ("Beginning in SciPy 1.17, multidimensional input will be treated as a "
8381
"batch, not `ravel`ed. To preserve the existing behavior and silence "
84-
"this warning, `ravel` aruments before passing them to `toeplitz`.")
82+
"this warning, `ravel` arguments before passing them to `toeplitz`.")
8583
warnings.warn(msg, FutureWarning, stacklevel=2)
8684

8785
c, r = c.ravel(), r.ravel()

scipy/linalg/tests/test_matmul_toeplitz.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,12 @@ def test_exceptions(self):
125125

126126
# For toeplitz matrices, matmul_toeplitz() should be equivalent to @.
127127
def do(self, x, c, r=None, check_finite=False, workers=None):
128+
c = np.ravel(c)
128129
if r is None:
129130
actual = matmul_toeplitz(c, x, check_finite, workers)
130131
else:
131132
r = np.ravel(r)
132133
actual = matmul_toeplitz((c, r), x, check_finite)
133-
desired = toeplitz(np.ravel(c), r) @ x
134+
desired = toeplitz(c, r) @ x
134135
assert_allclose(actual, desired,
135136
rtol=self.tolerance, atol=self.tolerance)

scipy/linalg/tests/test_solve_toeplitz.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33
import numpy as np
44
from scipy.linalg._solve_toeplitz import levinson
5-
from scipy.linalg import solve, toeplitz, solve_toeplitz
5+
from scipy.linalg import solve, toeplitz, solve_toeplitz, matmul_toeplitz
66
from numpy.testing import assert_equal, assert_allclose
77

88
import pytest
@@ -134,3 +134,17 @@ def test_empty(dt_c, dt_b):
134134
x1 = solve_toeplitz(c, b)
135135
assert x1.shape == (0, 0)
136136
assert x1.dtype == x.dtype
137+
138+
139+
@pytest.mark.parametrize('fun', [solve_toeplitz, matmul_toeplitz])
140+
def test_nd_FutureWarning(fun):
141+
# Test future warnings with n-D `c`/`r`
142+
rng = np.random.default_rng(283592436523456)
143+
c = rng.random((2, 3, 4))
144+
r = rng.random((2, 3, 4))
145+
b_or_x = rng.random(24)
146+
message = "Beginning in SciPy 1.17, multidimensional input will be..."
147+
with pytest.warns(FutureWarning, match=message):
148+
fun(c, b_or_x)
149+
with pytest.warns(FutureWarning, match=message):
150+
fun((c, r), b_or_x)

0 commit comments

Comments
 (0)