11import  numpy  as  np 
22
33from  pyproximal .ProxOperator  import  _check_tau 
4- from  pyproximal .projection  import  BoxProj 
54from  pyproximal  import  ProxOperator 
5+ from  pyproximal .proximal  import  L2 , L1 
66
77
88class  Huber (ProxOperator ):
99    r"""Huber norm proximal operator. 
1010
11-     Proximal operator of the Huber norm defined as: 
11+     Proximal operator of the Huber norm defined as  
12+     :math:`H_\alpha(\mathbf{x}) = \sum_i H_\alpha(x_i)` where: 
13+ 
14+     .. math:: 
15+ 
16+         H_\alpha(x_i) =  
17+         \begin{cases} 
18+         \frac{|x_i|^2}{2 \alpha}, & |x_i| \leq \alpha \\ 
19+         |x_i| - \frac{\alpha}{2}, & |x_i| > \alpha 
20+         \end{cases} 
21+ 
22+     which behaves like a :math:`\ell_2` norm for :math:`|x_i| \leq \alpha` and a 
23+     :math:`\ell_1` norm for :math:`|x_i| > \alpha`. 
24+ 
25+     Parameters 
26+     ---------- 
27+     alpha : :obj:`float` 
28+         Huber parameter 
29+ 
30+     Notes 
31+     ----- 
32+     The Huber proximal operator is defined as: 
33+ 
34+     .. math:: 
35+ 
36+         \prox_{\tau H_\alpha(\cdot)}(\mathbf{x}) = 
37+         \begin{cases} 
38+         \prox_{\frac{\tau}{2 \alpha} |x_i|^2}(x_i), & |x_i| \leq \alpha \\ 
39+         \prox_{\tau |x_i|}(x_i), & |x_i| > \alpha 
40+         \end{cases} 
41+          
42+     """ 
43+     def  __init__ (self , alpha ):
44+         super ().__init__ (None , False )
45+         self .alpha  =  alpha 
46+         self .l2  =  L2 (sigma = 1.  /  self .alpha )
47+         self .l1  =  L1 ()
48+ 
49+     def  __call__ (self , x ):
50+         h  =  np .zeros_like (x )
51+         xabs  =  np .abs (x )
52+         mask  =  xabs  >  self .alpha 
53+         h [~ mask ] =  xabs [~ mask ] **  2  /  (2.  *  self .alpha )
54+         h [mask ] =  xabs [mask ] -  self .alpha  /  2. 
55+         return  np .sum (h )
56+ 
57+     @_check_tau  
58+     def  prox (self , x , tau ):
59+         y  =  np .zeros_like (x )
60+         xabs  =  np .abs (x )
61+         mask  =  xabs  >  self .alpha 
62+         y [~ mask ] =  self .l2 .prox (x [~ mask ], tau )
63+         y [mask ] =  self .l1 .prox (x [mask ], tau )
64+         # alternative from https://math.stackexchange.com/questions/1650411/ 
65+         # proximal-operator-of-the-huber-loss-function... currently commented 
66+         # as it does not provide the same result 
67+         # y = (1. - tau / np.maximum(np.abs(x), tau + self.alpha)) * x 
68+ 
69+         return  y 
70+     
71+ 
72+ class  HuberCircular (ProxOperator ):
73+     r"""Circular Huber norm proximal operator. 
74+ 
75+     Proximal operator of the Circular Huber norm defined as: 
1276
1377    .. math:: 
1478
@@ -18,8 +82,8 @@ class Huber(ProxOperator):
1882        \|\mathbf{x}\|_2 - \frac{\alpha}{2}, & \|\mathbf{x}\|_2 > \alpha \\ 
1983        \end{cases} 
2084
21-     which behaves like a :math:`\ell_2` norm for :math:`|x_i|  \leq \alpha` and a 
22-     :math:`\ell_1` norm for :math:`|x_i| <  \alpha`. 
85+     which behaves like a :math:`\ell_2` norm for :math:`\|\mathbf{x}\|_2  \leq \alpha` and a 
86+     :math:`\ell_1` norm for :math:`\|\mathbf{x}\|_2 >  \alpha`. 
2387
2488    Parameters 
2589    ---------- 
@@ -28,13 +92,16 @@ class Huber(ProxOperator):
2892
2993    Notes 
3094    ----- 
31-     The Huber proximal operator is defined as: 
95+     The Circular  Huber proximal operator is defined as [1]_ : 
3296
3397    .. math:: 
3498
3599        \prox_{\tau H_\alpha(\cdot)}(\mathbf{x}) = 
36100        \left( 1 - \frac{\tau}{\max\{\|\mathbf{x}\|_2, \tau + \alpha \} } \right) \mathbf{x} 
37101
102+     .. [1] O’Donoghue, B. and Stathopoulos, G. and Boyd, S. "A Splitting Method for Optimal Control",  
103+         In the IEEE Transactions on Control Systems Technology, 2013. 
104+          
38105    """ 
39106    def  __init__ (self , alpha ):
40107        super ().__init__ (None , False )
@@ -51,4 +118,4 @@ def __call__(self, x):
51118    @_check_tau  
52119    def  prox (self , x , tau ):
53120        x  =  (1.  -  tau  /  max (np .linalg .norm (x ), tau  +  self .alpha )) *  x 
54-         return  x 
121+         return  x 
0 commit comments