Source code for pyproximal.proximal.Huber

import numpy as np

from pyproximal.ProxOperator import _check_tau
from pyproximal import ProxOperator
from pyproximal.proximal import L2, L1


[docs]class Huber(ProxOperator): r"""Huber norm proximal operator. Proximal operator of the Huber norm defined as :math:`H_\alpha(\mathbf{x}) = \sum_i H_\alpha(x_i)` where: .. math:: H_\alpha(x_i) = \begin{cases} \frac{|x_i|^2}{2 \alpha}, & |x_i| \leq \alpha \\ |x_i| - \frac{\alpha}{2}, & |x_i| > \alpha \end{cases} which behaves like a :math:`\ell_2^2` norm for :math:`|x_i| \leq \alpha` and a :math:`\ell_1` norm for :math:`|x_i| > \alpha`. Parameters ---------- alpha : :obj:`float` Huber parameter Notes ----- The Huber proximal operator is defined as: .. math:: \prox_{\tau H_\alpha(\cdot)}(\mathbf{x}) = \begin{cases} \prox_{\frac{\tau}{2 \alpha} |x_i|^2}(x_i), & |x_i| \leq \alpha \\ \prox_{\tau |x_i|}(x_i), & |x_i| > \alpha \end{cases} """ def __init__(self, alpha): super().__init__(None, False) self.alpha = alpha self.l2 = L2(sigma=1. / self.alpha) self.l1 = L1() def __call__(self, x): h = np.zeros_like(x) xabs = np.abs(x) mask = xabs > self.alpha h[~mask] = xabs[~mask] ** 2 / (2. * self.alpha) h[mask] = xabs[mask] - self.alpha / 2. return np.sum(h) @_check_tau def prox(self, x, tau): y = np.zeros_like(x) xabs = np.abs(x) mask = xabs > self.alpha y[~mask] = self.l2.prox(x[~mask], tau) y[mask] = self.l1.prox(x[mask], tau) # alternative from https://math.stackexchange.com/questions/1650411/ # proximal-operator-of-the-huber-loss-function... currently commented # as it does not provide the same result # y = (1. - tau / np.maximum(np.abs(x), tau + self.alpha)) * x return y
[docs]class HuberCircular(ProxOperator): r"""Circular Huber norm proximal operator. Proximal operator of the Circular Huber norm defined as: .. math:: H_\alpha(\mathbf{x}) = \begin{cases} \frac{\|\mathbf{x}\|_2^2}{2 \alpha}, & \|\mathbf{x}\|_2 \leq \alpha \\ \|\mathbf{x}\|_2 - \frac{\alpha}{2}, & \|\mathbf{x}\|_2 > \alpha \\ \end{cases} which behaves like a :math:`\ell_2^2` norm for :math:`\|\mathbf{x}\|_2 \leq \alpha` and a :math:`\ell_2` norm for :math:`\|\mathbf{x}\|_2 > \alpha`. Parameters ---------- alpha : :obj:`float` Huber parameter Notes ----- The Circular Huber proximal operator is defined as [1]_: .. math:: \prox_{\tau H_\alpha(\cdot)}(\mathbf{x}) = \left( 1 - \frac{\tau}{\max\{\|\mathbf{x}\|_2, \tau + \alpha \} } \right) \mathbf{x} .. [1] O’Donoghue, B. and Stathopoulos, G. and Boyd, S. "A Splitting Method for Optimal Control", In the IEEE Transactions on Control Systems Technology, 2013. """ def __init__(self, alpha): super().__init__(None, False) self.alpha = alpha def __call__(self, x): l2 = np.linalg.norm(x) if l2 <= self.alpha: h = l2 ** 2 / (2 * self.alpha) else: h = l2 - self.alpha / 2. return h @_check_tau def prox(self, x, tau): x = (1. - tau / max(np.linalg.norm(x), tau + self.alpha)) * x return x