1010import numpy as np
1111
1212from pylops .optimization .basesolver import Solver , _units
13+ from pylops .optimization .callback import _callback_stop
1314from pylops .utils .backend import (
1415 get_array_module ,
1516 get_module_name ,
@@ -121,7 +122,8 @@ def setup(
121122 Number of iterations (default to ``None`` in case a user wants to
122123 manually step over the solver)
123124 tol : :obj:`float`, optional
124- Tolerance on residual norm
125+ Absolute tolerance on residual norm. Stops the solver when the
126+ residual norm is below this value.
125127 preallocate : :obj:`bool`, optional
126128 .. versionadded:: 2.6.0
127129
@@ -260,6 +262,10 @@ def run(
260262 )
261263 x = self .step (x , showstep )
262264 self .callback (x )
265+ # check if any callback has raised a stop flag
266+ stop = _callback_stop (self .callbacks )
267+ if stop :
268+ break
263269 return x
264270
265271 def finalize (self , show : bool = False ) -> None :
@@ -299,7 +305,8 @@ def solve(
299305 niter : :obj:`int`, optional
300306 Number of iterations
301307 tol : :obj:`float`, optional
302- Tolerance on residual norm
308+ Absolute tolerance on residual norm. Stops the solver when the
309+ residual norm is below this value.
303310 preallocate : :obj:`bool`, optional
304311 .. versionadded:: 2.6.0
305312
@@ -440,7 +447,8 @@ def setup(
440447 damp : :obj:`float`, optional
441448 Damping coefficient
442449 tol : :obj:`float`, optional
443- Tolerance on residual norm
450+ Absolute tolerance on residual norm. Stops the solver when the
451+ residual norm is below this value.
444452 preallocate : :obj:`bool`, optional
445453 .. versionadded:: 2.6.0
446454
@@ -592,22 +600,26 @@ def run(
592600 Estimated model of size :math:`[M \times 1]`
593601
594602 """
595- niter = self .niter if niter is None else niter
596- if niter is None :
603+ self . niter = self .niter if niter is None else niter
604+ if self . niter is None :
597605 raise ValueError ("niter must not be None" )
598- while self .iiter < niter and self .kold > self .tol :
606+ while self .iiter < self . niter and self .kold > self .tol :
599607 showstep = (
600608 True
601609 if show
602610 and (
603611 self .iiter < itershow [0 ]
604- or niter - self .iiter < itershow [1 ]
612+ or self . niter - self .iiter < itershow [1 ]
605613 or self .iiter % itershow [2 ] == 0
606614 )
607615 else False
608616 )
609617 x = self .step (x , showstep )
610618 self .callback (x )
619+ # check if any callback has raised a stop flag
620+ stop = _callback_stop (self .callbacks )
621+ if stop :
622+ break
611623 return x
612624
613625 def finalize (self , show : bool = False ) -> None :
@@ -622,7 +634,12 @@ def finalize(self, show: bool = False) -> None:
622634 self .tend = time .time ()
623635 self .telapsed = self .tend - self .tstart
624636 # reason for termination
625- self .istop = 1 if self .kold < self .tol else 2
637+ if self .kold < self .tol :
638+ self .istop = 1
639+ elif self .iiter >= self .niter :
640+ self .istop = 2
641+ else :
642+ self .istop = 3
626643 self .r1norm = self .kold
627644 self .r2norm = self .cost1 [self .iiter ]
628645 if show :
@@ -655,7 +672,8 @@ def solve(
655672 damp : :obj:`float`, optional
656673 Damping coefficient
657674 tol : :obj:`float`, optional
658- Tolerance on residual norm
675+ Absolute tolerance on residual norm. Stops the solver when the
676+ residual norm is below this value.
659677 preallocate : :obj:`bool`, optional
660678 .. versionadded:: 2.6.0
661679
@@ -677,10 +695,14 @@ def solve(
677695 Gives the reason for termination
678696
679697 ``1`` means :math:`\mathbf{x}` is an approximate solution to
680- :math:`\mathbf{y} = \mathbf{Op}\,\mathbf{x}`
698+ :math:`\mathbf{y} = \mathbf{Op}\,\mathbf{x}` with the provided
699+ tolerance ``tol``
681700
682701 ``2`` means :math:`\mathbf{x}` approximately solves the least-squares
683- problem
702+ problem (reached the maximum number of iterations ``niter``)
703+
704+ ``3`` means another stopping criterion implemented via a callback
705+ was reached
684706 iit : :obj:`int`
685707 Iteration number upon termination
686708 r1norm : :obj:`float`
0 commit comments