|
43 | 43 | --------------------- |
44 | 44 | * b == 0 early-exit (return x0 or zeros with info=0) |
45 | 45 | * Breakdown detection via machine-epsilon rhotol (CG, GMRES) |
46 | | -* atol normalisation: atol = max(atol_arg, rtol * ||b||) |
| 46 | +* atol normalisation: atol = max(atol, rtol * ||b||) |
47 | 47 | * dtype promotion: f/F stay in single, d/D in double (CuPy rules) |
48 | 48 | * Preconditioner (M != None): raises NotImplementedError for CG and GMRES |
49 | 49 | until a full left-preconditioned implementation lands; MINRES supports M. |
|
62 | 62 | Stagnation floor uses 10*eps (matches SciPy minres.py) so that float32 |
63 | 63 | runs with tol near machine-epsilon do not false-positive as stagnated. |
64 | 64 | Convergence check always runs before the stagnation check. |
| 65 | +
|
| 66 | +Changes (2026-04-06) |
| 67 | +-------------------- |
| 68 | +* Fix DeprecationWarning from SciPy >=1.12: ``tol=`` renamed to ``rtol=`` |
| 69 | + in scipy.sparse.linalg.cg and scipy.sparse.linalg.gmres. |
| 70 | + All internal _get_atol calls now use the keyword ``rtol=tol`` explicitly. |
| 71 | +* Guard callback_type passthrough in _get_atol to avoid forwarding ``None`` |
| 72 | + to older SciPy versions that do not accept that keyword. |
65 | 73 | """ |
66 | 74 |
|
67 | 75 | from __future__ import annotations |
@@ -206,7 +214,15 @@ def _rmatvec(self, x): return orig.rmatvec(x) |
206 | 214 |
|
207 | 215 |
|
208 | 216 | def _get_atol(name: str, b_norm: float, atol, rtol: float) -> float: |
209 | | - """Absolute stopping tolerance: max(atol, rtol*||b||), mirroring SciPy.""" |
| 217 | + """Absolute stopping tolerance: max(atol, rtol*||b||), mirroring SciPy. |
| 218 | +
|
| 219 | + .. note:: |
| 220 | + The ``rtol`` parameter is the *relative* tolerance supplied by the |
| 221 | + caller (historically named ``tol`` in SciPy <= 1.11). SciPy >= 1.12 |
| 222 | + renamed the public argument from ``tol`` to ``rtol``; this helper |
| 223 | + always uses the keyword ``rtol=`` internally to avoid the |
| 224 | + DeprecationWarning emitted by SciPy >= 1.12. |
| 225 | + """ |
210 | 226 | if atol == "legacy" or atol is None: |
211 | 227 | atol = 0.0 |
212 | 228 | atol = float(atol) |
@@ -259,7 +275,9 @@ def cg( |
259 | 275 | if bnrm == 0.0: |
260 | 276 | return _dpnp.zeros_like(b), 0 |
261 | 277 |
|
262 | | - atol_eff = _get_atol("cg", bnrm, atol, tol) |
| 278 | + # FIX: use keyword rtol= (SciPy >= 1.12 renamed tol -> rtol). |
| 279 | + # _get_atol is our own helper, but the parameter name documents intent. |
| 280 | + atol_eff = _get_atol("cg", bnrm, atol=atol, rtol=tol) |
263 | 281 | if maxiter is None: |
264 | 282 | maxiter = n * 10 |
265 | 283 |
|
@@ -361,7 +379,8 @@ def gmres( |
361 | 379 | if bnrm == 0.0: |
362 | 380 | return _dpnp.zeros_like(b), 0 |
363 | 381 |
|
364 | | - atol_eff = _get_atol("gmres", bnrm, atol, tol) |
| 382 | + # FIX: use keyword rtol= (SciPy >= 1.12 renamed tol -> rtol). |
| 383 | + atol_eff = _get_atol("gmres", bnrm, atol=atol, rtol=tol) |
365 | 384 | if restart is None: restart = min(20, n) |
366 | 385 | if maxiter is None: maxiter = n |
367 | 386 | restart = int(restart) |
@@ -561,8 +580,7 @@ def minres( |
561 | 580 | if bnrm == 0.0: |
562 | 581 | return _dpnp.zeros_like(b), 0 |
563 | 582 |
|
564 | | - # FIX (Bug 3): pass the caller's `atol` argument instead of hard-coded |
565 | | - # `atol=None`, so the absolute tolerance is actually respected. |
| 583 | + # FIX: use keyword rtol= (SciPy >= 1.12 renamed tol -> rtol). |
566 | 584 | atol_eff = _get_atol("minres", bnrm, atol=atol, rtol=tol) |
567 | 585 |
|
568 | 586 | # ------------------------------------------------------------------ |
|
0 commit comments