Source code for mumott.optimization.regularizers.l1_norm

import numpy as np
from numpy.typing import NDArray

from mumott.optimization.regularizers.base_regularizer import Regularizer
import logging
logger = logging.getLogger(__name__)


[docs]class L1Norm(Regularizer): r"""Regularizes using the :math:`L_1` norm of the coefficient vector, also known as the Manhattan or taxicab norm. Suitable for scalar fields or tensor fields in local representations. Tends to reduce noise. The :math:`L_1` norm of a vector :math:`x` is given by :math:`\sum{\vert x \vert}`. See also `this Wikipedia article <https://en.wikipedia.org/wiki/Taxicab_geometry>`_. """ def __init__(self): super().__init__()
[docs] def get_regularization_norm(self, coefficients: NDArray[float], get_gradient: bool = False, gradient_part: str = None) -> dict[str, NDArray[float]]: """Retrieves the :math:`L_1` norm, also called the Manhattan or taxicab norm, of the coefficients. Appropriate for use with scalar fields or tensor fields in local basis sets. Parameters ---------- coefficients An ``np.ndarray`` of values, with shape ``(X, Y, Z, W)``, where the last channel contains, e.g., tensor components. get_gradient If ``True``, returns a ``'gradient'`` of the same shape as :attr:`coefficients`. Otherwise the entry ``'gradient'`` will be ``None``. Defaults to ``False``. gradient_part Used for the zonal harmonics resonstructions to determine what part of the gradient is being calculated. Default is None. If a flag is passed in ('full', 'angles', 'coefficients'), we assume that the ZH workflow is used and that the last two coefficients are euler angles, which should not be regularized by this regularizer. Returns ------- A dictionary with two entries, ``regularization_norm`` and ``gradient``. """ result = dict(regularization_norm=None, gradient=None) if get_gradient: if gradient_part is None: result['gradient'] = np.sign(coefficients) elif gradient_part in ('full', 'coefficients'): result['gradient'] = np.sign(coefficients) result['gradient'][..., -2:] = 0 elif gradient_part in ('angles'): result['gradient'] = np.zeros(coefficients.shape) else: logger.warning('Unexpected argument given for gradient part.') raise ValueError if gradient_part is None: result['regularization_norm'] = np.sum(np.abs(coefficients)) elif gradient_part in ('full', 'coefficients', 'angles'): result['regularization_norm'] = np.sum(np.abs(coefficients[..., :-2])) else: logger.warning('Unexpected argument given for gradient part.') raise ValueError return result
@property def _function_as_str(self) -> str: return 'R(x) = lambda * abs(x)' @property def _function_as_tex(self) -> str: return r'$R(\vec{x}) = \lambda \Vert \vec{x} \Vert_1$'