Module regpy.stoprules
Classes
class MissingValueError (*args, **kwargs)
-
Expand source code
class MissingValueError(Exception): pass
Ancestors
- builtins.Exception
- builtins.BaseException
class StopRule
-
Abstract base class for stopping rules.
Attributes
x
,y
:arrays
orNone
- The chosen solution. Stopping rules may decide to yield a result
different from the last iterate. Therefore, after :meth:
stop
has triggered, it should store the solution in this attribute. Before triggering, these attributes contain the iterates passed to :meth:stop
. triggered
:bool
- Whether the stopping rule decided to stop.
Expand source code
class StopRule: """Abstract base class for stopping rules. Attributes ---------- x, y : arrays or `None` The chosen solution. Stopping rules may decide to yield a result different from the last iterate. Therefore, after :meth:`stop` has triggered, it should store the solution in this attribute. Before triggering, these attributes contain the iterates passed to :meth:`stop`. triggered: bool Whether the stopping rule decided to stop. """ log = classlogger def __init__(self): self.x = None self.y = None self.triggered = False def stop(self, x, y=None): """Check whether to stop iterations. Parameters ---------- x : array The current iterate. y : array, optional The operator value at the current iterate. Can be omitted if unavailable, but some implementations may need it. Returns ------- bool `True` if iterations should be stopped. """ if self.triggered: return True self.x = x self.y = y self.triggered = self._stop(x, y) return self.triggered def _stop(self, x, y=None): """Check whether to stop iterations. This is an abstract method. Child classes should override it. Parameters and return values are the same as for the public interface method :meth:`stop`. This method will not be called again after returning `True`. Child classes that need `y` should raise :class:`MissingValueError` if called with `y=None`. """ raise NotImplementedError def __add__(self, other): return CombineRules([self, other])
Subclasses
- DualityGapStopping
- CombineRules
- CountIterations
- Discrepancy
- Monotonicity
- NoneRule
- RelativeChangeData
- RelativeChangeSol
Instance variables
prop log
-
The
logging.Logger
instance. Every subclass has a separate instance, named by its fully qualified name. Subclasses should use it instead ofprint
for any kind of status information to allow users to control output formatting, verbosity and persistence.Expand source code
@property def classlogger(self): """The [`logging.Logger`][1] instance. Every subclass has a separate instance, named by its fully qualified name. Subclasses should use it instead of `print` for any kind of status information to allow users to control output formatting, verbosity and persistence. [1]: https://docs.python.org/3/library/logging.html#logging.Logger """ return getattr(self, '_log', None) or getLogger(type(self).__qualname__)
Methods
def stop(self, x, y=None)
-
Check whether to stop iterations.
Parameters
x
:array
- The current iterate.
y
:array
, optional- The operator value at the current iterate. Can be omitted if unavailable, but some implementations may need it.
Returns
bool
True
if iterations should be stopped.
class NoneRule
-
Default stop rule that will never stop an iteration. The rule should not be used in normal setting it provides a default for the solvers that would stop by triggering their converged statement.
Expand source code
class NoneRule(StopRule): """Default stop rule that will never stop an iteration. The rule should not be used in normal setting it provides a default for the solvers that would stop by triggering their converged statement. """ def __init__(self): super().__init__() def _stop(self, x, y=None): return False
Ancestors
Inherited members
class CombineRules (rules, op=None)
-
Combine several stopping rules into one.
The resulting rule triggers when any of the given rules triggers and delegates selecting the solution to the active rule.
Parameters
rules
:list
of:class:
StopRule``- The rules to be combined.
op
::class:
~regpy.operators.Operator``, optional- If any rule needs the operator value and none is given to :meth:
stop
, the operator is used to compute it.
Attributes
rules
:list
of:class:
StopRule``- The combined rules.
op
::class:
~regpy.operators.Operatoror
None``- The forward operator.
active_rule
::class:
StopRuleor
None``- The rule that triggered.
Expand source code
class CombineRules(StopRule): """Combine several stopping rules into one. The resulting rule triggers when any of the given rules triggers and delegates selecting the solution to the active rule. Parameters ---------- rules : list of :class:`StopRule` The rules to be combined. op : :class:`~regpy.operators.Operator`, optional If any rule needs the operator value and none is given to :meth:`stop`, the operator is used to compute it. Attributes ---------- rules : list of :class:`StopRule` The combined rules. op : :class:`~regpy.operators.Operator` or `None` The forward operator. active_rule : :class:`StopRule` or `None` The rule that triggered. """ def __init__(self, rules, op=None): super().__init__() self.rules = [] for rule in rules: if type(rule) is type(self) and rule.op is self.op: self.rules.extend(rule.rules) else: self.rules.append(rule) self.op = op self.active_rule = None def __repr__(self): return 'CombineRules({})'.format(self.rules) def _stop(self, x, y=None): for rule in self.rules: try: triggered = rule.stop(x, y) except MissingValueError: if self.op is None or y is not None: raise y = self.op(x) triggered = rule.stop(x, y) if triggered: self.log.info('Rule {} triggered.'.format(rule)) self.active_rule = rule self.x = rule.x self.y = rule.y return True return False
Ancestors
Inherited members
class CountIterations (max_iterations, while_type=True, logging_level=20)
-
Stopping rule based on number of iterations.
Each call to :attr:
stop
increments the iteration count by 1.Parameters
max_iterations
:int
- The number of iterations after which to stop.
Expand source code
class CountIterations(StopRule): """Stopping rule based on number of iterations. Each call to :attr:`stop` increments the iteration count by 1. Parameters ---------- max_iterations : int The number of iterations after which to stop. """ def __init__(self, max_iterations, while_type = True,logging_level= logging.INFO): super().__init__() self.max_iterations = max_iterations self.iteration = 0 self.while_type = while_type self.log.setLevel(logging_level) def __repr__(self): return 'CountIterations(max_iterations={})'.format(self.max_iterations) def _stop(self, x, y=None): if self.while_type: self.iteration += 1 if self.iteration <= self.max_iterations: self.log.info( 'iteration = {} / {}' .format(self.iteration, self.max_iterations)) else: self.log.info( 'iteration = {} / {}' .format(self.iteration, self.max_iterations)) self.iteration += 1 return self.iteration > self.max_iterations
Ancestors
Inherited members
class Discrepancy (norm, data, noiselevel, tau=2)
-
Morozov's discrepancy principle.
Stops at the first iterate at which the residual is smaller than a pre-determined multiple of the noise level::
||y - data|| < tau * noiselevel
Parameters
norm
:callable
- The norm with respect to which the discrepancy should be measured.
Usually this will be the
norm
method of some :class:~regpy.spaces.Space
. data
:array
- The right hand side (noisy data).
noiselevel
:float
- An estimate of the distance from the noisy data to the exact data.
tau
:float
, optional- The multiplier; must be larger than 1. Defaults to 2.
Expand source code
class Discrepancy(StopRule): """Morozov's discrepancy principle. Stops at the first iterate at which the residual is smaller than a pre-determined multiple of the noise level:: ||y - data|| < tau * noiselevel Parameters ---------- norm : callable The norm with respect to which the discrepancy should be measured. Usually this will be the `norm` method of some :class:`~regpy.spaces.Space`. data : array The right hand side (noisy data). noiselevel : float An estimate of the distance from the noisy data to the exact data. tau : float, optional The multiplier; must be larger than 1. Defaults to 2. """ def __init__(self, norm, data, noiselevel, tau=2): super().__init__() self.norm = norm self.data = data self.noiselevel = noiselevel self.tau = tau def __repr__(self): return 'Discrepancy(noiselevel={}, tau={})'.format( self.noiselevel, self.tau) def _stop(self, x, y=None): if y is None: raise MissingValueError residual = self.data - y discrepancy = self.norm(residual) rel = discrepancy / self.noiselevel self.log.info('relative discrepancy = {:3.2f}, tolerance = {:1.2f}'.format(rel, self.tau)) return rel < self.tau
Ancestors
Inherited members
class RelativeChangeData (norm, data, cutoff)
-
Stops if the relative change in the residual becomes small
Stops at the first iterate at which the difference between the old residual and the new residual is smaller than a pre-determined cutoff::
||y_k-y_{k+1}|| < delta
Parameters
norm
:callable
- The norm with respect to which the difference should be measured.
Usually this will be the
norm
method of some :class:~regpy.spaces.Space
. cutoff
:float
- The cutoff value at which the iteration should be stopped
data
:np array
- The data array
Expand source code
class RelativeChangeData(StopRule): """Stops if the relative change in the residual becomes small Stops at the first iterate at which the difference between the old residual and the new residual is smaller than a pre-determined cutoff:: ||y_k-y_{k+1}|| < delta Parameters ---------- norm : callable The norm with respect to which the difference should be measured. Usually this will be the `norm` method of some :class:`~regpy.spaces.Space`. cutoff : float The cutoff value at which the iteration should be stopped data : np array The data array """ def __init__(self, norm, data, cutoff): super().__init__() self.norm = norm self.cutoff = cutoff self.data_old = data def __repr__(self): return 'RelativeChangeData(cutoff={})'.format( self.cutoff) def _stop(self, x, y=None): if y is None: raise MissingValueError change = self.norm(y - self.data_old) self.data_old = np.copy(y) self.log.info('RelativeChangeData = {}, cutoff = {}'.format( change, self.cutoff)) return change < self.cutoff
Ancestors
Inherited members
class RelativeChangeSol (norm, init, cutoff)
-
Stops if the relative change in the solution space becomes small
Stops at the first iterate at which the difference between the old estimate and the new estimate is smaller than a pre-determined cutoff::
||y_k-y_{k+1}|| < delta
Parameters
norm
:callable
- The norm with respect to which the difference should be measured.
Usually this will be the
norm
method of some :class:~regpy.spaces.Space
. cutoff
:float
- The cutoff value at which the iteration should be stopped
init
:np array
- initial guess
Expand source code
class RelativeChangeSol(StopRule): """Stops if the relative change in the solution space becomes small Stops at the first iterate at which the difference between the old estimate and the new estimate is smaller than a pre-determined cutoff:: ||y_k-y_{k+1}|| < delta Parameters ---------- norm : callable The norm with respect to which the difference should be measured. Usually this will be the `norm` method of some :class:`~regpy.spaces.Space`. cutoff : float The cutoff value at which the iteration should be stopped init : np array initial guess """ def __init__(self, norm, init, cutoff): super().__init__() self.norm = norm self.cutoff = cutoff self.sol_old = init def __repr__(self): return 'RelativeChangeSol(cutoff={})'.format( self.cutoff) def _stop(self, x, y=None): change = self.norm(x - self.sol_old) self.sol_old = np.copy(x) self.log.info('RelativeChangeSol = {}, cutoff = {}'.format( change, self.cutoff)) return change < self.cutoff
Ancestors
Inherited members
class Monotonicity (norm, data, init_data)
-
Stops if the residual is growing again.
Parameters
norm
:callable
- The norm with respect to which the difference should be measured.
Usually this will be the
norm
method of some :class:~regpy.spaces.Space
. data
:np array
- The data array
init_data
:np array
- initial guess in data space
Expand source code
class Monotonicity(StopRule): """Stops if the residual is growing again. Parameters ---------- norm : callable The norm with respect to which the difference should be measured. Usually this will be the `norm` method of some :class:`~regpy.spaces.Space`. data : np array The data array init_data : np array initial guess in data space """ def __init__(self, norm, data, init_data): super().__init__() self.norm = norm self.data = data self.residual = self.norm(self.data - init_data) def __repr__(self): return 'Monotonicty' def _stop(self, x, y=None): if y is None: raise MissingValueError residual = self.norm(self.data - y) change = self.residual - residual self.residual = residual self.log.info('Monotonicity = {}, residual = {}'.format( change, residual)) #self.log.info('Monotonicity = {}'.format( # change)) return change < 0
Ancestors
Inherited members