Coverage for local_installation_linux/mumott/optimization/regularizers/l2_norm.py: 86%
32 statements
« prev ^ index » next coverage.py v7.3.2, created at 2025-05-05 21:21 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2025-05-05 21:21 +0000
1import numpy as np
2from numpy.typing import NDArray
4from mumott.optimization.regularizers.base_regularizer import Regularizer
5import logging
6logger = logging.getLogger(__name__)
9class L2Norm(Regularizer):
11 r"""Regularizes using the :math:`L_2` norm of the coefficient vector, also known as the Euclidean norm.
12 Suitable for most representations, including non-local ones. Tends to reduce large values,
13 and often leads to fast convergence.
15 The :math:`L_2` norm of a vector :math:`x` is given by :math:`\sum{\vert x \vert^2}`.
17 See also `the Wikipedia article on the Euclidean norm
18 <https://en.wikipedia.org/wiki/Euclidean_space#Euclidean_norm>`_
19 """
21 def __init__(self):
22 super().__init__()
24 def get_regularization_norm(self,
25 coefficients: NDArray[float],
26 get_gradient: bool = False,
27 gradient_part: str = None) -> dict[str, NDArray[float]]:
28 """Retrieves the :math:`L_2` norm, of the coefficient vector. Appropriate for
29 use with scalar coefficients or local basis sets.
31 Parameters
32 ----------
33 coefficients
34 An ``np.ndarray`` of values, with shape ``(X, Y, Z, W)``, where
35 the last channel contains, e.g., tensor components.
36 get_gradient
37 If ``True``, returns a ``'gradient'`` of the same shape as :attr:`coefficients`.
38 Otherwise, the entry ``'gradient'`` will be ``None``. Defaults to ``False``.
39 gradient_part
40 Used for the zonal harmonics (ZH) reconstructions to determine what part of the gradient is
41 being calculated. Default is ``None``.
42 If a flag is passed in (``'full'``, ``'angles'``, ``'coefficients'``),
43 we assume that the ZH workflow is used and that the last two coefficients are Euler angles,
44 which should not be regularized by this regularizer.
46 Returns
47 -------
48 A dictionary with two entries, ``regularization_norm`` and ``gradient``.
49 """
51 result = dict(regularization_norm=None, gradient=None)
52 if get_gradient:
54 if gradient_part is None:
55 result['gradient'] = coefficients
56 elif gradient_part in ('full', 'coefficients'):
57 result['gradient'] = np.copy(coefficients)
58 result['gradient'][..., -2:] = 0
59 elif gradient_part in ('angles'): 59 ↛ 62line 59 didn't jump to line 62, because the condition on line 59 was never false
60 result['gradient'] = np.zeros(coefficients.shape)
61 else:
62 logger.warning('Unexpected argument given for gradient part.')
63 raise ValueError
65 if gradient_part is None:
66 result['regularization_norm'] = np.sum(coefficients ** 2)
67 elif gradient_part in ('full', 'coefficients', 'angles'): 67 ↛ 70line 67 didn't jump to line 70, because the condition on line 67 was never false
68 result['regularization_norm'] = np.sum(coefficients[..., :-2] ** 2)
69 else:
70 raise ValueError('Unexpected argument given for gradient part.')
72 return result
74 @property
75 def _function_as_str(self) -> str:
76 return 'R(x) = lambda * abs(x) ** 2'
78 @property
79 def _function_as_tex(self) -> str:
80 return r'$R(\vec{x}) = \lambda \Vert \vec{x} \Vert_2^2$'